mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2024-11-25 12:15:53 +01:00
Updates to SpeechController.
(Not working for some reason, will debug tomorrow.)
This commit is contained in:
parent
1baa5c0f01
commit
2be6437a63
2
pom.xml
2
pom.xml
@ -11,7 +11,7 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<craftbukkit.version>LATEST</craftbukkit.version>
|
||||
<craftbukkit.version>1.4.5-R1.0</craftbukkit.version>
|
||||
<citizensapi.version>2.0.6-SNAPSHOT</citizensapi.version>
|
||||
<vault.version>1.2.19-SNAPSHOT</vault.version>
|
||||
<powermock.version>1.4.12</powermock.version>
|
||||
|
@ -46,7 +46,6 @@ public class Settings {
|
||||
CHAT_FORMAT("npc.chat.format.no-targets", "[<npc>]: <text>"),
|
||||
CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[<npc>] -> You: <text>"),
|
||||
CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[<npc>] -> [<target>]: <text>"),
|
||||
CHAT_FORMAT_WITH_TARGETS_TO_TARGET("npc.chat.format.with-target-to-target", "[<npc>] -> [<targets>]: <text>"),
|
||||
CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[<npc>] -> [<target>]: <text>"),
|
||||
CHAT_RANGE("npc.chat.options.range", 5),
|
||||
CHAT_BYSTANDERS_HEAR_TARGETED_CHAT("npc.chat.options.bystanders-hear-targeted-chat", true),
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.citizensnpcs.npc.ai.speech;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -9,79 +11,102 @@ import net.citizensnpcs.Settings.Setting;
|
||||
import net.citizensnpcs.api.CitizensAPI;
|
||||
import net.citizensnpcs.api.ai.speech.Talkable;
|
||||
import net.citizensnpcs.api.ai.speech.TalkableEntity;
|
||||
import net.citizensnpcs.api.ai.speech.Tongue;
|
||||
import net.citizensnpcs.api.ai.speech.SpeechContext;
|
||||
import net.citizensnpcs.api.ai.speech.VocalChord;
|
||||
import net.citizensnpcs.api.npc.NPC;
|
||||
import net.citizensnpcs.util.Messaging;
|
||||
|
||||
public class Chat implements VocalChord {
|
||||
|
||||
/*
|
||||
CHAT_FORMAT("npc.chat.format.no-targets", "[<npc>]: <text>"),
|
||||
CHAT_FORMAT_TO_TARGET("npc.chat.format.to-target", "[<npc>] -> You: <text>"),
|
||||
CHAT_FORMAT_TO_BYSTANDERS("npc.chat.prefix.to-bystanders", "[<npc>] -> [<target>]: <text>"),
|
||||
CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS("npc.chat.format.with-target-to-bystanders", "[<npc>] -> [<targets>]: <text>"),
|
||||
CHAT_RANGE("npc.chat.options.range", 5),
|
||||
CHAT_BYSTANDERS_HEAR_TARGETED_CHAT("npc.chat.options.bystanders-hear-targeted-chat", true),
|
||||
CHAT_MAX_NUMBER_OF_TARGETS("npc.chat.options.max-number-of-targets-to-show", 2),
|
||||
CHAT_MULTIPLE_TARGETS_FORMAT("npc.chat.options.multiple-targets-format", "<target>,|<target>|& <target>|& others"),
|
||||
*/
|
||||
|
||||
public final String VOCAL_CHORD_NAME = "chat";
|
||||
|
||||
@Override
|
||||
public void talk(Tongue tongue) {
|
||||
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(tongue.getTalker().getEntity());
|
||||
@Override
|
||||
public void talk(SpeechContext context) {
|
||||
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getNPC(context.getTalker().getEntity());
|
||||
|
||||
// If no recipients, chat to the world with CHAT_FORMAT and CHAT_RANGE settings
|
||||
if (!tongue.isTargeted()) {
|
||||
String text = Setting.CHAT_FORMAT.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
|
||||
talkToBystanders(npc, text, tongue);
|
||||
if (!context.hasRecipients()) {
|
||||
String text = Setting.CHAT_FORMAT.asString().replace("<npc>", npc.getName()).replace("<text>", context.getMessage());
|
||||
talkToBystanders(npc, text, context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Assumed recipients at this point
|
||||
else if (tongue.getRecipients().size() <= 1) { // One recipient
|
||||
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
|
||||
tongue.getRecipients().get(0).talkTo(tongue, text, this);
|
||||
else if (context.size() <= 1) { // One recipient
|
||||
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", context.getMessage());
|
||||
String targetName = "";
|
||||
// For each recipient
|
||||
for (Talkable entity : context) {
|
||||
entity.talkTo(context, text, this);
|
||||
targetName = entity.getName();
|
||||
}
|
||||
// Check if bystanders hear targeted chat
|
||||
if (!Setting.CHAT_BYSTANDERS_HEAR_TARGETED_CHAT.asBoolean()) return;
|
||||
String bystanderText = Setting.CHAT_FORMAT_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<target>", tongue.getRecipients().get(0).getName()).replace("<text>", tongue.getContents());
|
||||
talkToBystanders(npc, bystanderText, tongue);
|
||||
// Format message with config setting and send to bystanders
|
||||
String bystanderText = Setting.CHAT_FORMAT_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<target>", targetName).replace("<text>", context.getMessage());
|
||||
talkToBystanders(npc, bystanderText, context);
|
||||
return;
|
||||
}
|
||||
|
||||
else { // Multiple recipients
|
||||
// Set up text
|
||||
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", tongue.getContents());
|
||||
tongue.getRecipients().get(0).talkTo(tongue, text, this);
|
||||
if (!Setting.CHAT_BYSTANDERS_HEAR_TARGETED_CHAT.asBoolean()) return;
|
||||
String bystanders = null;
|
||||
bystanders = bystanders + "";
|
||||
String bystanderText = Setting.CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<targets>", tongue.getRecipients().get(0).getName()).replace("<text>", tongue.getContents());
|
||||
talkToBystanders(npc, bystanderText, tongue);
|
||||
|
||||
// TODO: Finish multiple recipients
|
||||
|
||||
else { // Multiple recipients
|
||||
String text = Setting.CHAT_FORMAT_TO_TARGET.asString().replace("<npc>", npc.getName()).replace("<text>", context.getMessage());
|
||||
List<String> targetNames = Collections.emptyList();
|
||||
// Talk to each recipient
|
||||
for (Talkable entity : context) {
|
||||
entity.talkTo(context, text, this);
|
||||
targetNames.add(entity.getName());
|
||||
}
|
||||
|
||||
if (!Setting.CHAT_BYSTANDERS_HEAR_TARGETED_CHAT.asBoolean()) return;
|
||||
String targets = "";
|
||||
int max = Setting.CHAT_MAX_NUMBER_OF_TARGETS.asInt();
|
||||
String[] format = Setting.CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS.asString().split("\\|");
|
||||
if (format.length != 4) Messaging.log(Level.WARNING, "npc.chat.format.with-target-to-bystanders invalid!");
|
||||
if (max == 1) {
|
||||
targets = format[0].replace("<npc>", targetNames.get(0)) + format[3];
|
||||
}
|
||||
else if (max == 2 || targetNames.size() == 2) {
|
||||
if (targetNames.size() == 2)
|
||||
targets = format[0].replace("<npc>", targetNames.get(0)) + format[2].replace("<npc>", targetNames.get(1));
|
||||
else
|
||||
targets = format[0].replace("<npc>", targetNames.get(0)) + format[1].replace("<npc>", targetNames.get(1)) + format[3];
|
||||
}
|
||||
else if (max >= 3) {
|
||||
targets = format[0].replace("<npc>", targetNames.get(0));
|
||||
|
||||
int x = 1;
|
||||
for (x = 1; x < max - 1; x++) {
|
||||
if (targetNames.size() - 1 == x) break;
|
||||
targets = targets + format[1].replace("<npc>", targetNames.get(x));
|
||||
}
|
||||
if (targetNames.size() == max)
|
||||
targets = targets + format[2].replace("<npc>", targetNames.get(x));
|
||||
else targets = targets + format[3];
|
||||
}
|
||||
|
||||
String bystanderText = Setting.CHAT_FORMAT_WITH_TARGETS_TO_BYSTANDERS.asString().replace("<npc>", npc.getName()).replace("<targets>", targets).replace("<text>", context.getMessage());
|
||||
talkToBystanders(npc, bystanderText, context);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void talkToBystanders(NPC npc, String text, Tongue tongue) {
|
||||
private void talkToBystanders(NPC npc, String text, SpeechContext context) {
|
||||
// Get list of nearby entities
|
||||
List<Entity> bystanderEntities = npc.getBukkitEntity().getNearbyEntities(Setting.CHAT_RANGE.asDouble(), Setting.CHAT_RANGE.asDouble(), Setting.CHAT_RANGE.asDouble());
|
||||
for (Entity bystander : bystanderEntities)
|
||||
// Continue if a LivingEntity, which is compatible with TalkableEntity
|
||||
if (bystander instanceof LivingEntity) {
|
||||
// Exclude Targets
|
||||
if (tongue.isTargeted()) {
|
||||
for (Talkable target : tongue.getRecipients())
|
||||
// Exclude targeted recipients
|
||||
if (context.hasRecipients()) {
|
||||
for (Talkable target : context)
|
||||
if (target.getEntity() == bystander) continue;
|
||||
} else
|
||||
// Found a nearby LivingEntity, make it Talkable and talkNear it
|
||||
new TalkableEntity((LivingEntity) bystander).talkNear(tongue, text, this);
|
||||
// Found a nearby LivingEntity, make it Talkable and talkNear it
|
||||
new TalkableEntity((LivingEntity) bystander).talkNear(context, text, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return VOCAL_CHORD_NAME;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.citizensnpcs.npc.ai.speech;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@ -9,7 +9,7 @@ import net.citizensnpcs.api.ai.speech.VocalChord;
|
||||
|
||||
public class CitizensSpeechFactory implements SpeechFactory {
|
||||
|
||||
Map<String, Class<? extends VocalChord>> registered = Collections.emptyMap();
|
||||
Map<String, Class<? extends VocalChord>> registered = new HashMap<String, Class <? extends VocalChord>>();
|
||||
|
||||
@Override
|
||||
public void register(Class<? extends VocalChord> clazz, String name) {
|
||||
|
@ -1,232 +1,237 @@
|
||||
package net.citizensnpcs.trait.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.citizensnpcs.Settings.Setting;
|
||||
import net.citizensnpcs.api.CitizensAPI;
|
||||
import net.citizensnpcs.api.event.NPCRightClickEvent;
|
||||
import net.citizensnpcs.api.exception.NPCLoadException;
|
||||
import net.citizensnpcs.api.trait.Trait;
|
||||
import net.citizensnpcs.api.util.DataKey;
|
||||
import net.citizensnpcs.editor.Editor;
|
||||
import net.citizensnpcs.trait.Toggleable;
|
||||
import net.citizensnpcs.util.Messages;
|
||||
import net.citizensnpcs.util.Messaging;
|
||||
import net.citizensnpcs.util.Paginator;
|
||||
import net.citizensnpcs.util.Util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.conversations.ConversationAbandonedListener;
|
||||
import org.bukkit.conversations.ConversationFactory;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener {
|
||||
private final Map<String, Date> cooldowns = new HashMap<String, Date>();
|
||||
private int currentIndex;
|
||||
private String itemInHandPattern = "default";
|
||||
private final Plugin plugin;
|
||||
private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean();
|
||||
private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble();
|
||||
private boolean realisticLooker = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean();
|
||||
private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean();
|
||||
private final List<String> text = new ArrayList<String>();
|
||||
|
||||
public Text() {
|
||||
super("text");
|
||||
this.plugin = CitizensAPI.getPlugin();
|
||||
}
|
||||
|
||||
void add(String string) {
|
||||
text.add(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conversationAbandoned(ConversationAbandonedEvent event) {
|
||||
Bukkit.dispatchCommand((Player) event.getContext().getForWhom(), "npc text");
|
||||
}
|
||||
|
||||
void edit(int index, String newText) {
|
||||
text.set(index, newText);
|
||||
}
|
||||
|
||||
public Editor getEditor(final Player player) {
|
||||
final Conversation conversation = new ConversationFactory(plugin)
|
||||
.addConversationAbandonedListener(this).withLocalEcho(false).withEscapeSequence("/npc text")
|
||||
.withEscapeSequence("exit").withModality(false).withFirstPrompt(new TextStartPrompt(this))
|
||||
.buildConversation(player);
|
||||
return new Editor() {
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
Messaging.sendTr(player, Messages.TEXT_EDITOR_BEGIN);
|
||||
conversation.begin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
Messaging.sendTr(player, Messages.TEXT_EDITOR_END);
|
||||
conversation.abandon();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
boolean hasIndex(int index) {
|
||||
return index >= 0 && text.size() > index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataKey key) throws NPCLoadException {
|
||||
text.clear();
|
||||
// TODO: legacy, remove later
|
||||
for (DataKey sub : key.getIntegerSubKeys())
|
||||
text.add(sub.getString(""));
|
||||
for (DataKey sub : key.getRelative("text").getIntegerSubKeys())
|
||||
text.add(sub.getString(""));
|
||||
if (text.isEmpty())
|
||||
populateDefaultText();
|
||||
|
||||
talkClose = key.getBoolean("talk-close", talkClose);
|
||||
realisticLooker = key.getBoolean("realistic-looking", realisticLooker);
|
||||
randomTalker = key.getBoolean("random-talker", randomTalker);
|
||||
range = key.getDouble("range", range);
|
||||
itemInHandPattern = key.getString("talkitem", itemInHandPattern);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRightClick(NPCRightClickEvent event) {
|
||||
if (!event.getNPC().equals(npc))
|
||||
return;
|
||||
String localPattern = itemInHandPattern.equals("default") ? Setting.TALK_ITEM.asString()
|
||||
: itemInHandPattern;
|
||||
if (Util.matchesItemInHand(event.getClicker(), localPattern) && !shouldTalkClose())
|
||||
sendText(event.getClicker());
|
||||
}
|
||||
|
||||
private void populateDefaultText() {
|
||||
text.addAll(Setting.DEFAULT_TEXT.asList());
|
||||
}
|
||||
|
||||
void remove(int index) {
|
||||
text.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!talkClose || !npc.isSpawned())
|
||||
return;
|
||||
List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range);
|
||||
for (Entity search : nearby) {
|
||||
if (!(search instanceof Player))
|
||||
continue;
|
||||
Player player = (Player) search;
|
||||
// If the cooldown is not expired, do not send text
|
||||
Date cooldown = cooldowns.get(player.getName());
|
||||
if (cooldown != null) {
|
||||
if (!new Date().after(cooldown))
|
||||
return;
|
||||
cooldowns.remove(player.getName());
|
||||
}
|
||||
if (!sendText(player))
|
||||
return;
|
||||
// Add a cooldown if the text was successfully sent
|
||||
Date wait = new Date();
|
||||
int secondsDelta = RANDOM.nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt())
|
||||
+ Setting.TALK_CLOSE_MINIMUM_COOLDOWN.asInt();
|
||||
if (secondsDelta <= 0)
|
||||
return;
|
||||
long millisecondsDelta = TimeUnit.MILLISECONDS.convert(secondsDelta, TimeUnit.SECONDS);
|
||||
wait.setTime(wait.getTime() + millisecondsDelta);
|
||||
cooldowns.put(player.getName(), wait);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataKey key) {
|
||||
key.setBoolean("talk-close", talkClose);
|
||||
key.setBoolean("random-talker", randomTalker);
|
||||
key.setBoolean("realistic-looking", realisticLooker);
|
||||
key.setDouble("range", range);
|
||||
key.setString("talkitem", itemInHandPattern);
|
||||
// TODO: legacy, remove later
|
||||
for (int i = 0; i < 100; i++)
|
||||
key.removeKey(String.valueOf(i));
|
||||
key.removeKey("text");
|
||||
for (int i = 0; i < text.size(); i++)
|
||||
key.setString("text." + String.valueOf(i), text.get(i));
|
||||
}
|
||||
|
||||
boolean sendPage(Player player, int page) {
|
||||
Paginator paginator = new Paginator().header(npc.getName() + "'s Text Entries");
|
||||
for (int i = 0; i < text.size(); i++)
|
||||
paginator.addLine("<a>" + i + " <7>- <e>" + text.get(i));
|
||||
|
||||
return paginator.sendPage(player, page);
|
||||
}
|
||||
|
||||
private boolean sendText(Player player) {
|
||||
if (!player.hasPermission("citizens.admin") && !player.hasPermission("citizens.npc.talk"))
|
||||
return false;
|
||||
if (text.size() == 0)
|
||||
return false;
|
||||
|
||||
int index = 0;
|
||||
if (randomTalker)
|
||||
index = new Random().nextInt(text.size());
|
||||
else {
|
||||
if (currentIndex > text.size() - 1)
|
||||
currentIndex = 0;
|
||||
index = currentIndex++;
|
||||
}
|
||||
Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + text.get(index), npc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setItemInHandPattern(String pattern) {
|
||||
itemInHandPattern = pattern;
|
||||
}
|
||||
|
||||
void setRange(double range) {
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
boolean shouldTalkClose() {
|
||||
return talkClose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toggle() {
|
||||
return (talkClose = !talkClose);
|
||||
}
|
||||
|
||||
boolean toggleRandomTalker() {
|
||||
return (randomTalker = !randomTalker);
|
||||
}
|
||||
|
||||
boolean toggleRealisticLooking() {
|
||||
return (realisticLooker = !realisticLooker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Text{talk-close=" + talkClose + ",text=");
|
||||
for (String line : text)
|
||||
builder.append(line + ",");
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static Random RANDOM = Util.getFastRandom();
|
||||
package net.citizensnpcs.trait.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.citizensnpcs.Settings.Setting;
|
||||
import net.citizensnpcs.api.CitizensAPI;
|
||||
import net.citizensnpcs.api.ai.speech.SpeechContext;
|
||||
import net.citizensnpcs.api.ai.speech.Talkable;
|
||||
import net.citizensnpcs.api.ai.speech.TalkableEntity;
|
||||
import net.citizensnpcs.api.event.NPCRightClickEvent;
|
||||
import net.citizensnpcs.api.exception.NPCLoadException;
|
||||
import net.citizensnpcs.api.trait.Trait;
|
||||
import net.citizensnpcs.api.util.DataKey;
|
||||
import net.citizensnpcs.editor.Editor;
|
||||
import net.citizensnpcs.trait.Toggleable;
|
||||
import net.citizensnpcs.util.Messages;
|
||||
import net.citizensnpcs.util.Messaging;
|
||||
import net.citizensnpcs.util.Paginator;
|
||||
import net.citizensnpcs.util.Util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.conversations.ConversationAbandonedListener;
|
||||
import org.bukkit.conversations.ConversationFactory;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener {
|
||||
private final Map<String, Date> cooldowns = new HashMap<String, Date>();
|
||||
private int currentIndex;
|
||||
private String itemInHandPattern = "default";
|
||||
private final Plugin plugin;
|
||||
private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean();
|
||||
private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble();
|
||||
private boolean realisticLooker = Setting.DEFAULT_REALISTIC_LOOKING.asBoolean();
|
||||
private boolean talkClose = Setting.DEFAULT_TALK_CLOSE.asBoolean();
|
||||
private final List<String> text = new ArrayList<String>();
|
||||
|
||||
public Text() {
|
||||
super("text");
|
||||
this.plugin = CitizensAPI.getPlugin();
|
||||
}
|
||||
|
||||
void add(String string) {
|
||||
text.add(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conversationAbandoned(ConversationAbandonedEvent event) {
|
||||
Bukkit.dispatchCommand((Player) event.getContext().getForWhom(), "npc text");
|
||||
}
|
||||
|
||||
void edit(int index, String newText) {
|
||||
text.set(index, newText);
|
||||
}
|
||||
|
||||
public Editor getEditor(final Player player) {
|
||||
final Conversation conversation = new ConversationFactory(plugin)
|
||||
.addConversationAbandonedListener(this).withLocalEcho(false).withEscapeSequence("/npc text")
|
||||
.withEscapeSequence("exit").withModality(false).withFirstPrompt(new TextStartPrompt(this))
|
||||
.buildConversation(player);
|
||||
return new Editor() {
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
Messaging.sendTr(player, Messages.TEXT_EDITOR_BEGIN);
|
||||
conversation.begin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
Messaging.sendTr(player, Messages.TEXT_EDITOR_END);
|
||||
conversation.abandon();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
boolean hasIndex(int index) {
|
||||
return index >= 0 && text.size() > index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(DataKey key) throws NPCLoadException {
|
||||
text.clear();
|
||||
// TODO: legacy, remove later
|
||||
for (DataKey sub : key.getIntegerSubKeys())
|
||||
text.add(sub.getString(""));
|
||||
for (DataKey sub : key.getRelative("text").getIntegerSubKeys())
|
||||
text.add(sub.getString(""));
|
||||
if (text.isEmpty())
|
||||
populateDefaultText();
|
||||
|
||||
talkClose = key.getBoolean("talk-close", talkClose);
|
||||
realisticLooker = key.getBoolean("realistic-looking", realisticLooker);
|
||||
randomTalker = key.getBoolean("random-talker", randomTalker);
|
||||
range = key.getDouble("range", range);
|
||||
itemInHandPattern = key.getString("talkitem", itemInHandPattern);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRightClick(NPCRightClickEvent event) {
|
||||
if (!event.getNPC().equals(npc))
|
||||
return;
|
||||
String localPattern = itemInHandPattern.equals("default") ? Setting.TALK_ITEM.asString()
|
||||
: itemInHandPattern;
|
||||
if (Util.matchesItemInHand(event.getClicker(), localPattern) && !shouldTalkClose())
|
||||
sendText(event.getClicker());
|
||||
}
|
||||
|
||||
private void populateDefaultText() {
|
||||
text.addAll(Setting.DEFAULT_TEXT.asList());
|
||||
}
|
||||
|
||||
void remove(int index) {
|
||||
text.remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!talkClose || !npc.isSpawned())
|
||||
return;
|
||||
List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range);
|
||||
for (Entity search : nearby) {
|
||||
if (!(search instanceof Player))
|
||||
continue;
|
||||
Player player = (Player) search;
|
||||
// If the cooldown is not expired, do not send text
|
||||
Date cooldown = cooldowns.get(player.getName());
|
||||
if (cooldown != null) {
|
||||
if (!new Date().after(cooldown))
|
||||
return;
|
||||
cooldowns.remove(player.getName());
|
||||
}
|
||||
if (!sendText(player))
|
||||
return;
|
||||
// Add a cooldown if the text was successfully sent
|
||||
Date wait = new Date();
|
||||
int secondsDelta = RANDOM.nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt())
|
||||
+ Setting.TALK_CLOSE_MINIMUM_COOLDOWN.asInt();
|
||||
if (secondsDelta <= 0)
|
||||
return;
|
||||
long millisecondsDelta = TimeUnit.MILLISECONDS.convert(secondsDelta, TimeUnit.SECONDS);
|
||||
wait.setTime(wait.getTime() + millisecondsDelta);
|
||||
cooldowns.put(player.getName(), wait);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataKey key) {
|
||||
key.setBoolean("talk-close", talkClose);
|
||||
key.setBoolean("random-talker", randomTalker);
|
||||
key.setBoolean("realistic-looking", realisticLooker);
|
||||
key.setDouble("range", range);
|
||||
key.setString("talkitem", itemInHandPattern);
|
||||
// TODO: legacy, remove later
|
||||
for (int i = 0; i < 100; i++)
|
||||
key.removeKey(String.valueOf(i));
|
||||
key.removeKey("text");
|
||||
for (int i = 0; i < text.size(); i++)
|
||||
key.setString("text." + String.valueOf(i), text.get(i));
|
||||
}
|
||||
|
||||
boolean sendPage(Player player, int page) {
|
||||
Paginator paginator = new Paginator().header(npc.getName() + "'s Text Entries");
|
||||
for (int i = 0; i < text.size(); i++)
|
||||
paginator.addLine("<a>" + i + " <7>- <e>" + text.get(i));
|
||||
|
||||
return paginator.sendPage(player, page);
|
||||
}
|
||||
|
||||
private boolean sendText(Player player) {
|
||||
if (!player.hasPermission("citizens.admin") && !player.hasPermission("citizens.npc.talk"))
|
||||
return false;
|
||||
if (text.size() == 0)
|
||||
return false;
|
||||
|
||||
int index = 0;
|
||||
if (randomTalker)
|
||||
index = new Random().nextInt(text.size());
|
||||
else {
|
||||
if (currentIndex > text.size() - 1)
|
||||
currentIndex = 0;
|
||||
index = currentIndex++;
|
||||
}
|
||||
|
||||
npc.getDefaultSpeechController().speak(new SpeechContext(text.get(index), new TalkableEntity(player)));
|
||||
// Messaging.sendWithNPC(player, Setting.CHAT_PREFIX.asString() + text.get(index), npc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setItemInHandPattern(String pattern) {
|
||||
itemInHandPattern = pattern;
|
||||
}
|
||||
|
||||
void setRange(double range) {
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
boolean shouldTalkClose() {
|
||||
return talkClose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toggle() {
|
||||
return (talkClose = !talkClose);
|
||||
}
|
||||
|
||||
boolean toggleRandomTalker() {
|
||||
return (randomTalker = !randomTalker);
|
||||
}
|
||||
|
||||
boolean toggleRealisticLooking() {
|
||||
return (realisticLooker = !realisticLooker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Text{talk-close=" + talkClose + ",text=");
|
||||
for (String line : text)
|
||||
builder.append(line + ",");
|
||||
builder.append("}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static Random RANDOM = Util.getFastRandom();
|
||||
}
|
Loading…
Reference in New Issue
Block a user