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.ChestManager;
import dev.loki.chest.ChestOpening; import dev.loki.chest.ChestOpening;
import dev.loki.core.GameSession; import dev.loki.core.GameSession;
import dev.loki.damage.AttackListener;
import dev.loki.damage.DamageHandler;
import dev.loki.gate.ExitGate; import dev.loki.gate.ExitGate;
import dev.loki.gate.GateManager; import dev.loki.gate.GateManager;
import dev.loki.hook.Hook; import dev.loki.hook.Hook;
@ -10,6 +12,7 @@ import dev.loki.hook.HookManager;
import dev.loki.hook.HookRescue; import dev.loki.hook.HookRescue;
import dev.loki.hook.HookSacrifice; import dev.loki.hook.HookSacrifice;
import dev.loki.hook.HookStage; import dev.loki.hook.HookStage;
import dev.loki.killer.KillerController;
import dev.loki.listener.PlayerInteractListener; import dev.loki.listener.PlayerInteractListener;
import dev.loki.listener.PlayerMoveListener; import dev.loki.listener.PlayerMoveListener;
import dev.loki.mdbd; import dev.loki.mdbd;
@ -21,14 +24,21 @@ import dev.loki.pallet.PalletManager;
import dev.loki.pallet.PalletStun; import dev.loki.pallet.PalletStun;
import dev.loki.player.BasePlayer; import dev.loki.player.BasePlayer;
import dev.loki.player.Killer; import dev.loki.player.Killer;
import dev.loki.player.PlayerManager;
import dev.loki.player.PlayerState; import dev.loki.player.PlayerState;
import dev.loki.player.Survivor; import dev.loki.player.Survivor;
import dev.loki.state.StateMachine;
import dev.loki.ui.ActionBar; import dev.loki.ui.ActionBar;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.entity.Player; 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 { public class GameplayPhase implements Phase {
@ -49,6 +59,14 @@ public class GameplayPhase implements Phase {
private ChestManager chestManager; private ChestManager chestManager;
private ChestOpening chestOpening; 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 // Listener references grabbed from plugin
private PlayerMoveListener moveListener; private PlayerMoveListener moveListener;
private PlayerInteractListener interactListener; private PlayerInteractListener interactListener;
@ -87,6 +105,56 @@ public class GameplayPhase implements Phase {
session.setHookManager(hookManager); session.setHookManager(hookManager);
session.setGateManager(gateManager); 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 --- // --- Wire listeners ---
moveListener = plugin.getMoveListener(); moveListener = plugin.getMoveListener();
interactListener = plugin.getInteractListener(); interactListener = plugin.getInteractListener();
@ -136,6 +204,28 @@ public class GameplayPhase implements Phase {
chestOpening.cancelAll(); 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)); 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);
}
}
} }