feat: custom damage system - cancel vanilla damage, state-based hits, killer/survivor HP always 20

This commit is contained in:
loki5512344 2026-06-03 21:21:36 +02:00
parent d59b965407
commit 371384ca8a

View file

@ -3,6 +3,8 @@ package dev.loki.phase;
import dev.loki.chest.ChestManager;
import dev.loki.chest.ChestOpening;
import dev.loki.core.GameSession;
import dev.loki.damage.AttackListener;
import dev.loki.damage.DamageHandler;
import dev.loki.gate.ExitGate;
import dev.loki.gate.GateManager;
import dev.loki.hook.Hook;
@ -10,6 +12,7 @@ import dev.loki.hook.HookManager;
import dev.loki.hook.HookRescue;
import dev.loki.hook.HookSacrifice;
import dev.loki.hook.HookStage;
import dev.loki.killer.KillerController;
import dev.loki.listener.PlayerInteractListener;
import dev.loki.listener.PlayerMoveListener;
import dev.loki.mdbd;
@ -21,14 +24,21 @@ import dev.loki.pallet.PalletManager;
import dev.loki.pallet.PalletStun;
import dev.loki.player.BasePlayer;
import dev.loki.player.Killer;
import dev.loki.player.PlayerManager;
import dev.loki.player.PlayerState;
import dev.loki.player.Survivor;
import dev.loki.state.StateMachine;
import dev.loki.ui.ActionBar;
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 org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
public class GameplayPhase implements Phase {
@ -49,6 +59,14 @@ public class GameplayPhase implements Phase {
private ChestManager chestManager;
private ChestOpening chestOpening;
// Damage system
private PlayerManager playerManager;
private StateMachine stateMachine;
private DamageHandler damageHandler;
private KillerController killerController;
private AttackListener attackListener;
private Listener vanillaDamageBlocker;
// Listener references grabbed from plugin
private PlayerMoveListener moveListener;
private PlayerInteractListener interactListener;
@ -87,6 +105,56 @@ public class GameplayPhase implements Phase {
session.setHookManager(hookManager);
session.setGateManager(gateManager);
// --- Damage system ---
// Build PlayerManager from current session players
playerManager = new PlayerManager();
for (BasePlayer bp : session.getPlayers().values()) {
playerManager.register(bp);
}
stateMachine = new StateMachine();
damageHandler = new DamageHandler(stateMachine);
// When survivor is injured — show title + sound
damageHandler.setOnSurvivorInjured(survivor -> {
Player p = survivor.getPlayer();
if (p != null && p.isOnline()) {
p.showTitle(net.kyori.adventure.title.Title.title(
Component.text("РАНЕН!", net.kyori.adventure.text.format.TextColor.color(0xFF8C00)),
Component.text("Найдите аптечку или союзника", NamedTextColor.YELLOW)
));
p.playSound(p.getLocation(), Sound.ENTITY_PLAYER_HURT, 1.0f, 0.8f);
// Keep HP at 20 always — damage is state-based not HP-based
p.setHealth(20.0);
}
});
// When survivor is downed — show title + sound
damageHandler.setOnSurvivorDowned(survivor -> {
Player p = survivor.getPlayer();
if (p != null && p.isOnline()) {
p.showTitle(net.kyori.adventure.title.Title.title(
Component.text("НОКДАУН!", net.kyori.adventure.text.format.TextColor.color(0xFF2222)),
Component.text("Ждите помощи...", NamedTextColor.RED)
));
p.playSound(p.getLocation(), Sound.ENTITY_PLAYER_HURT, 1.0f, 0.5f);
p.setHealth(20.0);
}
});
killerController = new KillerController(plugin, playerManager, damageHandler, session.getConfig());
// AttackListener — intercepts EntityDamageByEntityEvent, cancels vanilla damage, applies custom
attackListener = new AttackListener(playerManager, damageHandler,
(killer, survivor) -> killerController.tryAttack(killer, survivor));
attackListener.register(plugin);
// Block ALL vanilla damage for players in this session (fall, fire, mobs, etc.)
vanillaDamageBlocker = new VanillaDamageBlocker(session);
Bukkit.getPluginManager().registerEvents(vanillaDamageBlocker, plugin);
killerController.initialize();
// --- Wire listeners ---
moveListener = plugin.getMoveListener();
interactListener = plugin.getInteractListener();
@ -136,6 +204,28 @@ public class GameplayPhase implements Phase {
chestOpening.cancelAll();
}
// Unregister damage listeners
if (attackListener != null) {
attackListener.unregister();
}
if (vanillaDamageBlocker != null) {
HandlerList.unregisterAll(vanillaDamageBlocker);
vanillaDamageBlocker = null;
}
if (killerController != null) {
killerController.shutdown();
}
if (playerManager != null) {
playerManager.clear();
}
// Restore HP for all players
for (BasePlayer bp : session.getPlayers().values()) {
Player p = bp.getPlayer();
if (p != null && p.isOnline()) {
p.setHealth(20.0);
}
}
Bukkit.broadcast(Component.text("[DBD] Игровая фаза завершена!", NamedTextColor.GOLD));
}
@ -381,4 +471,24 @@ public class GameplayPhase implements Phase {
}
});
}
// -------------------------------------------------------------------------
// Inner class: blocks all vanilla damage for players in the session
// -------------------------------------------------------------------------
private static class VanillaDamageBlocker implements Listener {
private final GameSession session;
VanillaDamageBlocker(GameSession session) {
this.session = session;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onDamage(EntityDamageEvent event) {
if (!(event.getEntity() instanceof Player p)) return;
if (!session.getPlayers().containsKey(p.getUniqueId())) return;
event.setCancelled(true);
p.setHealth(20.0);
}
}
}