Implement NPC SpeechController

This commit is contained in:
Jeremy Schroeder 2012-12-22 08:23:52 -05:00
parent c4cfd02b1a
commit 1baa5c0f01
6 changed files with 1034 additions and 871 deletions

View File

@ -8,6 +8,7 @@ import java.util.Iterator;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.CitizensPlugin;
import net.citizensnpcs.api.ai.speech.SpeechFactory;
import net.citizensnpcs.api.event.CitizensDisableEvent;
import net.citizensnpcs.api.event.CitizensEnableEvent;
import net.citizensnpcs.api.event.CitizensReloadEvent;
@ -36,6 +37,8 @@ import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.CitizensNPCRegistry;
import net.citizensnpcs.npc.CitizensTraitFactory;
import net.citizensnpcs.npc.NPCSelector;
import net.citizensnpcs.npc.ai.speech.Chat;
import net.citizensnpcs.npc.ai.speech.CitizensSpeechFactory;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Messaging;
import net.citizensnpcs.util.NMS;
@ -63,6 +66,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
private NPCDataStore saves;
private NPCSelector selector;
private CitizensTraitFactory traitFactory;
private CitizensSpeechFactory speechFactory;
private void despawnNPCs() {
Iterator<NPC> itr = npcRegistry.iterator();
@ -151,6 +155,11 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
return traitFactory;
}
@Override
public SpeechFactory getSpeechFactory() {
return speechFactory;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String cmdName, String[] args) {
String modifier = args.length > 0 ? args[0] : "";
@ -206,6 +215,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
npcRegistry = new CitizensNPCRegistry(saves);
traitFactory = new CitizensTraitFactory();
selector = new NPCSelector(this);
speechFactory = new CitizensSpeechFactory();
speechFactory.register(Chat.class, "chat");
getServer().getPluginManager().registerEvents(new EventListen(), this);
@ -348,4 +359,5 @@ public class Citizens extends JavaPlugin implements CitizensPlugin {
}
private static final String COMPATIBLE_MC_VERSION = "1.4";
}

View File

@ -43,7 +43,15 @@ public class Settings {
}
public enum Setting {
CHAT_PREFIX("npc.chat.prefix", "[<npc>]: "),
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),
CHAT_MAX_NUMBER_OF_TARGETS("npc.chat.options.max-number-of-targets-to-show", 3),
CHAT_MULTIPLE_TARGETS_FORMAT("npc.chat.options.multiple-targets-format", "<target>,|<target>|& <target>|& others"),
DATABASE_DRIVER("storage.database.driver", ""),
DATABASE_PASSWORD("storage.database.password", ""),
DATABASE_URL("storage.database.url", ""),

View File

@ -77,7 +77,7 @@ public class CitizensNPC extends AbstractNPC {
return entityController.getBukkitEntity();
}
@Deprecated
@Deprecated
public EntityLiving getHandle() {
return ((CraftLivingEntity) getBukkitEntity()).getHandle();
}

View File

@ -15,6 +15,7 @@ import net.citizensnpcs.api.trait.trait.Inventory;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
import net.citizensnpcs.api.trait.trait.Speech;
import net.citizensnpcs.trait.Age;
import net.citizensnpcs.trait.Anchors;
import net.citizensnpcs.trait.Behaviour;
@ -60,6 +61,7 @@ public class CitizensTraitFactory implements TraitFactory {
registerTrait(TraitInfo.create(NPCSkeletonType.class).withName("skeletontype"));
registerTrait(TraitInfo.create(SlimeSize.class).withName("slimesize"));
registerTrait(TraitInfo.create(Spawned.class).withName("spawned"));
registerTrait(TraitInfo.create(Speech.class).withName("speech"));
registerTrait(TraitInfo.create(Text.class).withName("text"));
registerTrait(TraitInfo.create(MobType.class).withName("type"));
registerTrait(TraitInfo.create(Waypoints.class).withName("waypoints"));

View File

@ -0,0 +1,90 @@
package net.citizensnpcs.npc.ai.speech;
import java.util.List;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
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.VocalChord;
import net.citizensnpcs.api.npc.NPC;
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());
// 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);
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);
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);
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
}
}
private void talkToBystanders(NPC npc, String text, Tongue tongue) {
// 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())
if (target.getEntity() == bystander) continue;
} else
// Found a nearby LivingEntity, make it Talkable and talkNear it
new TalkableEntity((LivingEntity) bystander).talkNear(tongue, text, this);
}
}
@Override
public String getName() {
return VOCAL_CHORD_NAME;
}
}

View File

@ -0,0 +1,51 @@
package net.citizensnpcs.npc.ai.speech;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import net.citizensnpcs.api.ai.speech.SpeechFactory;
import net.citizensnpcs.api.ai.speech.VocalChord;
public class CitizensSpeechFactory implements SpeechFactory {
Map<String, Class<? extends VocalChord>> registered = Collections.emptyMap();
@Override
public void register(Class<? extends VocalChord> clazz, String name) {
registered.put(name, clazz);
}
@Override
public String getVocalChordName(Class<? extends VocalChord> clazz) {
for (Entry<String, Class<? extends VocalChord>> vocalChord : registered.entrySet())
if (vocalChord.getValue() == clazz) return vocalChord.getKey();
return null;
}
@Override
public VocalChord getVocalChord(String name) {
if (registered.containsKey(name.toLowerCase()))
try {
return registered.get(name.toLowerCase()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
@Override
public VocalChord getVocalChord(Class<? extends VocalChord> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}