diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java index e25013f0f..c9bd053d2 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/LinearWaypointProvider.java @@ -88,9 +88,9 @@ public class LinearWaypointProvider implements WaypointProvider { } private final class LinearWaypointEditor extends WaypointEditor { + Conversation conversation; boolean editing = true; int editingSlot = waypoints.size() - 1; - Conversation conversation; private final Player player; private boolean showPath; Map waypointMarkers = Maps.newHashMap(); diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTrigger.java b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTrigger.java new file mode 100644 index 000000000..cdc1f028a --- /dev/null +++ b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTrigger.java @@ -0,0 +1,52 @@ +package net.citizensnpcs.trait.waypoint.triggers; + +import java.util.Collection; +import java.util.List; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.persistence.Persist; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; + +public class ChatTrigger implements WaypointTrigger { + @Persist(required = true) + private List lines; + @Persist + private double radius = -1; + + public ChatTrigger() { + } + + public ChatTrigger(double radius, Collection chatLines) { + this.radius = radius; + lines = Lists.newArrayList(chatLines); + } + + @Override + public String description() { + return String.format("Chat Trigger [radius %d, %s]", radius, Joiner.on(", ").join(lines)); + } + + @Override + public void onWaypointReached(NPC npc, Location waypoint) { + if (radius < 0) { + for (Player player : npc.getBukkitEntity().getWorld().getPlayers()) { + for (String line : lines) + Messaging.send(player, line); + } + } else { + for (Entity entity : npc.getBukkitEntity().getNearbyEntities(radius, radius, radius)) { + if (!(entity instanceof Player)) + continue; + for (String line : lines) + Messaging.send((Player) entity, line); + } + } + } +} diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTriggerPrompt.java b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTriggerPrompt.java new file mode 100644 index 000000000..76566b127 --- /dev/null +++ b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/ChatTriggerPrompt.java @@ -0,0 +1,48 @@ +package net.citizensnpcs.trait.waypoint.triggers; + +import java.util.List; + +import net.citizensnpcs.util.Messages; +import net.citizensnpcs.util.Messaging; + +import org.bukkit.command.CommandSender; +import org.bukkit.conversations.ConversationContext; +import org.bukkit.conversations.Prompt; +import org.bukkit.conversations.StringPrompt; + +import com.google.common.collect.Lists; + +public class ChatTriggerPrompt extends StringPrompt implements WaypointTriggerPrompt { + private final List lines = Lists.newArrayList(); + private double radius = -1; + + @Override + public Prompt acceptInput(ConversationContext context, String input) { + if (input.equalsIgnoreCase("back")) + return (Prompt) context.getSessionData("previous"); + if (input.startsWith("radius")) { + try { + radius = Double.parseDouble(input.split(" ")[1]); + } catch (NumberFormatException e) { + Messaging.sendErrorTr((CommandSender) context.getForWhom(), + Messages.WAYPOINT_TRIGGER_CHAT_INVALID_RADIUS); + } catch (IndexOutOfBoundsException e) { + Messaging.sendErrorTr((CommandSender) context.getForWhom(), + Messages.WAYPOINT_TRIGGER_CHAT_NO_RADIUS); + } + return this; + } + if (input.equalsIgnoreCase("finish")) { + context.setSessionData(WaypointTriggerPrompt.CREATED_TRIGGER_KEY, new ChatTrigger(radius, lines)); + return (Prompt) context.getSessionData(WaypointTriggerPrompt.RETURN_PROMPT_KEY); + } + lines.add(input); + return this; + } + + @Override + public String getPromptText(ConversationContext context) { + Messaging.sendTr((CommandSender) context.getForWhom(), Messages.CHAT_TRIGGER_PROMPT); + return ""; + } +} diff --git a/src/main/java/net/citizensnpcs/trait/waypoint/triggers/WaypointTriggerRegistry.java b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/WaypointTriggerRegistry.java index 81dab1590..cc17e6c24 100644 --- a/src/main/java/net/citizensnpcs/trait/waypoint/triggers/WaypointTriggerRegistry.java +++ b/src/main/java/net/citizensnpcs/trait/waypoint/triggers/WaypointTriggerRegistry.java @@ -51,5 +51,6 @@ public class WaypointTriggerRegistry implements Persister { static { addTrigger("teleport", TeleportTrigger.class, TeleportTriggerPrompt.class); addTrigger("delay", DelayTrigger.class, DelayTriggerPrompt.class); + addTrigger("chat", ChatTrigger.class, ChatTriggerPrompt.class); } } diff --git a/src/main/java/net/citizensnpcs/util/Messages.java b/src/main/java/net/citizensnpcs/util/Messages.java index 081980099..d650c1aa4 100644 --- a/src/main/java/net/citizensnpcs/util/Messages.java +++ b/src/main/java/net/citizensnpcs/util/Messages.java @@ -18,6 +18,7 @@ public class Messages { public static final String BEHAVIOUR_HELP = "citizens.commands.npc.behaviour.help"; public static final String BEHAVIOURS_ADDED = "citizens.commands.npc.behaviour.added"; public static final String BEHAVIOURS_REMOVED = "citizens.commands.npc.behaviour.removed"; + public static final String CHAT_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.chat.prompt"; public static final String CITIZENS_DISABLED = "citizens.notifications.disabled"; public static final String CITIZENS_ENABLED = "citizens.notifications.enabled"; public static final String CITIZENS_IMPLEMENTATION_DISABLED = "citizens.changed-implementation"; @@ -188,6 +189,8 @@ public class Messages { public static final String WAYPOINT_TELEPORTING_DISABLED = "citizens.commands.waypoints.disableteleporting.disabled"; public static final String WAYPOINT_TRIGGER_ADD_PROMPT = "citizens.editors.waypoints.triggers.add.prompt"; public static final String WAYPOINT_TRIGGER_ADDED_SUCCESSFULLY = "citizens.editors.waypoints.triggers.add.added"; + public static final String WAYPOINT_TRIGGER_CHAT_INVALID_RADIUS = "citizens.editors.waypoints.triggers.chat.invalid-radius"; + public static final String WAYPOINT_TRIGGER_CHAT_NO_RADIUS = "citizens.editors.waypoints.triggers.chat.missing-radius"; public static final String WAYPOINT_TRIGGER_EDITOR_INACTIVE = "citizens.editors.waypoints.triggers.main.missing-waypoint"; public static final String WAYPOINT_TRIGGER_EDITOR_INVALID_TRIGGER = "citizens.editors.waypoints.triggers.add.invalid-trigger"; public static final String WAYPOINT_TRIGGER_EDITOR_PROMPT = "citizens.editors.waypoints.triggers.main.prompt"; diff --git a/src/main/java/net/citizensnpcs/util/PlayerAnimation.java b/src/main/java/net/citizensnpcs/util/PlayerAnimation.java new file mode 100644 index 000000000..90cb2ea1c --- /dev/null +++ b/src/main/java/net/citizensnpcs/util/PlayerAnimation.java @@ -0,0 +1,80 @@ +package net.citizensnpcs.util; + +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.Packet; +import net.minecraft.server.Packet17EntityLocationAction; +import net.minecraft.server.Packet18ArmAnimation; +import net.minecraft.server.Packet40EntityMetadata; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public enum PlayerAnimation { + HURT { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + Packet18ArmAnimation packet = new Packet18ArmAnimation(player, 2); + sendPacketNearby(packet, player, radius); + } + }, + SLEEP { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + Packet17EntityLocationAction packet = new Packet17EntityLocationAction(player, 0, + (int) player.locX, (int) player.locY, (int) player.locZ); + sendPacketNearby(packet, player, radius); + } + }, + SNEAK { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + player.getBukkitEntity().setSneaking(true); + sendPacketNearby(new Packet40EntityMetadata(player.id, player.getDataWatcher()), player, radius); + } + }, + STOP_SLEEPING { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + Packet18ArmAnimation packet = new Packet18ArmAnimation(player, 3); + sendPacketNearby(packet, player, radius); + } + }, + STOP_SNEAKING { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + player.getBukkitEntity().setSneaking(false); + sendPacketNearby(new Packet40EntityMetadata(player.id, player.getDataWatcher()), player, radius); + } + }, + SWING_ARM { + @Override + protected void playAnimation(EntityPlayer player, int radius) { + Packet18ArmAnimation packet = new Packet18ArmAnimation(player, 1); + sendPacketNearby(packet, player, radius); + } + }; + + public void play(Player player) { + playAnimation(((CraftPlayer) player).getHandle(), 64); + } + + protected void playAnimation(EntityPlayer player, int radius) { + throw new UnsupportedOperationException("unimplemented animation"); + } + + protected void sendPacketNearby(Packet packet, EntityPlayer player, int radius) { + radius *= radius; + World world = player.world.getWorld(); + Location location = player.getBukkitEntity().getLocation(); + for (Player dest : Bukkit.getServer().getOnlinePlayers()) { + if (dest == null || world != dest.getWorld()) + continue; + if (location.distanceSquared(dest.getLocation()) > radius) + continue; + ((CraftPlayer) dest).getHandle().netServerHandler.sendPacket(packet); + } + } +} diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 7b7262ade..3e40312f2 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -134,7 +134,10 @@ 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.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.waypoints.triggers.chat.prompt=Enter in chat lines to say.
Type in [[radius (radius)]] to set the block radius to broadcast the messages.
Type [[finish]] to finish the chat trigger or [[back]] to return to the previous prompt. citizens.editors.waypoints.triggers.remove.not-a-number=Index must be a number. +citizens.editors.waypoints.triggers.chat.missing-radius=No radius supplied. +citizens.editors.waypoints.triggers.chat.invalid-radius=The radius must be a number. citizens.editors.waypoints.triggers.remove.removed=Successfully removed trigger {0}. citizens.editors.waypoints.triggers.remove.index-out-of-range=Index must be in the range [[1-{0}]]. citizens.editors.waypoints.triggers.remove.prompt=Enter in the index of the trigger to delete or [[back]] to return to the edit prompt. Current triggers are: