package dev.loki.ui; import dev.loki.mdbd; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.title.Title; import org.bukkit.entity.Player; import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; public class TitleUI { private final mdbd plugin; private final Map activeSkillChecks; public TitleUI(mdbd plugin) { this.plugin = plugin; this.activeSkillChecks = new HashMap<>(); } public void showGameStart(Player player, boolean isKiller) { Title.Times times = Title.Times.times( Duration.ofMillis(500), Duration.ofSeconds(3), Duration.ofMillis(500) ); Component title; Component subtitle; if (isKiller) { title = Component.text("KILLER") .color(NamedTextColor.DARK_RED) .decoration(TextDecoration.BOLD, true); subtitle = Component.text("Sacrifice them all") .color(NamedTextColor.RED); } else { title = Component.text("SURVIVOR") .color(NamedTextColor.DARK_GREEN) .decoration(TextDecoration.BOLD, true); subtitle = Component.text("Repair generators and escape") .color(NamedTextColor.GREEN); } player.showTitle(Title.title(title, subtitle, times)); } public void showVictory(Player player, boolean escaped) { Title.Times times = Title.Times.times( Duration.ofMillis(500), Duration.ofSeconds(5), Duration.ofSeconds(1) ); Component title = escaped ? Component.text("ESCAPED!") .color(NamedTextColor.GREEN) .decoration(TextDecoration.BOLD, true) : Component.text("VICTORY!") .color(NamedTextColor.DARK_RED) .decoration(TextDecoration.BOLD, true); Component subtitle = escaped ? Component.text("You survived the night") .color(NamedTextColor.DARK_GREEN) : Component.text("All survivors sacrificed") .color(NamedTextColor.RED); player.showTitle(Title.title(title, subtitle, times)); } public void showDefeat(Player player) { Title.Times times = Title.Times.times( Duration.ofMillis(500), Duration.ofSeconds(5), Duration.ofSeconds(1) ); Component title = Component.text("DEFEAT") .color(NamedTextColor.DARK_RED) .decoration(TextDecoration.BOLD, true); Component subtitle = Component.text("The Entity claims all") .color(NamedTextColor.RED); player.showTitle(Title.title(title, subtitle, times)); } public void showSkillCheck(Player player, int windowTicks, Consumer callback) { UUID uuid = player.getUniqueId(); if (activeSkillChecks.containsKey(uuid)) { callback.accept(false); return; } int startTick = plugin.getServer().getCurrentTick(); int successStart = startTick + (windowTicks / 2); int successEnd = successStart + (windowTicks / 2); SkillCheckState state = new SkillCheckState(startTick, successStart, successEnd, callback); activeSkillChecks.put(uuid, state); plugin.getServer().getScheduler().runTaskTimer(plugin, task -> { int currentTick = plugin.getServer().getCurrentTick(); SkillCheckState checkState = activeSkillChecks.get(uuid); if (checkState == null || player.isSneaking()) { task.cancel(); boolean success = checkState != null && currentTick >= checkState.successStart && currentTick <= checkState.successEnd; activeSkillChecks.remove(uuid); callback.accept(success); return; } if (currentTick > checkState.successEnd + 5) { task.cancel(); activeSkillChecks.remove(uuid); callback.accept(false); return; } renderSkillCheck(player, checkState, currentTick); }, 1L, 1L); } private void renderSkillCheck(Player player, SkillCheckState state, int currentTick) { double progress = (currentTick - state.startTick) / 40.0; int position = (int) (progress * 20) % 21; StringBuilder visual = new StringBuilder(); int successStartPos = (int) ((state.successStart - state.startTick) / 40.0 * 20); int successEndPos = (int) ((state.successEnd - state.startTick) / 40.0 * 20); for (int i = 0; i <= 20; i++) { if (i == position) { visual.append("◆"); } else if (i >= successStartPos && i <= successEndPos) { visual.append("░"); } else { visual.append("─"); } } Component title = Component.text(visual.toString()) .color(NamedTextColor.WHITE); String subStr = plugin.getConfigManager().getMessages() .getString("hook.struggle.subtitle", "&eПрисядь когда будешь в зоне!"); Component subtitle = dev.loki.util.TextUtil.color(subStr); Title.Times times = Title.Times.times(Duration.ZERO, Duration.ofMillis(100), Duration.ZERO); player.showTitle(Title.title(title, subtitle, times)); } public void clearSkillChecks() { for (SkillCheckState state : activeSkillChecks.values()) { state.callback().accept(false); } activeSkillChecks.clear(); } private record SkillCheckState(int startTick, int successStart, int successEnd, Consumer callback) {} }