package com.tiedup.remake.dialogue; import com.tiedup.remake.entities.EntityKidnapper; import com.tiedup.remake.entities.ai.kidnapper.KidnapperState; import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.Nullable; /** * Proactive dialogue trigger system for Kidnappers. * * This system enables kidnappers to speak unprompted based on their current state. * Should be called periodically from the kidnapper's tick method. * * Universal NPC Dialogue Support */ public class KidnapperDialogueTriggerSystem { /** Minimum ticks between proactive dialogues (60 seconds) */ private static final int PROACTIVE_COOLDOWN = 1200; /** Chance to trigger proactive dialogue (1/400 per check = ~0.25% per check) */ private static final int TRIGGER_CHANCE = 400; /** Check interval (every 20 ticks = 1 second) */ private static final int CHECK_INTERVAL = 20; /** * Tick the dialogue trigger system for a kidnapper. * Should be called every tick from the kidnapper. * * @param kidnapper The kidnapper to check * @param tickCount Current tick counter */ public static void tick(EntityKidnapper kidnapper, int tickCount) { // Only check periodically if (tickCount % CHECK_INTERVAL != 0) { return; } // Check cooldown if (kidnapper.getDialogueCooldown() > 0) { return; } // Random chance check if (kidnapper.getRandom().nextInt(TRIGGER_CHANCE) != 0) { return; } // Get dialogue ID based on current state String dialogueId = selectProactiveDialogue(kidnapper); if (dialogueId == null) { return; } // Find nearest player to speak to Player nearestPlayer = findNearestPlayer(kidnapper, 10.0); if (nearestPlayer == null) { return; } // Speak DialogueBridge.talkTo(kidnapper, nearestPlayer, dialogueId); } /** * Select a proactive dialogue ID based on the kidnapper's current state. * * @param kidnapper The kidnapper * @return Dialogue ID or null if no dialogue for this state */ @Nullable private static String selectProactiveDialogue(EntityKidnapper kidnapper) { KidnapperState state = kidnapper.getCurrentState(); if (state == null) { return null; } return switch (state) { case GUARD -> "guard.idle"; case PATROL -> "patrol.idle"; case ALERT -> "patrol.alert"; case SELLING -> "idle.sale_waiting"; case IDLE -> null; // No proactive dialogue when idle default -> null; }; } /** * Find the nearest player within a radius. * * @param kidnapper The kidnapper * @param radius Search radius * @return Nearest player or null */ @Nullable private static Player findNearestPlayer( EntityKidnapper kidnapper, double radius ) { var nearbyPlayers = kidnapper .level() .getEntitiesOfClass( Player.class, kidnapper.getBoundingBox().inflate(radius) ); Player nearest = null; double nearestDistSq = Double.MAX_VALUE; for (Player player : nearbyPlayers) { double distSq = kidnapper.distanceToSqr(player); if (distSq < nearestDistSq) { nearestDistSq = distSq; nearest = player; } } return nearest; } }