/**
* 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.config;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import pl.betoncraft.betonquest.BetonQuest;
import pl.betoncraft.betonquest.ConditionID;
import pl.betoncraft.betonquest.EventID;
import pl.betoncraft.betonquest.InstructionParseException;
import pl.betoncraft.betonquest.ItemID;
import pl.betoncraft.betonquest.Journal;
import pl.betoncraft.betonquest.ObjectNotFoundException;
import pl.betoncraft.betonquest.ObjectiveID;
import pl.betoncraft.betonquest.database.PlayerData;
import pl.betoncraft.betonquest.item.QuestItem;
import pl.betoncraft.betonquest.utils.Debug;
import pl.betoncraft.betonquest.utils.PlayerConverter;
/**
* Represents a quest canceler, which cancels quests for players.
*
* @author Jakub Sapalski
*/
public class QuestCanceler {
private String item;
private String[] tags, points, journal;
private ConditionID[] conditions;
private EventID[] events;
private ObjectiveID[] objectives;
private Location loc;
private HashMap<String, String> name = new HashMap<>();
private String packName;
private String cancelerName;
/**
* Creates a new canceler with given name.
*
* @param cancelerID
* ID of the canceler (package.name)
* @throws InstructionParseException
* when parsing the canceler fails for some reason
*/
public QuestCanceler(String cancelerID) throws InstructionParseException {
if (cancelerID == null)
throw new InstructionParseException("Name is null");
// get the instruction
String[] parts = cancelerID.split("\\.");
if (parts.length != 2)
throw new InstructionParseException("ID is incorrect");
packName = parts[0];
cancelerName = parts[1];
ConfigPackage pack = Config.getPackages().get(packName);
if (pack == null)
throw new InstructionParseException("Package does not exist");
String rawEvents = pack.getString("main.cancel." + cancelerName + ".events"),
rawConditions = pack.getString("main.cancel." + cancelerName + ".conditions"),
rawTags = pack.getString("main.cancel." + cancelerName + ".tags"),
rawObjectives = pack.getString("main.cancel." + cancelerName + ".objectives"),
rawPoints = pack.getString("main.cancel." + cancelerName + ".points"),
rawJournal = pack.getString("main.cancel." + cancelerName + ".journal"),
rawLoc = pack.getString("main.cancel." + cancelerName + ".loc");
// get the name
if (pack.getMain().getConfig().isConfigurationSection("cancel." + cancelerName + ".name")) {
for (String lang : pack.getMain().getConfig().getConfigurationSection("cancel." + cancelerName + ".name")
.getKeys(false)) {
name.put(lang, pack.getString("main.cancel." + cancelerName + ".name." + lang));
}
} else {
name.put(Config.getLanguage(), pack.getString("main.cancel." + cancelerName + ".name"));
}
// get the item
item = pack.getString("main.cancel." + cancelerName + ".item");
if (item == null) {
item = Config.getString(packName + ".items.cancel_button");
}
// parse it to get the data
if (rawEvents != null) {
String[] arr = rawEvents.split(",");
events = new EventID[arr.length];
for (int i = 0; i < arr.length; i++) {
try {
events[i] = new EventID(Config.getPackages().get(packName), arr[i]);
} catch (ObjectNotFoundException e) {
throw new InstructionParseException("Error while parsing quest canceler events: " + e.getMessage());
}
}
} else {
events = new EventID[0];
}
if (rawConditions != null) {
String[] arr = rawConditions.split(",");
conditions = new ConditionID[arr.length];
for (int i = 0; i < arr.length; i++) {
try {
conditions[i] = new ConditionID(Config.getPackages().get(packName), arr[i]);
} catch (ObjectNotFoundException e) {
throw new InstructionParseException("Error while parsing quest canceler conditions: " + e.getMessage());
}
}
} else {
conditions = new ConditionID[0];
}
if (rawObjectives != null) {
String[] arr = rawObjectives.split(",");
objectives = new ObjectiveID[arr.length];
for (int i = 0; i < arr.length; i++) {
try {
objectives[i] = new ObjectiveID(Config.getPackages().get(packName), arr[i]);
} catch (ObjectNotFoundException e) {
throw new InstructionParseException("Error while parsing quest canceler objectives: " + e.getMessage());
}
}
} else {
objectives = new ObjectiveID[0];
}
tags = (rawTags != null) ? rawTags.split(",") : null;
points = (rawPoints != null) ? rawPoints.split(",") : null;
journal = (rawJournal != null) ? rawJournal.split(",") : null;
String[] locParts = (rawLoc != null) ? rawLoc.split(";") : null;
// get location
if (locParts != null) {
if (locParts.length != 4 && locParts.length != 6) {
Debug.error("Wrong location format in quest canceler " + name);
return;
}
double x, y, z;
try {
x = Double.parseDouble(locParts[0]);
y = Double.parseDouble(locParts[1]);
z = Double.parseDouble(locParts[2]);
} catch (NumberFormatException e) {
Debug.error("Could not parse location in quest canceler " + name);
return;
}
World world = Bukkit.getWorld(locParts[3]);
if (world == null) {
Debug.error("The world doesn't exist in quest canceler " + name);
return;
}
float yaw = 0, pitch = 0;
if (locParts.length == 6) {
try {
yaw = Float.parseFloat(locParts[4]);
pitch = Float.parseFloat(locParts[5]);
} catch (NumberFormatException e) {
Debug.error("Could not parse yaw/pitch in quest canceler " + name + ", setting to 0");
yaw = 0;
pitch = 0;
}
}
loc = new Location(world, x, y, z, yaw, pitch);
}
}
/**
* Checks conditions of this canceler to decide if it should be shown to the
* player or not.
*
* @param playerID
* ID of the player
* @return true if all conditions are met, false otherwise
*/
public boolean show(String playerID) {
if (conditions == null)
return true;
for (ConditionID condition : conditions) {
if (!BetonQuest.condition(playerID, condition)) {
return false;
}
}
return true;
}
/**
* Cancels the quest for specified player.
*
* @param playerID
* ID of the player
*/
public void cancel(String playerID) {
Debug.info("Canceling the quest " + name + " for player " + PlayerConverter.getName(playerID));
PlayerData playerData = BetonQuest.getInstance().getPlayerData(playerID);
// remove tags, points, objectives and journals
if (tags != null) {
for (String tag : tags) {
Debug.info(" Removing tag " + tag);
if (!tag.contains(".")) {
playerData.removeTag(packName + "." + tag);
} else {
playerData.removeTag(tag);
}
}
}
if (points != null) {
for (String point : points) {
Debug.info(" Removing points " + point);
if (!point.contains(".")) {
playerData.removePointsCategory(packName + "." + point);
} else {
playerData.removePointsCategory(point);
}
}
}
if (objectives != null) {
for (ObjectiveID objectiveID : objectives) {
Debug.info(" Removing objective " + objectiveID);
BetonQuest.getInstance().getObjective(objectiveID).removePlayer(playerID);
playerData.removeRawObjective(objectiveID);
}
}
if (journal != null) {
Journal j = playerData.getJournal();
for (String entry : journal) {
Debug.info(" Removing entry " + entry);
if (entry.contains(".")) {
j.removePointer(entry);
} else {
j.removePointer(packName + "." + entry);
}
}
j.update();
}
// teleport player to the location
if (loc != null) {
Debug.info(" Teleporting to new location");
PlayerConverter.getPlayer(playerID).teleport(loc);
}
// fire all events
if (events != null) {
for (EventID event : events) {
BetonQuest.event(playerID, event);
}
}
// done
Debug.info("Quest removed!");
String questName = getName(playerID);
Config.sendMessage(playerID, "quest_canceled", new String[] { questName });
}
/**
* Returns a name of this quest canceler in the language of the player,
* default language, English or if none of above are specified, simply
* "Quest". In that case, it will also log an error to the console.
*
* @param playerID
* ID of the player
* @return the name of the quest canceler
*/
public String getName(String playerID) {
String questName = name.get(BetonQuest.getInstance().getPlayerData(playerID).getLanguage());
if (questName == null)
questName = name.get(Config.getLanguage());
if (questName == null)
questName = name.get("en");
if (questName == null) {
Debug.error("Default quest name not defined in canceler " + packName + "." + cancelerName);
questName = "Quest";
}
return questName.replace("_", " ").replace("&", "ยง");
}
public ItemStack getItem(String playerID) {
ItemStack stack = new ItemStack(Material.BONE);
if (item != null) {
try {
ItemID itemID = new ItemID(Config.getPackages().get(packName), item);
stack = new QuestItem(itemID).generate(1);
} catch (InstructionParseException | ObjectNotFoundException e) {
Debug.error("Could not load cancel button: " + e.getMessage());
}
}
ItemMeta meta = stack.getItemMeta();
meta.setDisplayName(getName(playerID));
stack.setItemMeta(meta);
return stack;
}
}