Improve text

This commit is contained in:
fullwall 2012-11-04 13:31:22 +08:00
parent e9128acb47
commit bcd3975f1c
10 changed files with 122 additions and 82 deletions

View File

@ -72,9 +72,14 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
Iterator<NPC> itr = npcRegistry.iterator(); Iterator<NPC> itr = npcRegistry.iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
NPC npc = itr.next(); NPC npc = itr.next();
try {
npc.despawn(); npc.despawn();
for (Trait t : npc.getTraits()) for (Trait t : npc.getTraits())
t.onRemove(); t.onRemove();
} catch (Exception e) {
e.printStackTrace();
// ensure that all entities are despawned
}
itr.remove(); itr.remove();
} }
} }

View File

@ -70,7 +70,7 @@ public class NPCSelector implements Listener {
NPC npc = event.getNPC(); NPC npc = event.getNPC();
List<MetadataValue> selected = player.getMetadata("selected"); List<MetadataValue> selected = player.getMetadata("selected");
if (selected == null || selected.size() == 0 || selected.get(0).asInt() != npc.getId()) { if (selected == null || selected.size() == 0 || selected.get(0).asInt() != npc.getId()) {
if (Util.isSettingFulfilled(player, Setting.SELECTION_ITEM) if (Util.matchesItemInHand(player, Setting.SELECTION_ITEM.asString())
&& npc.getTrait(Owner.class).isOwnedBy(player)) { && npc.getTrait(Owner.class).isOwnedBy(player)) {
player.removeMetadata("selected", plugin); player.removeMetadata("selected", plugin);
select(player, npc); select(player, npc);

View File

@ -15,20 +15,18 @@ import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.editor.Editor; import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPC;
import net.citizensnpcs.trait.Toggleable; import net.citizensnpcs.trait.Toggleable;
import net.citizensnpcs.util.Messages; import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging; import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.Paginator; import net.citizensnpcs.util.Paginator;
import net.citizensnpcs.util.Util; import net.citizensnpcs.util.Util;
import net.minecraft.server.EntityHuman;
import net.minecraft.server.EntityLiving;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.conversations.Conversation; import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent; import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.conversations.ConversationAbandonedListener; import org.bukkit.conversations.ConversationAbandonedListener;
import org.bukkit.conversations.ConversationFactory; import org.bukkit.conversations.ConversationFactory;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -37,6 +35,7 @@ import org.bukkit.plugin.Plugin;
public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener { public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener {
private final Map<String, Date> cooldowns = new HashMap<String, Date>(); private final Map<String, Date> cooldowns = new HashMap<String, Date>();
private int currentIndex; private int currentIndex;
private String itemInHandPattern = Setting.TALK_ITEM.asString();
private final Plugin plugin; private final Plugin plugin;
private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean(); private boolean randomTalker = Setting.DEFAULT_RANDOM_TALKER.asBoolean();
private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble(); private double range = Setting.DEFAULT_TALK_CLOSE_RANGE.asDouble();
@ -49,7 +48,7 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
this.plugin = CitizensAPI.getPlugin(); this.plugin = CitizensAPI.getPlugin();
} }
public void add(String string) { void add(String string) {
text.add(string); text.add(string);
} }
@ -58,7 +57,7 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
Bukkit.dispatchCommand((Player) event.getContext().getForWhom(), "npc text"); Bukkit.dispatchCommand((Player) event.getContext().getForWhom(), "npc text");
} }
public void edit(int index, String newText) { void edit(int index, String newText) {
text.set(index, newText); text.set(index, newText);
} }
@ -78,18 +77,19 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
@Override @Override
public void end() { public void end() {
Messaging.sendTr(player, Messages.TEXT_EDITOR_END); Messaging.sendTr(player, Messages.TEXT_EDITOR_END);
conversation.abandon();
} }
}; };
} }
public boolean hasIndex(int index) { boolean hasIndex(int index) {
return index >= 0 && text.size() > index; return index >= 0 && text.size() > index;
} }
@Override @Override
public void load(DataKey key) throws NPCLoadException { public void load(DataKey key) throws NPCLoadException {
text.clear(); text.clear();
// TODO: backwards compat, remove later // TODO: legacy, remove later
for (DataKey sub : key.getIntegerSubKeys()) for (DataKey sub : key.getIntegerSubKeys())
text.add(sub.getString("")); text.add(sub.getString(""));
for (DataKey sub : key.getRelative("text").getIntegerSubKeys()) for (DataKey sub : key.getRelative("text").getIntegerSubKeys())
@ -101,13 +101,14 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
realisticLooker = key.getBoolean("realistic-looking", realisticLooker); realisticLooker = key.getBoolean("realistic-looking", realisticLooker);
randomTalker = key.getBoolean("random-talker", randomTalker); randomTalker = key.getBoolean("random-talker", randomTalker);
range = key.getDouble("range", range); range = key.getDouble("range", range);
itemInHandPattern = key.getString("talkitem", itemInHandPattern);
} }
@EventHandler @EventHandler
public void onRightClick(NPCRightClickEvent event) { public void onRightClick(NPCRightClickEvent event) {
if (!event.getNPC().equals(npc)) if (!event.getNPC().equals(npc))
return; return;
if (Util.isSettingFulfilled(event.getClicker(), Setting.TALK_ITEM) && !shouldTalkClose()) if (Util.matchesItemInHand(event.getClicker(), itemInHandPattern) && !shouldTalkClose())
sendText(event.getClicker()); sendText(event.getClicker());
} }
@ -115,35 +116,39 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
text.addAll(Setting.DEFAULT_TEXT.asList()); text.addAll(Setting.DEFAULT_TEXT.asList());
} }
public void remove(int index) { void remove(int index) {
text.remove(index); text.remove(index);
} }
@Override @Override
public void run() { public void run() {
if (!npc.isSpawned()) if (!npc.isSpawned() || !talkClose)
return; return;
EntityHuman search = null; List<Entity> nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range);
EntityLiving handle = ((CitizensNPC) npc).getHandle(); for (Entity search : nearby) {
if ((search = handle.world.findNearbyPlayer(handle, range)) != null && talkClose) { if (!(search instanceof Player))
Player player = (Player) search.getBukkitEntity(); continue;
Player player = (Player) search;
// If the cooldown is not expired, do not send text // If the cooldown is not expired, do not send text
if (cooldowns.get(player.getName()) != null) { Date cooldown = cooldowns.get(player.getName());
if (!new Date().after(cooldowns.get(player.getName()))) if (cooldown != null) {
if (!new Date().after(cooldown))
return; return;
cooldowns.remove(player.getName()); cooldowns.remove(player.getName());
} }
if (sendText(player)) { if (!sendText(player))
return;
// Add a cooldown if the text was successfully sent // Add a cooldown if the text was successfully sent
Date wait = new Date(); Date wait = new Date();
int secondsDelta = new Random().nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt()) int secondsDelta = new Random().nextInt(Setting.TALK_CLOSE_MAXIMUM_COOLDOWN.asInt())
+ Setting.TALK_CLOSE_MINIMUM_COOLDOWN.asInt(); + Setting.TALK_CLOSE_MINIMUM_COOLDOWN.asInt();
if (secondsDelta <= 0)
return;
long millisecondsDelta = TimeUnit.MILLISECONDS.convert(secondsDelta, TimeUnit.SECONDS); long millisecondsDelta = TimeUnit.MILLISECONDS.convert(secondsDelta, TimeUnit.SECONDS);
wait.setTime(wait.getTime() + millisecondsDelta); wait.setTime(wait.getTime() + millisecondsDelta);
cooldowns.put(player.getName(), wait); cooldowns.put(player.getName(), wait);
} }
} }
}
@Override @Override
public void save(DataKey key) { public void save(DataKey key) {
@ -151,7 +156,8 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
key.setBoolean("random-talker", randomTalker); key.setBoolean("random-talker", randomTalker);
key.setBoolean("realistic-looking", realisticLooker); key.setBoolean("realistic-looking", realisticLooker);
key.setDouble("range", range); key.setDouble("range", range);
// TODO: for backwards compat purposes, remove later key.setString("talkitem", itemInHandPattern);
// TODO: legacy, remove later
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
key.removeKey(String.valueOf(i)); key.removeKey(String.valueOf(i));
key.removeKey("text"); key.removeKey("text");
@ -159,7 +165,7 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
key.setString("text." + String.valueOf(i), text.get(i)); key.setString("text." + String.valueOf(i), text.get(i));
} }
public boolean sendPage(Player player, int page) { boolean sendPage(Player player, int page) {
Paginator paginator = new Paginator().header(npc.getName() + "'s Text Entries"); Paginator paginator = new Paginator().header(npc.getName() + "'s Text Entries");
for (int i = 0; i < text.size(); i++) for (int i = 0; i < text.size(); i++)
paginator.addLine("<a>" + i + " <7>- <e>" + text.get(i)); paginator.addLine("<a>" + i + " <7>- <e>" + text.get(i));
@ -167,7 +173,7 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
return paginator.sendPage(player, page); return paginator.sendPage(player, page);
} }
public boolean sendText(Player player) { private boolean sendText(Player player) {
if (!player.hasPermission("citizens.admin") && !player.hasPermission("citizens.npc.talk")) if (!player.hasPermission("citizens.admin") && !player.hasPermission("citizens.npc.talk"))
return false; return false;
if (text.size() == 0) if (text.size() == 0)
@ -185,7 +191,15 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
return true; return true;
} }
public boolean shouldTalkClose() { void setItemInHandPattern(String pattern) {
itemInHandPattern = pattern;
}
void setRange(double range) {
this.range = range;
}
boolean shouldTalkClose() {
return talkClose; return talkClose;
} }
@ -194,11 +208,11 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
return (talkClose = !talkClose); return (talkClose = !talkClose);
} }
public boolean toggleRandomTalker() { boolean toggleRandomTalker() {
return (randomTalker = !randomTalker); return (randomTalker = !randomTalker);
} }
public boolean toggleRealisticLooking() { boolean toggleRealisticLooking() {
return (realisticLooker = !realisticLooker); return (realisticLooker = !realisticLooker);
} }

View File

@ -17,8 +17,9 @@ public class TextStartPrompt extends StringPrompt {
} }
@Override @Override
public Prompt acceptInput(ConversationContext context, String input) { public Prompt acceptInput(ConversationContext context, String original) {
input = ChatColor.stripColor(input.trim().split(" ")[0]); String[] parts = ChatColor.stripColor(original.trim()).split(" ");
String input = parts[0];
CommandSender sender = (CommandSender) context.getForWhom(); CommandSender sender = (CommandSender) context.getForWhom();
if (input.equalsIgnoreCase("add")) if (input.equalsIgnoreCase("add"))
return new TextAddPrompt(text); return new TextAddPrompt(text);
@ -31,9 +32,24 @@ public class TextStartPrompt extends StringPrompt {
else if (input.equalsIgnoreCase("realistic looking")) else if (input.equalsIgnoreCase("realistic looking"))
Messaging.sendTr(sender, Messages.TEXT_EDITOR_REALISTIC_LOOKING_SET, Messaging.sendTr(sender, Messages.TEXT_EDITOR_REALISTIC_LOOKING_SET,
text.toggleRealisticLooking()); text.toggleRealisticLooking());
else if (input.equalsIgnoreCase("close")) else if (input.equalsIgnoreCase("close") || input.equalsIgnoreCase("talk-close"))
Messaging.sendTr(sender, Messages.TEXT_EDITOR_CLOSE_TALKER_SET, text.toggle()); Messaging.sendTr(sender, Messages.TEXT_EDITOR_CLOSE_TALKER_SET, text.toggle());
else if (input.equalsIgnoreCase("help")) { else if (input.equalsIgnoreCase("range")) {
try {
double range = Math.max(0, Double.parseDouble(parts[1]));
text.setRange(range);
Messaging.sendTr(sender, Messages.TEXT_EDITOR_RANGE_SET, range);
} catch (NumberFormatException e) {
Messaging.sendErrorTr(sender, Messages.TEXT_EDITOR_INVALID_RANGE);
} catch (ArrayIndexOutOfBoundsException e) {
Messaging.sendErrorTr(sender, Messages.TEXT_EDITOR_INVALID_RANGE);
}
} else if (input.equalsIgnoreCase("item")) {
if (parts.length > 1) {
text.setItemInHandPattern(parts[1]);
Messaging.sendTr(sender, Messages.TEXT_EDITOR_SET_ITEM, parts[1]);
}
} else if (input.equalsIgnoreCase("help")) {
context.setSessionData("said-text", false); context.setSessionData("said-text", false);
Messaging.send(sender, getPromptText(context)); Messaging.send(sender, getPromptText(context));
} else } else

View File

@ -104,6 +104,13 @@ public class LinearWaypointProvider implements WaypointProvider {
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_BEGIN); Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_BEGIN);
} }
private void clearWaypoints() {
editingSlot = 0;
waypoints.clear();
destroyWaypointMarkers();
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_WAYPOINTS_CLEARED);
}
private void createWaypointMarker(int index, Waypoint waypoint) { private void createWaypointMarker(int index, Waypoint waypoint) {
Entity entity = spawnMarker(player.getWorld(), waypoint.getLocation().add(0, 1, 0)); Entity entity = spawnMarker(player.getWorld(), waypoint.getLocation().add(0, 1, 0));
if (entity == null) if (entity == null)
@ -208,13 +215,6 @@ public class LinearWaypointProvider implements WaypointProvider {
}); });
} }
private void clearWaypoints() {
editingSlot = 0;
waypoints.clear();
destroyWaypointMarkers();
Messaging.sendTr(player, Messages.LINEAR_WAYPOINT_EDITOR_WAYPOINTS_CLEARED);
}
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL) if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL)
@ -328,6 +328,10 @@ public class LinearWaypointProvider implements WaypointProvider {
itr = getNewIterator(); itr = getNewIterator();
} }
private Navigator getNavigator() {
return npc.getNavigator();
}
private Iterator<Waypoint> getNewIterator() { private Iterator<Waypoint> getNewIterator() {
LinearWaypointsCompleteEvent event = new LinearWaypointsCompleteEvent( LinearWaypointsCompleteEvent event = new LinearWaypointsCompleteEvent(
LinearWaypointProvider.this, waypoints.iterator()); LinearWaypointProvider.this, waypoints.iterator());
@ -336,10 +340,6 @@ public class LinearWaypointProvider implements WaypointProvider {
return next; return next;
} }
private Navigator getNavigator() {
return npc.getNavigator();
}
public boolean isPaused() { public boolean isPaused() {
return paused; return paused;
} }

View File

@ -15,26 +15,26 @@ public class LinearWaypointsCompleteEvent extends CitizensEvent {
this.provider = provider; this.provider = provider;
} }
public WaypointProvider getWaypointProvider() { @Override
return provider; public HandlerList getHandlers() {
return handlers;
} }
public Iterator<Waypoint> getNextWaypoints() { public Iterator<Waypoint> getNextWaypoints() {
return next; return next;
} }
public WaypointProvider getWaypointProvider() {
return provider;
}
public void setNextWaypoints(Iterator<Waypoint> waypoints) { public void setNextWaypoints(Iterator<Waypoint> waypoints) {
this.next = waypoints; this.next = waypoints;
} }
@Override private static final HandlerList handlers = new HandlerList();
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
private static final HandlerList handlers = new HandlerList();
} }

View File

@ -174,11 +174,14 @@ public class Messages {
public static final String TEXT_EDITOR_INVALID_INDEX = "citizens.editors.text.invalid-index"; public static final String TEXT_EDITOR_INVALID_INDEX = "citizens.editors.text.invalid-index";
public static final String TEXT_EDITOR_INVALID_INPUT = "citizens.editors.text.invalid-input"; public static final String TEXT_EDITOR_INVALID_INPUT = "citizens.editors.text.invalid-input";
public static final String TEXT_EDITOR_INVALID_PAGE = "citizens.editors.text.invalid-page"; public static final String TEXT_EDITOR_INVALID_PAGE = "citizens.editors.text.invalid-page";
public static final String TEXT_EDITOR_INVALID_RANGE = "citizens.editors.text.invalid-range";
public static final String TEXT_EDITOR_PAGE_PROMPT = "citizens.editors.text.change-page-prompt"; public static final String TEXT_EDITOR_PAGE_PROMPT = "citizens.editors.text.change-page-prompt";
public static final String TEXT_EDITOR_RANDOM_TALKER_SET = "citizens.editors.text.random-talker-set"; public static final String TEXT_EDITOR_RANDOM_TALKER_SET = "citizens.editors.text.random-talker-set";
public static final String TEXT_EDITOR_RANGE_SET = "citizens.editors.text.range-set";
public static final String TEXT_EDITOR_REALISTIC_LOOKING_SET = "citizens.editors.text.realistic-looking-set"; public static final String TEXT_EDITOR_REALISTIC_LOOKING_SET = "citizens.editors.text.realistic-looking-set";
public static final String TEXT_EDITOR_REMOVE_PROMPT = "citizens.editors.text.remove-prompt"; public static final String TEXT_EDITOR_REMOVE_PROMPT = "citizens.editors.text.remove-prompt";
public static final String TEXT_EDITOR_REMOVED_ENTRY = "citizens.editors.text.removed-entry"; public static final String TEXT_EDITOR_REMOVED_ENTRY = "citizens.editors.text.removed-entry";
public static final String TEXT_EDITOR_SET_ITEM = "citizens.editors.text.talk-item-set";
public static final String TEXT_EDITOR_START_PROMPT = "citizens.editors.text.start-prompt"; public static final String TEXT_EDITOR_START_PROMPT = "citizens.editors.text.start-prompt";
public static final String TRAIT_LOAD_FAILED = "citizens.notifications.trait-load-failed"; public static final String TRAIT_LOAD_FAILED = "citizens.notifications.trait-load-failed";
public static final String TRAIT_NOT_CONFIGURABLE = "citizens.commands.traitc.not-configurable"; public static final String TRAIT_NOT_CONFIGURABLE = "citizens.commands.traitc.not-configurable";

View File

@ -280,6 +280,10 @@ public class NMS {
} }
} }
public static void updateSenses(EntityLiving entity) {
entity.az().a();
}
static { static {
// true field above false and three synchronised lists // true field above false and three synchronised lists
THREAD_STOPPER = getField(NetworkManager.class, "m"); THREAD_STOPPER = getField(NetworkManager.class, "m");
@ -322,8 +326,4 @@ public class NMS {
STAIR_MATERIALS.add(material.getId()); STAIR_MATERIALS.add(material.getId());
} }
} }
public static void updateSenses(EntityLiving entity) {
entity.az().a();
}
} }

View File

@ -1,6 +1,5 @@
package net.citizensnpcs.util; package net.citizensnpcs.util;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.event.NPCCollisionEvent; import net.citizensnpcs.api.event.NPCCollisionEvent;
import net.citizensnpcs.api.event.NPCPushEvent; import net.citizensnpcs.api.event.NPCPushEvent;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
@ -104,16 +103,12 @@ public class Util {
return ((0 <= degrees) && (degrees < 45 + leeway)) || ((315 - leeway <= degrees) && (degrees <= 360)); return ((0 <= degrees) && (degrees < 45 + leeway)) || ((315 - leeway <= degrees) && (degrees <= 360));
} }
public static boolean isSettingFulfilled(Player player, Setting setting) { public static boolean isLoaded(Location location) {
String parts = setting.asString(); if (location.getWorld() == null)
if (parts.contains("*"))
return true;
for (String part : Splitter.on(',').split(parts)) {
if (Material.matchMaterial(part) == player.getItemInHand().getType()) {
return true;
}
}
return false; return false;
int chunkX = location.getBlockX() >> 4;
int chunkZ = location.getBlockZ() >> 4;
return location.getWorld().isChunkLoaded(chunkX, chunkZ);
} }
public static EntityType matchEntityType(String toMatch) { public static EntityType matchEntityType(String toMatch) {
@ -138,6 +133,18 @@ public class Util {
return type; return type;
} }
public static boolean matchesItemInHand(Player player, String setting) {
String parts = setting;
if (parts.contains("*"))
return true;
for (String part : Splitter.on(',').split(parts)) {
if (Material.matchMaterial(part) == player.getItemInHand().getType()) {
return true;
}
}
return false;
}
public static void sendPacketNearby(Location location, Packet packet) { public static void sendPacketNearby(Location location, Packet packet) {
sendPacketNearby(location, packet, 64); sendPacketNearby(location, packet, 64);
} }
@ -166,12 +173,4 @@ public class Util {
} }
} }
} }
public static boolean isLoaded(Location location) {
if (location.getWorld() == null)
return false;
int chunkX = location.getBlockX() >> 4;
int chunkZ = location.getBlockZ() >> 4;
return location.getWorld().isChunkLoaded(chunkX, chunkZ);
}
} }

View File

@ -131,11 +131,14 @@ citizens.editors.text.invalid-edit-type=Invalid edit type.
citizens.editors.text.invalid-index={0} is not a valid index! citizens.editors.text.invalid-index={0} is not a valid index!
citizens.editors.text.invalid-input=Invalid input. citizens.editors.text.invalid-input=Invalid input.
citizens.editors.text.invalid-page=Invalid page number. citizens.editors.text.invalid-page=Invalid page number.
citizens.editors.text.invalid-range=Invalid range.
citizens.editors.text.random-talker-set=[[Random talking]] set to [[{0}]]. citizens.editors.text.random-talker-set=[[Random talking]] set to [[{0}]].
citizens.editors.text.range-set=[[Range]] set to [[{0}]].
citizens.editors.text.realistic-looking-set=[[Realistic looking]] set to [[{0}]]. citizens.editors.text.realistic-looking-set=[[Realistic looking]] set to [[{0}]].
citizens.editors.text.remove-prompt=Enter the index of the entry you wish to remove or [[page]] to view more pages. citizens.editors.text.remove-prompt=Enter the index of the entry you wish to remove or [[page]] to view more pages.
citizens.editors.text.removed-entry=[[Removed]] entry at index [[{0}]]. citizens.editors.text.removed-entry=[[Removed]] entry at index [[{0}]].
citizens.editors.text.start-prompt=Type [[add]] to add an entry, [[edit]] to edit entries, [[remove]] to remove entries, [[close]] to toggle the NPC as a close talker, and [[random]] to toggle the NPC as a random talker. Type [[help]] to show this again. citizens.editors.text.start-prompt=Type [[add]] to add an entry, [[edit]] to edit entries, [[remove]] to remove entries, [[close]] to toggle the NPC as a close talker, [[item]] to set the item in hand pattern, [[range]] to set the talking range, and [[random]] to toggle the NPC as a random talker. Type [[help]] to show this again.
citizens.editors.text.talk-item-set=[[Talk item pattern]] set to [[{0}]].
citizens.editors.waypoints.linear.added-waypoint=[[Added]] a waypoint at ({0}) ([[{1}]], [[{2}]]) citizens.editors.waypoints.linear.added-waypoint=[[Added]] a waypoint at ({0}) ([[{1}]], [[{2}]])
citizens.editors.waypoints.linear.begin=<b>Entered the linear waypoint editor!<br> [[Left click]] to add a waypoint, [[right click]] to remove.<br> Type [[toggle path]] to toggle showing entities at waypoints, [[triggers]] to enter the trigger editor and [[clear]] to clear all waypoints. citizens.editors.waypoints.linear.begin=<b>Entered the linear waypoint editor!<br> [[Left click]] to add a waypoint, [[right click]] to remove.<br> Type [[toggle path]] to toggle showing entities at waypoints, [[triggers]] to enter the trigger editor and [[clear]] to clear all waypoints.
citizens.editors.waypoints.linear.edit-slot-set=Editing slot set to [[{0}]] ({1}). citizens.editors.waypoints.linear.edit-slot-set=Editing slot set to [[{0}]] ({1}).