Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
122 lines
3.5 KiB
Java
122 lines
3.5 KiB
Java
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;
|
|
}
|
|
}
|