diff --git a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java
index eb8d158af..ba1c4ad46 100644
--- a/src/main/java/net/citizensnpcs/command/command/NPCCommands.java
+++ b/src/main/java/net/citizensnpcs/command/command/NPCCommands.java
@@ -8,6 +8,7 @@ import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
+import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.MobType;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.trait.trait.Spawned;
@@ -70,6 +71,10 @@ public class NPCCommands {
public void age(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
Age trait = npc.getTrait(Age.class);
+ boolean toggleLock = args.hasFlag('l');
+ if (toggleLock)
+ Messaging.send(sender, "Age " + (trait.toggle() ? "locked" : "unlocked") + ".");
+
if (args.argsLength() > 1) {
int age = 0;
String ageStr = "an adult";
@@ -77,7 +82,7 @@ public class NPCCommands {
age = args.getInteger(1);
if (age < -24000 || age > 0)
throw new CommandException("Invalid age. Valid: adult, baby, number between -24000 and 0");
- ageStr = "age " + age;
+ ageStr = "age " + StringHelper.wrap(age);
} catch (NumberFormatException ex) {
if (args.getString(1).equalsIgnoreCase("baby")) {
age = -24000;
@@ -87,11 +92,9 @@ public class NPCCommands {
}
trait.setAge(age);
- Messaging.send(sender, StringHelper.wrap(npc.getName()) + " is now " + ageStr + ".");
- }
-
- if (args.hasFlag('l'))
- Messaging.send(sender, "Age " + (trait.toggle() ? "locked" : "unlocked") + ".");
+ Messaging.sendF(sender, StringHelper.wrap(npc.getName()) + " is now %s.", ageStr);
+ } else if (!toggleLock)
+ trait.describe(sender);
}
@Command(
@@ -104,19 +107,19 @@ public class NPCCommands {
public void behaviour(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
Iterable files = Splitter.on(',').split(args.getJoinedStrings(1, ','));
if (args.hasFlag('r')) {
- npc.getTrait(Behaviour.class).addScripts(files);
- sender.sendMessage(ChatColor.GREEN + "Behaviours added.");
- } else {
npc.getTrait(Behaviour.class).removeScripts(files);
sender.sendMessage(ChatColor.GREEN + "Behaviours removed.");
+ } else {
+ npc.getTrait(Behaviour.class).addScripts(files);
+ sender.sendMessage(ChatColor.GREEN + "Behaviours added.");
}
}
@Command(
aliases = { "npc" },
- usage = "controllable",
+ usage = "controllable|control",
desc = "Toggles whether the NPC can be ridden and controlled",
- modifiers = { "controllable" },
+ modifiers = { "controllable", "control" },
min = 1,
max = 1,
permission = "npc.controllable")
@@ -155,16 +158,15 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
- usage = "create [name] ((-b) --type (type) --char (char) --behaviour (behaviour))",
+ usage = "create [name] ((-b) --type (type) --trait ('trait1, trait2...') --b (behaviour))",
desc = "Create a new NPC",
flags = "b",
modifiers = { "create" },
min = 2,
- max = 5,
permission = "npc.create")
@Requirements
public void create(CommandContext args, final Player player, NPC npc) {
- String name = args.getString(1);
+ String name = StringHelper.parseColors(args.getJoinedStrings(1));
if (name.length() > 16) {
Messaging.sendError(player,
"NPC names cannot be longer than 16 characters. The name has been shortened.");
@@ -183,6 +185,7 @@ public class NPCCommands {
type = EntityType.PLAYER;
}
}
+
npc = npcRegistry.createNPC(type, name);
String msg = ChatColor.GREEN + "You created " + StringHelper.wrap(npc.getName())
+ " at your location";
@@ -197,8 +200,17 @@ public class NPCCommands {
msg += " as a baby";
}
}
+ if (args.hasValueFlag("trait")) {
+ Iterable parts = Splitter.on(",").trimResults().split(args.getFlag("trait"));
+ for (String tr : parts) {
+ Class extends Trait> clazz = CitizensAPI.getTraitFactory().getTraitClass(tr);
+ if (clazz != null)
+ npc.addTrait(clazz);
+ }
+ msg += " with the specified traits";
+ }
- if (args.hasValueFlag("behaviour")) {
+ if (args.hasValueFlag("b")) {
npc.getTrait(Behaviour.class).addScripts(Splitter.on(",").split(args.getFlag("behaviour")));
msg += " with the specified behaviours";
}
@@ -393,32 +405,28 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
- usage = "profession [profession]",
+ usage = "profession|prof [profession]",
desc = "Set a NPC's profession",
- modifiers = { "profession" },
+ modifiers = { "profession", "prof" },
min = 2,
max = 2,
permission = "npc.profession")
@Requirements(selected = true, ownership = true, types = { EntityType.VILLAGER })
public void profession(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
String profession = args.getString(1);
+ Profession parsed;
try {
- npc.getTrait(VillagerProfession.class)
- .setProfession(Profession.valueOf(profession.toUpperCase()));
- Messaging.send(sender, StringHelper.wrap(npc.getName()) + " is now the profession "
- + StringHelper.wrap(profession.toUpperCase()) + ".");
+ parsed = Profession.valueOf(profession.toUpperCase());
} catch (IllegalArgumentException ex) {
throw new CommandException("'" + profession + "' is not a valid profession.");
}
+ npc.getTrait(VillagerProfession.class).setProfession(parsed);
+ Messaging.send(sender,
+ StringHelper.wrap(npc.getName()) + " is now a " + StringHelper.wrap(profession) + ".");
}
- @Command(
- aliases = { "npc" },
- usage = "remove (all)",
- desc = "Remove a NPC",
- modifiers = { "remove" },
- min = 1,
- max = 2)
+ @Command(aliases = { "npc" }, usage = "remove|rem (all)", desc = "Remove a NPC", modifiers = { "remove",
+ "rem" }, min = 1, max = 2)
@Requirements
public void remove(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
if (args.argsLength() == 2) {
@@ -466,9 +474,9 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
- usage = "select [id]",
+ usage = "select|sel [id]",
desc = "Select a NPC with the given ID",
- modifiers = { "select" },
+ modifiers = { "select", "sel" },
min = 2,
max = 2,
permission = "npc.select")
@@ -547,7 +555,7 @@ public class NPCCommands {
}
@Command(aliases = { "npc" }, usage = "tphere", desc = "Teleport a NPC to your location", modifiers = {
- "tphere", "move" }, min = 1, max = 1, permission = "npc.tphere")
+ "tphere", "tph", "move" }, min = 1, max = 1, permission = "npc.tphere")
public void tphere(CommandContext args, Player player, NPC npc) {
// Spawn the NPC if it isn't spawned to prevent NPEs
if (!npc.isSpawned())
diff --git a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java
index f8b498661..fd9a92c7a 100644
--- a/src/main/java/net/citizensnpcs/npc/CitizensNPC.java
+++ b/src/main/java/net/citizensnpcs/npc/CitizensNPC.java
@@ -139,10 +139,10 @@ public abstract class CitizensNPC extends AbstractNPC {
getTrait(CurrentLocation.class).setLocation(loc);
getTrait(Spawned.class).setSpawned(true);
+ navigator.onSpawn();
// Modify NPC using traits after the entity has been created
for (Trait trait : traits.values())
trait.onSpawn();
- navigator.onSpawn();
return true;
}
diff --git a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java
index e16ccdf26..ae5d447fa 100644
--- a/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java
+++ b/src/main/java/net/citizensnpcs/npc/ai/CitizensNavigator.java
@@ -46,6 +46,8 @@ public class CitizensNavigator implements Navigator {
@Override
public float getSpeed() {
+ if (speed == -1)
+ throw new IllegalStateException("NPC has not been spawned");
return speed;
}
@@ -88,6 +90,8 @@ public class CitizensNavigator implements Navigator {
@Override
public void setSpeed(float speed) {
this.speed = speed;
+ if (isNavigating())
+ executing.setSpeed(this.speed);
}
@Override
diff --git a/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java
index 1eb98892d..acbdb1232 100644
--- a/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java
+++ b/src/main/java/net/citizensnpcs/npc/ai/MCNavigationStrategy.java
@@ -38,6 +38,11 @@ public class MCNavigationStrategy implements PathStrategy {
return TargetType.LOCATION;
}
+ @Override
+ public void setSpeed(float speed) {
+ navigation.a(speed);
+ }
+
@Override
public boolean update() {
return navigation.f();
diff --git a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java
index 7dda1b802..777a0868c 100644
--- a/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java
+++ b/src/main/java/net/citizensnpcs/npc/ai/MCTargetStrategy.java
@@ -84,6 +84,10 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
}
private static final int ATTACK_DELAY_TICKS = 20;
-
private static final double ATTACK_DISTANCE = 1.75 * 1.75;
+
+ @Override
+ public void setSpeed(float speed) {
+ navigation.a(speed);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/citizensnpcs/npc/ai/PathStrategy.java b/src/main/java/net/citizensnpcs/npc/ai/PathStrategy.java
index 43ea83e69..556b79832 100644
--- a/src/main/java/net/citizensnpcs/npc/ai/PathStrategy.java
+++ b/src/main/java/net/citizensnpcs/npc/ai/PathStrategy.java
@@ -10,4 +10,6 @@ public interface PathStrategy {
TargetType getTargetType();
boolean update();
+
+ void setSpeed(float speed);
}
\ No newline at end of file
diff --git a/src/main/java/net/citizensnpcs/trait/Age.java b/src/main/java/net/citizensnpcs/trait/Age.java
index 36930889b..53ddf62f4 100644
--- a/src/main/java/net/citizensnpcs/trait/Age.java
+++ b/src/main/java/net/citizensnpcs/trait/Age.java
@@ -3,7 +3,10 @@ package net.citizensnpcs.trait;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.DataKey;
+import net.citizensnpcs.util.Messaging;
+import net.citizensnpcs.util.StringHelper;
+import org.bukkit.command.CommandSender;
import org.bukkit.entity.Ageable;
public class Age extends Trait implements Toggleable {
@@ -64,4 +67,9 @@ public class Age extends Trait implements Toggleable {
public String toString() {
return "Age{age=" + age + ",locked=" + locked + "}";
}
+
+ public void describe(CommandSender sender) {
+ Messaging.sendF(sender, "%s's age is %s and %s locked.", StringHelper.wrap(npc.getName()),
+ StringHelper.wrap(age), StringHelper.wrap(locked ? "is" : "isn't"));
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/citizensnpcs/trait/Controllable.java b/src/main/java/net/citizensnpcs/trait/Controllable.java
index 3de66e324..dd7ea7cd6 100644
--- a/src/main/java/net/citizensnpcs/trait/Controllable.java
+++ b/src/main/java/net/citizensnpcs/trait/Controllable.java
@@ -72,6 +72,7 @@ public class Controllable extends Trait implements Toggleable {
boolean onGround = handle.onGround;
handle.motX += handle.passenger.motX * (onGround ? GROUND_SPEED : AIR_SPEED);
handle.motZ += handle.passenger.motZ * (onGround ? GROUND_SPEED : AIR_SPEED);
+ handle.e(npc.getNavigator().getSpeed());
}
@Override
diff --git a/src/main/java/net/citizensnpcs/trait/LookClose.java b/src/main/java/net/citizensnpcs/trait/LookClose.java
index 835a92043..af0fd650e 100644
--- a/src/main/java/net/citizensnpcs/trait/LookClose.java
+++ b/src/main/java/net/citizensnpcs/trait/LookClose.java
@@ -40,7 +40,7 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
}
private void findNewTarget() {
- List nearby = npc.getBukkitEntity().getNearbyEntities(range / 2, range, range / 2);
+ List nearby = npc.getBukkitEntity().getNearbyEntities(range, range, range);
final Location npcLocation = npc.getBukkitEntity().getLocation();
Collections.sort(nearby, new Comparator() {
@Override
diff --git a/src/main/java/net/citizensnpcs/util/StringHelper.java b/src/main/java/net/citizensnpcs/util/StringHelper.java
index 8ffe3c014..fa87062bc 100644
--- a/src/main/java/net/citizensnpcs/util/StringHelper.java
+++ b/src/main/java/net/citizensnpcs/util/StringHelper.java
@@ -64,6 +64,7 @@ public class StringHelper {
for (ChatColor color : ChatColor.values()) {
parsed = parsed.replace("<" + color.getChar() + ">", color.toString());
}
+ parsed = ChatColor.translateAlternateColorCodes('&', parsed);
return parsed;
}