/** * BetonQuest - advanced quests for Bukkit * Copyright (C) 2016 Jakub "Co0sh" Sapalski * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pl.betoncraft.betonquest.conversation; import java.util.HashMap; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; import pl.betoncraft.betonquest.BetonQuest; import pl.betoncraft.betonquest.config.Config; import pl.betoncraft.betonquest.utils.PlayerConverter; /** * Base of all chat conversation outputs * * @author Jakub Sapalski */ public abstract class ChatConvIO implements ConversationIO, Listener { protected int i; // counts options protected HashMap<Integer, String> options; protected String npcText; protected String npcName; protected final Conversation conv; protected final String name; protected final Player player; protected final HashMap<String, ChatColor[]> colors; protected String answerFormat; protected String textFormat; public ChatConvIO(Conversation conv, String playerID) { this.options = new HashMap<>(); this.conv = conv; this.player = PlayerConverter.getPlayer(playerID); this.name = player.getName(); this.colors = ConversationColors.getColors(); StringBuilder string = new StringBuilder(); for (ChatColor color : colors.get("npc")) { string.append(color); } string.append("%npc%" + ChatColor.RESET + ": "); for (ChatColor color : colors.get("text")) { string.append(color); } textFormat = string.toString(); string = new StringBuilder(); for (ChatColor color : colors.get("player")) { string.append(color); } string.append(name + ChatColor.RESET + ": "); for (ChatColor color : colors.get("answer")) { string.append(color); } answerFormat = string.toString(); Bukkit.getPluginManager().registerEvents(this, BetonQuest.getInstance()); } @EventHandler public void onWalkAway(PlayerMoveEvent event) { // return if it's someone else if (!event.getPlayer().equals(player)) { return; } // if player passes max distance if (!event.getTo().getWorld().equals(conv.getLocation().getWorld()) || event.getTo() .distance(conv.getLocation()) > Integer.valueOf(Config.getString("config.max_npc_distance"))) { // we can stop the player or end conversation if (conv.isMovementBlock()) { moveBack(event); } else { conv.endConversation(); } } return; } /** * Moves the player back a few blocks in the conversation's center * direction. * * @param event * PlayerMoveEvent event, for extracting the necessary data */ private void moveBack(PlayerMoveEvent event) { // if the player is in other world (he teleported himself), teleport him // back to the center of the conversation if (!event.getTo().getWorld().equals(conv.getLocation().getWorld()) || event.getTo() .distance(conv.getLocation()) > Integer.valueOf(Config.getString("config.max_npc_distance")) * 2) { event.getPlayer().teleport(conv.getLocation()); return; } // if not, then calculate the vector float yaw = event.getTo().getYaw(); float pitch = event.getTo().getPitch(); Vector vector = new Vector(conv.getLocation().getX() - event.getTo().getX(), conv.getLocation().getY() - event.getTo().getY(), conv.getLocation().getZ() - event.getTo().getZ()); vector = vector.multiply(1 / vector.length()); // and teleport him back using this vector Location newLocation = event.getTo().clone(); newLocation.add(vector); newLocation.setPitch(pitch); newLocation.setYaw(yaw); event.getPlayer().teleport(newLocation); if (Config.getString("config.notify_pullback").equalsIgnoreCase("true")) { Config.sendMessage(PlayerConverter.getID(event.getPlayer()), "pullback"); } } @EventHandler(priority = EventPriority.LOWEST) public void onReply(AsyncPlayerChatEvent event) { if (event.isCancelled()) return; if (!event.getPlayer().equals(player)) return; String message = event.getMessage().trim(); for (int i : options.keySet()) { if (message.equals(Integer.toString(i))) { player.sendMessage(answerFormat + options.get(i)); conv.passPlayerAnswer(i); event.setCancelled(true); return; } } // redisplay the conversation after player's message so he can see it new BukkitRunnable() { @Override public void run() { display(); } }.runTask(BetonQuest.getInstance()); } @Override public void setNpcResponse(String npcName, String response) { this.npcName = npcName; this.npcText = response.replace('&', '§'); } @Override public void addPlayerOption(String option) { i++; options.put(i, option.replace('&', '§')); } @Override public void display() { if (npcText == null && options.isEmpty()) { end(); return; } player.sendMessage(textFormat.replace("%npc%", npcName) + npcText); } @Override public void clear() { i = 0; options.clear(); npcText = null; } @Override public void end() { HandlerList.unregisterAll(this); } }