diff --git a/api/pom.xml b/api/pom.xml index 57e4a5fd4..74cc357a8 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,10 +1,11 @@ + 4.0.0 me.blackvein.quests quests-parent - 4.1.3 + 4.2.0 quests-api @@ -166,31 +167,6 @@ clean package install ${basedir}/src/main/java - - - . - ${basedir}/src/main/resources/ - true - - lang/**/*.* - actions.yml - conditions.yml - config.yml - plugin.yml - quests.yml - strings.yml - - - - . - ${basedir}/ - false - - README.md - - - - org.apache.maven.plugins diff --git a/api/src/main/java/me/blackvein/quests/CustomObjective.java b/api/src/main/java/me/blackvein/quests/CustomObjective.java index 86b9203f2..d37c1d8c6 100644 --- a/api/src/main/java/me/blackvein/quests/CustomObjective.java +++ b/api/src/main/java/me/blackvein/quests/CustomObjective.java @@ -12,85 +12,34 @@ package me.blackvein.quests; -import me.blackvein.quests.enums.ObjectiveType; -import me.blackvein.quests.events.quester.QuesterPostUpdateObjectiveEvent; -import me.blackvein.quests.events.quester.QuesterPreUpdateObjectiveEvent; -import org.bukkit.Material; import org.bukkit.entity.Player; -import org.bukkit.event.Listener; -import org.bukkit.inventory.ItemStack; -import java.io.File; -import java.util.AbstractMap; -import java.util.HashMap; import java.util.LinkedList; import java.util.Map; -import java.util.Map.Entry; -public abstract class CustomObjective implements Listener { +public interface CustomObjective { - private final Quests plugin = Quests.getPlugin(Quests.class); - private String name = null; - private String author = null; - private String display = "Progress: %count%"; - private Entry item = new AbstractMap.SimpleEntry<>("BOOK", (short) 0); - private final LinkedList> data = new LinkedList<>(); - private final Map descriptions = new HashMap<>(); - private String countPrompt = "Enter number"; - private boolean showCount = true; - private int count = 1; + String getModuleName(); - public String getModuleName() { - return new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath()).getName() - .replace(".jar", ""); - } + Map.Entry getModuleItem(); - public Entry getModuleItem() { - return new AbstractMap.SimpleEntry<>("IRON_INGOT", (short) 0); - } + String getName(); - public String getName() { - return name; - } + void setName(final String name); - public void setName(final String name) { - this.name = name; - } + String getAuthor(); - public String getAuthor() { - return author; - } + void setAuthor(final String author); - public void setAuthor(final String author) { - this.author = author; - } + String getDisplay(); - public String getDisplay() { - return display; - } + void setDisplay(final String display); - public void setDisplay(final String display) { - this.display = display; - } + Map.Entry getItem(); - public Entry getItem() { - return item; - } + void setItem(final String type, final short durability); - /** - * @deprecated Use {@link #setItem(String, short)} - */ - public void addItem(final String type, final short durability) { - setItem(type, durability); - } - - public void setItem(final String type, final short durability) { - this.item = new AbstractMap.SimpleEntry<>(type, durability); - } - - public LinkedList> getData() { - return data; - } + LinkedList> getData(); /** * Add a new prompt

@@ -101,128 +50,39 @@ public abstract class CustomObjective implements Listener { * @param description Description of expected input * @param defaultValue Value to be used if input is not received */ - public void addStringPrompt(final String title, final String description, final Object defaultValue) { - final Entry prompt = new AbstractMap.SimpleEntry<>(title, defaultValue); - data.add(prompt); - descriptions.put(title, description); - } + void addStringPrompt(final String title, final String description, final Object defaultValue); - public Map getDescriptions() { - return descriptions; - } + Map getDescriptions(); - public int getCount() { - return count; - } + int getCount(); - public void setCount(final int count) { - this.count = count; - } + void setCount(final int count); - public String getCountPrompt() { - return countPrompt; - } + String getCountPrompt(); - public void setCountPrompt(final String countPrompt) { - this.countPrompt = countPrompt; - } + void setCountPrompt(final String countPrompt); /** * Check whether to let user set required amount for objective */ - public boolean canShowCount() { - return showCount; - } + boolean canShowCount(); /** * Set whether to let user set required amount for objective * * @param showCount Whether to show the count */ - public void setShowCount(final boolean showCount) { - this.showCount = showCount; - } - - public Map getDataForPlayer(final Player player, final CustomObjective customObj, final Quest quest) { - final Quester quester = plugin.getQuester(player.getUniqueId()); - if (quester != null) { - final Stage currentStage = quester.getCurrentStage(quest); - if (currentStage == null) { - return null; - } - CustomObjective found = null; - for (final me.blackvein.quests.CustomObjective co : currentStage.customObjectives) { - if (co.getName().equals(customObj.getName())) { - found = co; - break; - } - } - if (found != null) { - final Map m = new HashMap<>(); - for (final Entry dataMap : found.getData()) { - for (final Entry e : currentStage.customObjectiveData) { - if (e.getKey().equals(dataMap.getKey())) { - m.put(e.getKey(), e.getValue()); - } - } - } - if (!m.isEmpty()) { - return m; - } - } - } - return null; - } + void setShowCount(final boolean showCount); - public void incrementObjective(final Player player, final CustomObjective obj, final int count, final Quest quest) { - final Quester quester = plugin.getQuester(player.getUniqueId()); - if (quester != null) { - if (quester.hasCustomObjective(quest, obj.getName())) { - int index = -1; - final LinkedList customObjCounts = quester.getQuestData(quest).customObjectiveCounts; - for (final CustomObjective co : quester.getCurrentStage(quest).customObjectives) { - index++; - if (co.getName().equals(this.getName())) { - if (index >= customObjCounts.size()) { - plugin.getLogger().severe("Index was larger than count for " + obj.getName() + " by " - + obj.getAuthor()); - continue; - } - final int old = customObjCounts.get(index); - plugin.getQuester(player.getUniqueId()).getQuestData(quest).customObjectiveCounts - .set(index, old + count); - break; - } - } - if (index > -1) { - final int progress = customObjCounts.get(index); - final int goal = quester.getCurrentStage(quest).customObjectiveCounts.get(index); - - final ObjectiveType type = ObjectiveType.CUSTOM; - final QuesterPreUpdateObjectiveEvent preEvent - = new QuesterPreUpdateObjectiveEvent(quester, quest, new Objective(type, progress, goal)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - if (progress >= goal) { - quester.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, goal)), null, null, null, null, null, null, obj); - - // Multiplayer - final int finalIndex = index; - quester.dispatchMultiplayerObjectives(quest, quester.getCurrentStage(quest), (final Quester q) -> { - final int old = q.getQuestData(quest).customObjectiveCounts.get(finalIndex); - q.getQuestData(quest).customObjectiveCounts.set(finalIndex, old + count); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, goal)), null, null, null, null, null, null, obj); - return null; - }); - } - - final QuesterPostUpdateObjectiveEvent postEvent - = new QuesterPostUpdateObjectiveEvent(quester, quest, new Objective(type, progress, goal)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - } - } + /** + * Get custom objective data for applicable player + * + * @param player Player attempting this objective + * @param customObj The objective being attempted + * @param quest Current me.blackvein.quests.Quest which includes this objective + * @return data + */ + Map getDataForPlayer(final Player player, final CustomObjective customObj, final Quest quest); + + void incrementObjective(final Player player, final CustomObjective obj, final int count, final Quest quest); } diff --git a/api/src/main/java/me/blackvein/quests/Objective.java b/api/src/main/java/me/blackvein/quests/Objective.java index 62c2af5c5..87faa0bf2 100644 --- a/api/src/main/java/me/blackvein/quests/Objective.java +++ b/api/src/main/java/me/blackvein/quests/Objective.java @@ -1,62 +1,4 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package me.blackvein.quests; -import org.bukkit.inventory.ItemStack; - -import me.blackvein.quests.enums.ObjectiveType; - -public class Objective { - private final ObjectiveType type; - private final int progress; - private final int goal; - private final ItemStack progressStack; - private final ItemStack goalStack; - - - public Objective(final ObjectiveType type, final int progress, final int goal) { - this.type = type; - this.progress = progress; - this.goal = goal; - this.progressStack = null; - this.goalStack = null; - } - - public Objective(final ObjectiveType type, final ItemStack progress, final ItemStack goal) { - this.type = type; - this.progress = progress.getAmount(); - this.goal = goal.getAmount(); - this.progressStack = progress; - this.goalStack = goal; - } - - public ObjectiveType getType() { - return type; - } - - public int getProgress() { - return progress; - } - - public int getGoal() { - return goal; - } - - public ItemStack getItemProgress() { - return progressStack; - } - - public ItemStack getItemGoal() { - return goalStack; - } +public interface Objective { } diff --git a/api/src/main/java/me/blackvein/quests/Options.java b/api/src/main/java/me/blackvein/quests/Options.java index dfc3f0082..9a774ed88 100644 --- a/api/src/main/java/me/blackvein/quests/Options.java +++ b/api/src/main/java/me/blackvein/quests/Options.java @@ -1,97 +1,4 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package me.blackvein.quests; -public class Options { - private boolean allowCommands = true; - private boolean allowQuitting = true; - private boolean ignoreSilkTouch = true; - private String externalPartyPlugin = null; - private boolean usePartiesPlugin = true; - private boolean handleOfflinePlayers = false; - private double shareDistance = 0.0D; - private int shareProgressLevel = 1; - private boolean shareSameQuestOnly = true; - - public boolean canAllowCommands() { - return allowCommands; - } - - public void setAllowCommands(final boolean allowCommands) { - this.allowCommands = allowCommands; - } - - public boolean canAllowQuitting() { - return allowQuitting; - } - - public void setAllowQuitting(final boolean allowQuitting) { - this.allowQuitting = allowQuitting; - } - - public boolean canIgnoreSilkTouch() { - return ignoreSilkTouch; - } - - public void setIgnoreSilkTouch(final boolean ignoreSilkTouch) { - this.ignoreSilkTouch = ignoreSilkTouch; - } - - public String getExternalPartyPlugin() { - return externalPartyPlugin; - } - - public void setExternalPartyPlugin(final String externalPartyPlugin) { - this.externalPartyPlugin = externalPartyPlugin; - } - - public boolean canUsePartiesPlugin() { - return usePartiesPlugin; - } - - public void setUsePartiesPlugin(final boolean usePartiesPlugin) { - this.usePartiesPlugin = usePartiesPlugin; - } - - public int getShareProgressLevel() { - return shareProgressLevel; - } - - public void setShareProgressLevel(final int shareProgressLevel) { - this.shareProgressLevel = shareProgressLevel; - } - - public boolean canShareSameQuestOnly() { - return shareSameQuestOnly; - } - - public void setShareSameQuestOnly(final boolean shareSameQuestOnly) { - this.shareSameQuestOnly = shareSameQuestOnly; - } - - public double getShareDistance() { - return shareDistance; - } - - public void setShareDistance(final double shareDistance) { - this.shareDistance = shareDistance; - } - - public boolean canHandleOfflinePlayers() { - return handleOfflinePlayers; - } - - public void setHandleOfflinePlayers(final boolean handleOfflinePlayers) { - this.handleOfflinePlayers = handleOfflinePlayers; - } +public interface Options { } diff --git a/api/src/main/java/me/blackvein/quests/Planner.java b/api/src/main/java/me/blackvein/quests/Planner.java index 2af07c168..a9730b490 100644 --- a/api/src/main/java/me/blackvein/quests/Planner.java +++ b/api/src/main/java/me/blackvein/quests/Planner.java @@ -1,91 +1,4 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package me.blackvein.quests; -import java.util.Calendar; -import java.util.TimeZone; - -public class Planner { - public String start = null; - public String end = null; - public long repeat = -1; - public long cooldown = -1; - public boolean override = false; - - public String getStart() { - return start; - } - public long getStartInMillis() { - if (start == null) { - return -1; - } - final Calendar cal = Calendar.getInstance(); - final String[] s = start.split(":"); - cal.set(Integer.parseInt(s[2]), Integer.parseInt(s[1]), Integer.parseInt(s[0]), - Integer.parseInt(s[3]), Integer.parseInt(s[4]), Integer.parseInt(s[5])); - final TimeZone tz = TimeZone.getTimeZone(s[6]); - cal.setTimeZone(tz); - return cal.getTimeInMillis(); - } - public boolean hasStart() { - return start != null; - } - public void setStart(final String start) { - this.start = start; - } - public String getEnd() { - return end; - } - public long getEndInMillis() { - if (end == null) { - return -1; - } - final Calendar cal = Calendar.getInstance(); - final String[] s = end.split(":"); - cal.set(Integer.parseInt(s[2]), Integer.parseInt(s[1]), Integer.parseInt(s[0]), - Integer.parseInt(s[3]), Integer.parseInt(s[4]), Integer.parseInt(s[5])); - final TimeZone tz = TimeZone.getTimeZone(s[6]); - cal.setTimeZone(tz); - return cal.getTimeInMillis(); - } - public boolean hasEnd() { - return end != null; - } - public void setEnd(final String end) { - this.end = end; - } - public long getRepeat() { - return repeat; - } - public boolean hasRepeat() { - return repeat != -1; - } - public void setRepeat(final long repeat) { - this.repeat = repeat; - } - public long getCooldown() { - return cooldown; - } - public boolean hasCooldown() { - return cooldown != -1; - } - public void setCooldown(final long cooldown) { - this.cooldown = cooldown; - } - public boolean getOverride() { - return override; - } - public void setOverride(final boolean override) { - this.override = override; - } +public interface Planner { } diff --git a/api/src/main/java/me/blackvein/quests/Quest.java b/api/src/main/java/me/blackvein/quests/Quest.java index 5be667d8e..5df3e7990 100644 --- a/api/src/main/java/me/blackvein/quests/Quest.java +++ b/api/src/main/java/me/blackvein/quests/Quest.java @@ -1,1144 +1,56 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package me.blackvein.quests; -import com.alessiodp.parties.api.interfaces.Party; -import com.alessiodp.parties.api.interfaces.PartyPlayer; -import com.codisimus.plugins.phatloots.PhatLootsAPI; -import com.codisimus.plugins.phatloots.loot.CommandLoot; -import com.codisimus.plugins.phatloots.loot.LootBundle; -import com.gmail.nossr50.datatypes.skills.SkillType; -import com.gmail.nossr50.util.player.UserManager; -import com.herocraftonline.heroes.characters.Hero; import me.blackvein.quests.actions.Action; -import me.blackvein.quests.conditions.Condition; -import me.blackvein.quests.events.quest.QuestUpdateCompassEvent; -import me.blackvein.quests.events.quester.QuesterPostChangeStageEvent; -import me.blackvein.quests.events.quester.QuesterPostCompleteQuestEvent; -import me.blackvein.quests.events.quester.QuesterPostFailQuestEvent; -import me.blackvein.quests.events.quester.QuesterPreChangeStageEvent; -import me.blackvein.quests.events.quester.QuesterPreCompleteQuestEvent; -import me.blackvein.quests.events.quester.QuesterPreFailQuestEvent; -import me.blackvein.quests.util.ConfigUtil; -import me.blackvein.quests.util.InventoryUtil; -import me.blackvein.quests.util.ItemUtil; -import me.blackvein.quests.util.Lang; -import me.blackvein.quests.util.MiscUtil; -import me.blackvein.quests.util.RomanNumeral; -import me.clip.placeholderapi.PlaceholderAPI; -import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.DyeColor; import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.entity.Sheep; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CompletableFuture; -public class Quest implements Comparable { +public interface Quest { + public String getId(); - protected Quests plugin; - protected String id; - private String name; - protected String description; - protected String finished; - protected ItemStack guiDisplay = null; - private final LinkedList orderedStages = new LinkedList<>(); - protected NPC npcStart; - protected Location blockStart; - protected String regionStart = null; - protected Action initialAction; - private final Requirements requirements = new Requirements(); - private final Planner planner = new Planner(); - private final Rewards rewards = new Rewards(); - private final Options options = new Options(); + public String getName(); - @Override - public int compareTo(final Quest quest) { - return id.compareTo(quest.getId()); - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public void setName(final String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(final String description) { - this.description = description; - } - - public String getFinished() { - return finished; - } - - public void setFinished(final String finished) { - this.finished = finished; - } - - public String getRegionStart() { - return regionStart; - } - - public void setRegionStart(final String regionStart) { - this.regionStart = regionStart; - } - - public ItemStack getGUIDisplay() { - return guiDisplay; - } - - public void setGUIDisplay(final ItemStack guiDisplay) { - this.guiDisplay = guiDisplay; - } - - public Stage getStage(final int index) { - try { - return orderedStages.get(index); - } catch (final Exception e) { - return null; - } - } - - public LinkedList getStages() { - return orderedStages; - } - - public NPC getNpcStart() { - return npcStart; - } - - public void setNpcStart(final NPC npcStart) { - this.npcStart = npcStart; - } - - public Location getBlockStart() { - return blockStart; - } - - public void setBlockStart(final Location blockStart) { - this.blockStart = blockStart; - } - - public Action getInitialAction() { - return initialAction; - } - - public void setInitialAction(final Action initialAction) { - this.initialAction = initialAction; - } - - public Requirements getRequirements() { - return requirements; - } - - public Planner getPlanner() { - return planner; - } - - public Rewards getRewards() { - return rewards; - } - - public Options getOptions() { - return options; - } + public void setName(final String name); - /** - * Force player to proceed to the next ordered stage - * - * @param quester Player to force - * @param allowSharedProgress Whether to distribute progress to fellow questers - */ - public void nextStage(final Quester quester, final boolean allowSharedProgress) { - final Stage currentStage = quester.getCurrentStage(this); - if (currentStage == null) { - plugin.getLogger().severe("Current stage was null for quester " + quester.getPlayer().getUniqueId()); - return; - } - final String stageCompleteMessage = currentStage.completeMessage; - if (stageCompleteMessage != null) { - if (quester.getOfflinePlayer().isOnline()) { - quester.getPlayer().sendMessage(ConfigUtil.parseStringWithPossibleLineBreaks(stageCompleteMessage, - this, quester.getPlayer())); - } - } - if (quester.getPlayer().hasPermission("quests.compass")) { - quester.resetCompass(); - quester.findCompassTarget(); - } - if (currentStage.delay < 0) { - if (currentStage.finishAction != null) { - currentStage.finishAction.fire(quester, this); - } - if (quester.currentQuests.get(this) == (orderedStages.size() - 1)) { - if (currentStage.script != null) { - plugin.getDenizenTrigger().runDenizenScript(currentStage.script, quester); - } - completeQuest(quester); - } else { - setStage(quester, quester.currentQuests.get(this) + 1); - } - if (quester.getQuestData(this) != null) { - quester.getQuestData(this).setDelayStartTime(0); - quester.getQuestData(this).setDelayTimeLeft(-1); - } - - // Multiplayer - if (allowSharedProgress && options.getShareProgressLevel() == 3) { - final List mq = quester.getMultiplayerQuesters(this); - for (final Quester qq : mq) { - if (currentStage.equals(qq.getCurrentStage(this))) { - nextStage(qq, true); - } - } - } - } else { - quester.startStageTimer(this); - } - quester.updateJournal(); - } + public String getDescription(); - /** - * Force player to proceed to the specified stage - * - * @param quester Player to force - * @param stage Stage number to specify - * @throws IndexOutOfBoundsException if stage does not exist - */ - public void setStage(final Quester quester, final int stage) throws IndexOutOfBoundsException { - final OfflinePlayer player = quester.getOfflinePlayer(); - if (orderedStages.size() - 1 < stage) { - final String msg = "Tried to set invalid stage number of " + stage + " for quest " + getName() + " on " - + player.getName(); - throw new IndexOutOfBoundsException(msg); - } - final Stage currentStage = quester.getCurrentStage(this); - final Stage nextStage = getStage(stage); - if (player.isOnline()) { - final QuesterPreChangeStageEvent preEvent = new QuesterPreChangeStageEvent(quester, this, currentStage, nextStage); - plugin.getServer().getPluginManager().callEvent(preEvent); - if (preEvent.isCancelled()) { - return; - } - } - quester.hardQuit(this); - quester.hardStagePut(this, stage); - quester.addEmptiesFor(this, stage); - if (currentStage.script != null) { - plugin.getDenizenTrigger().runDenizenScript(currentStage.script, quester); - } - if (nextStage.startAction != null) { - nextStage.startAction.fire(quester, this); - } - updateCompass(quester, nextStage); - if (player.isOnline()) { - final Player p = quester.getPlayer(); - final String title = Lang.get(p, "objectives").replace("", name); - quester.sendMessage(ChatColor.GOLD + title); - plugin.showObjectives(this, quester, false); - final String stageStartMessage = quester.getCurrentStage(this).startMessage; - if (stageStartMessage != null) { - p.sendMessage(ConfigUtil.parseStringWithPossibleLineBreaks(stageStartMessage, this, p)); - } - final Condition c = nextStage.getCondition(); - if (c != null && nextStage.getObjectiveOverrides().isEmpty()) { - p.sendMessage(ChatColor.LIGHT_PURPLE + Lang.get("stageEditorConditions")); - if (!c.getEntitiesWhileRiding().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorRideEntity")); - for (final String e : c.getEntitiesWhileRiding()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(e); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getNpcsWhileRiding().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorRideNPC")); - for (final int i : c.getNpcsWhileRiding()) { - if (plugin.getDependencies().getCitizens() != null) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(CitizensAPI.getNPCRegistry() - .getById(i).getName()); - } else { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(i); - } - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getPermissions().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorPermissions")); - for (final String e : c.getPermissions()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(e); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getItemsWhileHoldingMainHand().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorItemsInMainHand")); - for (final ItemStack is : c.getItemsWhileHoldingMainHand()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(ItemUtil.getPrettyItemName(is - .getType().name())); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getWorldsWhileStayingWithin().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorStayWithinWorld")); - for (final String w : c.getWorldsWhileStayingWithin()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(w); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getBiomesWhileStayingWithin().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorStayWithinBiome")); - for (final String b : c.getBiomesWhileStayingWithin()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(MiscUtil - .snakeCaseToUpperCamelCase(b)); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getRegionsWhileStayingWithin().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorStayWithinRegion")); - for (final String r : c.getRegionsWhileStayingWithin()) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(r); - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } else if (!c.getPlaceholdersCheckIdentifier().isEmpty()) { - final StringBuilder msg = new StringBuilder("- " + Lang.get("conditionEditorCheckPlaceholder")); - int index = 0; - for (final String r : c.getPlaceholdersCheckIdentifier()) { - if (c.getPlaceholdersCheckValue().size() > index) { - msg.append(ChatColor.AQUA).append("\n \u2515 ").append(r).append(ChatColor.GRAY) - .append(" = ").append(ChatColor.AQUA).append(c.getPlaceholdersCheckValue() - .get(index)); - } - index++; - } - p.sendMessage(ChatColor.YELLOW + msg.toString()); - } - } - } - quester.updateJournal(); - if (player.isOnline()) { - final QuesterPostChangeStageEvent postEvent = new QuesterPostChangeStageEvent(quester, this, currentStage, nextStage); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } + public void setDescription(final String description); - /** - * Set location-objective target for compass.

- * - * Method may be called as often as needed. - * - * @param quester The online quester to have their compass updated - * @param stage The stage to process for targets - * @return true if an attempt was made successfully - */ - public boolean updateCompass(final Quester quester, final Stage stage) { - if (quester == null) { - return false; - } - if (stage == null) { - return false; - } - if (!quester.getOfflinePlayer().isOnline()) { - return false; - } - if (!quester.getPlayer().hasPermission("quests.compass")) { - return false; - } - final Quest quest = this; - Bukkit.getScheduler().runTask(plugin, () -> { - Location targetLocation = null; - if (stage.citizensToInteract != null && stage.citizensToInteract.size() > 0) { - targetLocation = plugin.getDependencies().getNPCLocation(stage.citizensToInteract.getFirst()); - } else if (stage.citizensToKill != null && stage.citizensToKill.size() > 0) { - targetLocation = plugin.getDependencies().getNPCLocation(stage.citizensToKill.getFirst()); - } else if (stage.locationsToReach != null && stage.locationsToReach.size() > 0) { - targetLocation = stage.locationsToReach.getFirst(); - } else if (stage.itemDeliveryTargets != null && stage.itemDeliveryTargets.size() > 0) { - final NPC npc = plugin.getDependencies().getCitizens().getNPCRegistry().getById(stage.itemDeliveryTargets - .getFirst()); - targetLocation = npc.getStoredLocation(); - } else if (stage.playersToKill != null && stage.playersToKill > 0) { - final Location source = quester.getPlayer().getLocation(); - Location nearest = null; - double old_distance = 30000000; - if (source.getWorld() == null) { - return; - } - for (final Player p : source.getWorld().getPlayers()) { - if (p.getUniqueId().equals(quester.getUUID())) { - continue; - } - final double new_distance = p.getLocation().distanceSquared(source); - if (new_distance < old_distance) { - nearest = p.getLocation(); - old_distance = new_distance; - } - } - if (nearest != null) { - targetLocation = nearest; - } - } else if (stage.mobsToKill != null && stage.mobsToKill.size() > 0) { - final Location source = quester.getPlayer().getLocation(); - Location nearest = null; - double old_distance = 30000000; - final EntityType et = stage.mobsToKill.getFirst(); - if (source.getWorld() == null) { - return; - } - for (final Entity e : source.getWorld().getEntities()) { - if (!e.getType().equals(et)) { - continue; - } - final double new_distance = e.getLocation().distanceSquared(source); - if (new_distance < old_distance) { - nearest = e.getLocation(); - old_distance = new_distance; - } - } - if (nearest != null) { - targetLocation = nearest; - } - } else if (stage.mobsToTame != null && stage.mobsToTame.size() > 0) { - final Location source = quester.getPlayer().getLocation(); - Location nearest = null; - double old_distance = 30000000; - final EntityType et = stage.mobsToTame.getFirst(); - if (source.getWorld() == null) { - return; - } - for (final Entity e : source.getWorld().getEntities()) { - if (!e.getType().equals(et)) { - continue; - } - final double new_distance = e.getLocation().distanceSquared(source); - if (new_distance < old_distance) { - nearest = e.getLocation(); - old_distance = new_distance; - } - } - if (nearest != null) { - targetLocation = nearest; - } - } else if (stage.sheepToShear != null && stage.sheepToShear.size() > 0) { - final Location source = quester.getPlayer().getLocation(); - Location nearest = null; - double old_distance = 30000000; - final DyeColor dc = stage.sheepToShear.getFirst(); - if (source.getWorld() == null) { - return; - } - for (final Entity e : source.getWorld().getEntities()) { - if (!e.getType().equals(EntityType.SHEEP)) { - continue; - } - final Sheep s = (Sheep)e; - if (s.getColor()!= null && s.getColor().equals(dc)) { - continue; - } - final double new_distance = e.getLocation().distanceSquared(source); - if (new_distance < old_distance) { - nearest = e.getLocation(); - old_distance = new_distance; - } - } - if (nearest != null) { - targetLocation = nearest; - } - } - if (targetLocation != null && targetLocation.getWorld() != null) { - if (targetLocation.getWorld().getName().equals(quester.getPlayer().getWorld().getName())) { - final Location lockedTarget = new Location(targetLocation.getWorld(), targetLocation.getX(), - targetLocation.getY(), targetLocation.getZ()); - final QuestUpdateCompassEvent event = new QuestUpdateCompassEvent(quest, quester, lockedTarget); - plugin.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - quester.getPlayer().setCompassTarget(lockedTarget); - } - } - }); - return true; - } - - /** - * Check that a quester has met all Requirements to accept this quest

- * - * Item, permission and custom Requirements are only checked for online players - * - * @param quester The quester to check - * @return true if all Requirements have been met - */ - public boolean testRequirements(final Quester quester) { - return testRequirements(quester.getOfflinePlayer()); - } - - /** - * Check that a player has met all Requirements to accept this quest

- * - * Item, permission and custom Requirements are only checked for online players - * - * @param player The player to check - * @return true if all Requirements have been met - */ - protected boolean testRequirements(final OfflinePlayer player) { - final Quester quester = plugin.getQuester(player.getUniqueId()); - if (requirements.getMoney() != 0 && plugin.getDependencies().getVaultEconomy() != null) { - if (plugin.getDependencies().getVaultEconomy().getBalance(player) < requirements.getMoney()) { - return false; - } - } - if (quester.questPoints < requirements.getQuestPoints()) { - return false; - } - if (!quester.completedQuests.containsAll(requirements.getNeededQuests())) { - return false; - } - for (final Quest q : requirements.getBlockQuests()) { - if (quester.completedQuests.contains(q) || quester.currentQuests.containsKey(q)) { - return false; - } - } - for (final String s : requirements.getMcmmoSkills()) { - final SkillType st = Quests.getMcMMOSkill(s); - final int lvl = requirements.getMcmmoAmounts().get(requirements.getMcmmoSkills().indexOf(s)); - if (UserManager.getOfflinePlayer(player).getProfile().getSkillLevel(st) < lvl) { - return false; - } - } - if (requirements.getHeroesPrimaryClass() != null) { - if (!plugin.getDependencies().testPrimaryHeroesClass(requirements.getHeroesPrimaryClass(), player.getUniqueId())) { - return false; - } - } - if (requirements.getHeroesSecondaryClass() != null) { - if (!plugin.getDependencies().testSecondaryHeroesClass(requirements.getHeroesSecondaryClass(), - player.getUniqueId())) { - return false; - } - } - if (player.isOnline()) { - final Player p = (Player)player; - final Inventory fakeInv = Bukkit.createInventory(null, InventoryType.PLAYER); - fakeInv.setContents(p.getInventory().getContents().clone()); - for (final ItemStack is : requirements.getItems()) { - if (InventoryUtil.canRemoveItem(fakeInv, is)) { - InventoryUtil.removeItem(fakeInv, is); - } else { - return false; - } - } - for (final String s : requirements.getPermissions()) { - if (!p.hasPermission(s)) { - return false; - } - } - for (final String s : requirements.getCustomRequirements().keySet()) { - CustomRequirement found = null; - for (final CustomRequirement cr : plugin.getCustomRequirements()) { - if (cr.getName().equalsIgnoreCase(s)) { - found = cr; - break; - } - } - if (found != null) { - if (!found.testRequirement(p, requirements.getCustomRequirements().get(s))) { - return false; - } - } else { - plugin.getLogger().warning("Quester \"" + p.getName() + "\" attempted to take Quest \"" + name - + "\", but the Custom Requirement \"" + s + "\" could not be found. Does it still exist?"); - } - } - } - return true; - } - - /** - * Proceed to finish this quest, issuing applicable rewards - * - * @param quester The quester finishing this quest - */ - public void completeQuest(final Quester quester) { - completeQuest(quester, true); - } - - /** - * Proceed to finish this quest, issuing applicable rewards - * - * @param quester The quester finishing this quest - * @param allowMultiplayer Allow multiplayer sharing - */ - @SuppressWarnings("deprecation") - public void completeQuest(final Quester quester, final boolean allowMultiplayer) { - final OfflinePlayer player = quester.getOfflinePlayer(); - boolean cancelled = false; - if (player.isOnline()) { - if (Bukkit.isPrimaryThread()) { - final QuesterPreCompleteQuestEvent preEvent - = new QuesterPreCompleteQuestEvent(quester, this, false); - plugin.getServer().getPluginManager().callEvent(preEvent); - if (preEvent.isCancelled()) { - return; - } - } else { - final CompletableFuture future = CompletableFuture.supplyAsync(() -> { - final QuesterPreCompleteQuestEvent preEvent - = new QuesterPreCompleteQuestEvent(quester, Quest.this, true); - plugin.getServer().getPluginManager().callEvent(preEvent); - return preEvent.isCancelled(); - }); + public String getFinished(); - try { - cancelled = future.get(); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - if (cancelled) { - return; - } - quester.hardQuit(this); - quester.completedQuests.add(this); - for (final Map.Entry entry : quester.timers.entrySet()) { - if (entry.getValue().getName().equals(getName())) { - plugin.getServer().getScheduler().cancelTask(entry.getKey()); - quester.timers.remove(entry.getKey()); - } - } - if (player.isOnline()) { - final Player p = (Player)player; - final String[] ps = ConfigUtil.parseStringWithPossibleLineBreaks(ChatColor.AQUA - + finished, this, p); - Bukkit.getScheduler().runTaskLater(plugin, () -> p.sendMessage(ps), 40); - } - if (planner.getCooldown() > -1) { - quester.completedTimes.put(this, System.currentTimeMillis()); - if (quester.amountsCompleted.containsKey(this)) { - quester.amountsCompleted.put(this, quester.amountsCompleted.get(this) + 1); - } else { - quester.amountsCompleted.put(this, 1); - } - } - - // Issue rewards - final Dependencies depends = plugin.getDependencies(); - boolean issuedReward = false; - if (rewards.getMoney() > 0 && depends.getVaultEconomy() != null) { - depends.getVaultEconomy().depositPlayer(player, rewards.getMoney()); - issuedReward = true; - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " - + depends.getVaultEconomy().format(rewards.getMoney())); - } - } - if (player.isOnline()) { - for (final ItemStack i : rewards.getItems()) { - try { - InventoryUtil.addItem(player.getPlayer(), i); - } catch (final Exception e) { - plugin.getLogger().severe("Unable to add null reward item to inventory of " - + player.getName() + " upon completion of quest " + name); - quester.sendMessage(ChatColor.RED + "Quests encountered a problem with an item. " - + "Please contact an administrator."); - } - issuedReward = true; - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " + i.getType().name() + " x " - + i.getAmount()); - } - } - } - for (final String s : rewards.getCommands()) { - if (player.getName() == null) { - continue; - } - String temp = s.replace("", player.getName()); - if (depends.getPlaceholderApi() != null && player.isOnline()) { - temp = PlaceholderAPI.setPlaceholders((Player)player, temp); - } - final String command = temp; - if (Bukkit.isPrimaryThread()) { - Bukkit.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command); - } else { - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> - Bukkit.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command)); - } - issuedReward = true; - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded command " + s); - } - } - for (int i = 0; i < rewards.getPermissions().size(); i++) { - if (depends.getVaultPermission() != null) { - final String perm = rewards.getPermissions().get(i); - String world = null; - if (i < rewards.getPermissionWorlds().size()) { - world = rewards.getPermissionWorlds().get(i); - } - if (world == null || world.equals("null")) { - depends.getVaultPermission().playerAdd(null, player, perm); - } else { - depends.getVaultPermission().playerAdd(world, player, perm); - } - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded permission " + perm); - } - issuedReward = true; - } - } - for (final String s : rewards.getMcmmoSkills()) { - final int levels = rewards.getMcmmoAmounts().get(rewards.getMcmmoSkills().indexOf(s)); - UserManager.getOfflinePlayer(player).getProfile().addLevels(Quests.getMcMMOSkill(s), levels); - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " + s + " x " + levels); - } - issuedReward = true; - } - if (player.isOnline()) { - for (final String s : rewards.getHeroesClasses()) { - final Hero hero = plugin.getDependencies().getHero(player.getUniqueId()); - final double expChange = rewards.getHeroesAmounts().get(rewards.getHeroesClasses().indexOf(s)); - hero.addExp(expChange, plugin.getDependencies().getHeroes().getClassManager().getClass(s), - ((Player)player).getLocation()); - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " + s + " x " + expChange); - } - issuedReward = true; - } - } - if (rewards.getPartiesExperience() > 0 && depends.getPartiesApi() != null) { - final PartyPlayer partyPlayer = depends.getPartiesApi().getPartyPlayer(player.getUniqueId()); - if (partyPlayer != null && partyPlayer.getPartyId() != null) { - final Party party = depends.getPartiesApi().getParty(partyPlayer.getPartyId()); - if (party != null) { - party.giveExperience(rewards.getPartiesExperience()); - issuedReward = true; - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " - + rewards.getPartiesExperience() + " party experience"); - } - } - } - } - final LinkedList phatLootItems = new LinkedList<>(); - int phatLootExp = 0; - final LinkedList phatLootMessages = new LinkedList<>(); - for (final String s : rewards.getPhatLoots()) { - final LootBundle lb = PhatLootsAPI.getPhatLoot(s).rollForLoot(); - if (lb.getExp() > 0) { - phatLootExp += lb.getExp(); - if (player.isOnline()) { - ((Player)player).giveExp(lb.getExp()); - } - } - if (lb.getMoney() > 0) { - if (depends.getVaultEconomy() != null) { - depends.getVaultEconomy().depositPlayer(player, lb.getMoney()); - } - } - if (!lb.getItemList().isEmpty()) { - phatLootItems.addAll(lb.getItemList()); - if (player.isOnline()) { - for (final ItemStack is : lb.getItemList()) { - try { - InventoryUtil.addItem(player.getPlayer(), is); - } catch (final Exception e) { - plugin.getLogger().severe("Unable to add PhatLoots item to inventory of " - + player.getName() + " upon completion of quest " + name); - quester.sendMessage(ChatColor.RED + "Quests encountered a problem with an item. " - + "Please contact an administrator."); - } - } - } - } - if (!lb.getCommandList().isEmpty() && player.isOnline()) { - for (final CommandLoot cl : lb.getCommandList()) { - cl.execute((Player)player); - } - } - if (!lb.getMessageList().isEmpty()) { - phatLootMessages.addAll(lb.getMessageList()); - } - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded loot " + s); - } - issuedReward = true; - } - if (rewards.getExp() > 0 && player.isOnline()) { - ((Player)player).giveExp(rewards.getExp()); - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded exp " + rewards.getExp()); - } - issuedReward = true; - } - if (rewards.getQuestPoints() > 0) { - quester.questPoints += rewards.getQuestPoints(); - if (plugin.getSettings().getConsoleLogging() > 2) { - plugin.getLogger().info(player.getUniqueId() + " was rewarded " + rewards.getQuestPoints() + " " - + Lang.get("questPoints")); - } - issuedReward = true; - } - if (!rewards.getCustomRewards().isEmpty()) { - issuedReward = true; - if (plugin.getSettings().getConsoleLogging() > 2) { - for (final String s : rewards.getCustomRewards().keySet()) { - plugin.getLogger().info(player.getUniqueId() + " was custom rewarded " + s); - } - } - } - - // Inform player - if (player.isOnline()) { - final Player p = (Player)player; - Lang.send(p, ChatColor.GOLD + Lang.get(p, "questCompleteTitle").replace("", - ChatColor.YELLOW + name + ChatColor.GOLD)); - if (plugin.getSettings().canShowQuestTitles()) { - p.sendTitle(ChatColor.GOLD + Lang.get(p, "quest") + " " + Lang.get(p, "complete"), - ChatColor.YELLOW + name); - } - Lang.send(p, ChatColor.GREEN + Lang.get(p, "questRewardsTitle")); - if (!issuedReward) { - p.sendMessage(ChatColor.GRAY + "- (" + Lang.get("none") + ")"); - } else if (!rewards.getDetailsOverride().isEmpty()) { - for (final String s: rewards.getDetailsOverride()) { - String message = ChatColor.DARK_GREEN + ConfigUtil.parseString( - ChatColor.translateAlternateColorCodes('&', s)); - if (plugin.getDependencies().getPlaceholderApi() != null) { - message = PlaceholderAPI.setPlaceholders(p, message); - } - quester.sendMessage("- " + message); - } - } else { - if (rewards.getQuestPoints() > 0) { - quester.sendMessage("- " + ChatColor.DARK_GREEN + rewards.getQuestPoints() + " " - + Lang.get(p, "questPoints")); - } - for (final ItemStack i : rewards.getItems()) { - StringBuilder text; - if (i.getItemMeta() != null && i.getItemMeta().hasDisplayName()) { - if (i.getEnchantments().isEmpty()) { - text = new StringBuilder("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + i.getItemMeta().getDisplayName() - + ChatColor.RESET + ChatColor.GRAY + " x " + i.getAmount()); - } else { - text = new StringBuilder("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + i.getItemMeta().getDisplayName() - + ChatColor.RESET); - try { - if (!i.getItemMeta().hasItemFlag(ItemFlag.HIDE_ENCHANTS)) { - text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")).append(ChatColor.DARK_PURPLE); - for (final Entry e : i.getEnchantments().entrySet()) { - text.append(" ").append(ItemUtil.getPrettyEnchantmentName(e.getKey())).append(":").append(e.getValue()); - } - } - } catch (final Throwable tr) { - // Do nothing, hasItemFlag() not introduced until 1.8.6 - } - text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); - } - } else if (i.getDurability() != 0) { - text = new StringBuilder("- " + ChatColor.DARK_GREEN + ":" + i.getDurability()); - if (!i.getEnchantments().isEmpty()) { - text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")); - for (int iz = 0; iz < i.getEnchantments().size(); iz++) { - text.append(" "); - } - } - text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); - } else { - text = new StringBuilder("- " + ChatColor.DARK_GREEN + ""); - if (!i.getEnchantments().isEmpty()) { - try { - if (!i.getItemMeta().hasItemFlag(ItemFlag.HIDE_ENCHANTS)) { - text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")); - for (int iz = 0; iz < i.getEnchantments().size(); iz++) { - text.append(" "); - } - } - } catch (final Throwable tr) { - // Do nothing, hasItemFlag() not introduced until 1.8.6 - } - } - text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); - } - if (plugin.getSettings().canTranslateNames() && text.toString().contains("")) { - if (!plugin.getLocaleManager().sendMessage(p, text.toString(), i.getType(), i.getDurability(), - i.getEnchantments())) { - for (final Entry e : i.getEnchantments().entrySet()) { - text = new StringBuilder(text.toString().replaceFirst("", ItemUtil.getPrettyEnchantmentName( - e.getKey()))); - text = new StringBuilder(text.toString().replaceFirst("", RomanNumeral.getNumeral(e.getValue()))); - } - quester.sendMessage(text.toString().replace("", ItemUtil.getName(i))); - } - } else { - for (final Entry e : i.getEnchantments().entrySet()) { - text = new StringBuilder(text.toString().replaceFirst("", ItemUtil.getPrettyEnchantmentName( - e.getKey()))); - text = new StringBuilder(text.toString().replaceFirst("", RomanNumeral.getNumeral(e.getValue()))); - } - quester.sendMessage(text.toString().replace("", ItemUtil.getName(i))); - } - } - for (final ItemStack i : phatLootItems) { - if (i.getItemMeta() != null && i.getItemMeta().hasDisplayName()) { - if (i.getEnchantments().isEmpty()) { - quester.sendMessage("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC - + i.getItemMeta().getDisplayName() + ChatColor.RESET + ChatColor.GRAY + " x " - + i.getAmount()); - } else { - quester.sendMessage("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC - + i.getItemMeta().getDisplayName() + ChatColor.RESET + ChatColor.GRAY + " x " - + i.getAmount() + ChatColor.DARK_PURPLE + " " + Lang.get(p, "enchantedItem")); - } - } else if (i.getDurability() != 0) { - if (i.getEnchantments().isEmpty()) { - quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ":" - + i.getDurability() + ChatColor.GRAY + " x " + i.getAmount()); - } else { - quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ":" - + i.getDurability() + ChatColor.GRAY + " x " + i.getAmount() - + ChatColor.DARK_PURPLE + " " + Lang.get(p, "enchantedItem")); - } - } else { - if (i.getEnchantments().isEmpty()) { - quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ChatColor.GRAY - + " x " + i.getAmount()); - } else { - quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ChatColor.GRAY - + " x " + i.getAmount() + ChatColor.DARK_PURPLE + " " - + Lang.get(p, "enchantedItem")); - } - } - } - if (rewards.getMoney() > 0 && depends.getVaultEconomy() != null) { - quester.sendMessage("- " + ChatColor.DARK_GREEN - + depends.getVaultEconomy().format(rewards.getMoney())); - } - if (rewards.getExp() > 0 || phatLootExp > 0) { - final int tot = rewards.getExp() + phatLootExp; - quester.sendMessage("- " + ChatColor.DARK_GREEN + tot + ChatColor.DARK_PURPLE + " " - + Lang.get(p, "experience")); - } - if (!rewards.getCommands().isEmpty()) { - int index = 0; - for (final String s : rewards.getCommands()) { - if (!rewards.getCommandsOverrideDisplay().isEmpty() - && rewards.getCommandsOverrideDisplay().size() > index) { - if (!rewards.getCommandsOverrideDisplay().get(index).trim().equals("")) { - quester.sendMessage("- " + ChatColor.DARK_GREEN - + rewards.getCommandsOverrideDisplay().get(index)); - } - } else { - quester.sendMessage("- " + ChatColor.DARK_GREEN + s); - } - index++; - } - } - if (!rewards.getPermissions().isEmpty()) { - int index = 0; - for (final String s : rewards.getPermissions()) { - if (rewards.getPermissionWorlds() != null && rewards.getPermissionWorlds().size() > index) { - quester.sendMessage("- " + ChatColor.DARK_GREEN + s + " (" - + rewards.getPermissionWorlds().get(index) + ")"); - } else { - quester.sendMessage("- " + ChatColor.DARK_GREEN + s); - - } - index++; - } - } - if (!rewards.getMcmmoSkills().isEmpty()) { - for (final String s : rewards.getMcmmoSkills()) { - quester.sendMessage("- " + ChatColor.DARK_GREEN - + rewards.getMcmmoAmounts().get(rewards.getMcmmoSkills().indexOf(s)) + " " - + ChatColor.DARK_PURPLE + s + " " + Lang.get(p, "experience")); - } - } - if (!rewards.getHeroesClasses().isEmpty()) { - for (final String s : rewards.getHeroesClasses()) { - quester.sendMessage("- " + ChatColor.AQUA - + rewards.getHeroesAmounts().get(rewards.getHeroesClasses().indexOf(s)) + " " + ChatColor.BLUE - + s + " " + Lang.get(p, "experience")); - } - } - if (rewards.getPartiesExperience() > 0) { - p.sendMessage("- " + ChatColor.DARK_GREEN + rewards.getPartiesExperience() + ChatColor.DARK_PURPLE - + " " + Lang.get(p, "partiesExperience")); - } - if (!phatLootMessages.isEmpty()) { - for (final String s : phatLootMessages) { - quester.sendMessage("- " + s); - } - } - for (final String s : rewards.getCustomRewards().keySet()) { - CustomReward found = null; - for (final CustomReward cr : plugin.getCustomRewards()) { - if (cr.getName().equalsIgnoreCase(s)) { - found = cr; - break; - } - } - if (found != null) { - final Map dataMap = rewards.getCustomRewards().get(found.getName()); - String message = found.getDisplay(); - if (message != null) { - for (final String key : dataMap.keySet()) { - message = message.replace("%" + key + "%", dataMap.get(key).toString()); - } - quester.sendMessage("- " + ChatColor.GOLD + message); - } else { - plugin.getLogger().warning("Failed to notify player: " - + "Custom Reward does not have an assigned name"); - } - found.giveReward(p, rewards.getCustomRewards().get(s)); - } else { - plugin.getLogger().warning("Quester \"" + player.getName() + "\" completed the Quest \"" - + name + "\", but the Custom Reward \"" + s - + "\" could not be found. Does it still exist?"); - } - } - } - } - quester.saveData(); - if (player.isOnline()) { - if (player.getPlayer() != null) { - player.getPlayer().updateInventory(); - } - } - quester.updateJournal(); - quester.findCompassTarget(); - if (player.isOnline()) { - final QuesterPostCompleteQuestEvent postEvent = new QuesterPostCompleteQuestEvent(quester, this); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - // Multiplayer - if (allowMultiplayer && options.getShareProgressLevel() == 4) { - final List mq = quester.getMultiplayerQuesters(this); - for (final Quester qq : mq) { - if (qq.getQuestData(this) != null) { - completeQuest(qq, false); - } - } - } - } - - /** - * Force player to quit quest and inform them of their failure - * - * @param quester The quester to be ejected - */ - public void failQuest(final Quester quester) { - failQuest(quester, false); - } - - /** - * Force player to quit quest and inform them of their failure - * - * @param quester The quester to be ejected - * @param ignoreFailAction Whether to ignore quest fail Action - */ - @SuppressWarnings("deprecation") - public void failQuest(final Quester quester, final boolean ignoreFailAction) { - final QuesterPreFailQuestEvent preEvent = new QuesterPreFailQuestEvent(quester, this); - plugin.getServer().getPluginManager().callEvent(preEvent); - if (preEvent.isCancelled()) { - return; - } - final Player player = quester.getPlayer(); - if (!ignoreFailAction) { - final Stage stage = quester.getCurrentStage(this); - if (stage != null && stage.getFailAction() != null) { - quester.getCurrentStage(this).getFailAction().fire(quester, this); - } - } - final String[] messages = { - ChatColor.GOLD + Lang.get(player, "questCommandTitle").replace("", name), - ChatColor.RED + Lang.get(player, "questFailed") - }; - quester.quitQuest(this, messages); - if (player.isOnline()) { - player.updateInventory(); - } - final QuesterPostFailQuestEvent postEvent = new QuesterPostFailQuestEvent(quester, this); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Checks if quester is in WorldGuard region start - * - * @deprecated Use {@link #isInRegionStart(Quester)} - * @param quester The quester to check - * @return true if quester is in region - */ - @Deprecated - public boolean isInRegion(final Quester quester) { - return isInRegionStart(quester); - } + public void setFinished(final String finished); - /** - * Checks if player is in WorldGuard region start - * - * @deprecated Use {@link #isInRegionStart(Player)} - * @param player The player to check - * @return true if player is in region - */ - @Deprecated - @SuppressWarnings("unused") - private boolean isInRegion(final Player player) { - return isInRegionStart(player); - } - - /** - * Checks if quester is in WorldGuard region start - * - * @param quester The quester to check - * @return true if quester is in region - */ - public boolean isInRegionStart(final Quester quester) { - return isInRegionStart(quester.getPlayer()); - } + public String getRegionStart(); - /** - * Checks if player is in WorldGuard region start - * - * @param player The player to check - * @return true if player is in region - */ - private boolean isInRegionStart(final Player player) { - if (regionStart == null) { - return false; - } - return plugin.getDependencies().getWorldGuardApi() - .getApplicableRegionsIDs(player.getWorld(), player.getLocation()).contains(regionStart); - } + public void setRegionStart(final String regionStart); + + public ItemStack getGUIDisplay(); + + public void setGUIDisplay(final ItemStack guiDisplay); + + public Stage getStage(final int index); + + public LinkedList getStages(); + + public NPC getNpcStart(); + + public void setNpcStart(final NPC npcStart); + + public Location getBlockStart(); + + public void setBlockStart(final Location blockStart); + + public Action getInitialAction(); + + public void setInitialAction(final Action initialAction); + + public Requirements getRequirements(); + + public Planner getPlanner(); + + public Rewards getRewards(); + + public Options getOptions(); } diff --git a/api/src/main/java/me/blackvein/quests/Quester.java b/api/src/main/java/me/blackvein/quests/Quester.java index 3260460d9..7debcb335 100644 --- a/api/src/main/java/me/blackvein/quests/Quester.java +++ b/api/src/main/java/me/blackvein/quests/Quester.java @@ -1,4322 +1,63 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - package me.blackvein.quests; -import com.alessiodp.parties.api.interfaces.Party; -import com.alessiodp.parties.api.interfaces.PartyPlayer; -import com.gmail.nossr50.datatypes.skills.SkillType; -import com.gmail.nossr50.util.player.UserManager; -import me.blackvein.quests.conditions.Condition; -import me.blackvein.quests.enums.ObjectiveType; -import me.blackvein.quests.events.quest.QuestTakeEvent; -import me.blackvein.quests.events.quester.QuesterPostStartQuestEvent; -import me.blackvein.quests.events.quester.QuesterPostUpdateObjectiveEvent; -import me.blackvein.quests.events.quester.QuesterPreOpenGUIEvent; -import me.blackvein.quests.events.quester.QuesterPreStartQuestEvent; -import me.blackvein.quests.events.quester.QuesterPreUpdateObjectiveEvent; -import me.blackvein.quests.item.QuestJournal; -import me.blackvein.quests.storage.Storage; -import me.blackvein.quests.tasks.StageTimer; -import me.blackvein.quests.util.ConfigUtil; -import me.blackvein.quests.util.InventoryUtil; -import me.blackvein.quests.util.ItemUtil; -import me.blackvein.quests.util.Lang; -import me.blackvein.quests.util.MiscUtil; -import me.blackvein.quests.util.RomanNumeral; -import me.clip.placeholderapi.PlaceholderAPI; -import me.pikamug.unite.api.objects.PartyProvider; -import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.npc.NPC; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.DyeColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.material.Crops; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; -public class Quester implements Comparable { +public interface Quester { + public UUID getUUID(); - private final Quests plugin; - private UUID id; - protected String questIdToTake; - private String lastKnownName; - protected int questPoints = 0; - private String compassTargetQuestId; - private long lastNotifiedCondition = 0L; - protected ConcurrentHashMap timers = new ConcurrentHashMap<>(); - protected ConcurrentHashMap currentQuests = new ConcurrentHashMap() { + public void setUUID(final UUID id); - private static final long serialVersionUID = 6361484975823846780L; + public String getQuestIdToTake(); - @Override - public Integer put(final @NotNull Quest key, final @NotNull Integer val) { - final Integer data = super.put(key, val); - updateJournal(); - return data; - } + public void setQuestIdToTake(final String questIdToTake); - @Override - public Integer remove(final @NotNull Object key) { - final Integer i = super.remove(key); - updateJournal(); - return i; - } + public String getLastKnownName(); - @Override - public void clear() { - super.clear(); - updateJournal(); - } + public void setLastKnownName(final String lastKnownName); - @Override - public void putAll(final Map m) { - super.putAll(m); - updateJournal(); - } - }; - protected ConcurrentSkipListSet completedQuests = new ConcurrentSkipListSet() { + public int getQuestPoints(); - private static final long serialVersionUID = -269110128568487000L; + public void setQuestPoints(final int questPoints); - @Override - public boolean add(final Quest e) { - final boolean b = super.add(e); - updateJournal(); - return b; - } - - @Override - public boolean addAll(final @NotNull Collection c) { - final boolean b = super.addAll(c); - updateJournal(); - return b; - } - - @Override - public void clear() { - super.clear(); - updateJournal(); - } - - @Override - public boolean remove(final Object o) { - final boolean b = super.remove(o); - updateJournal(); - return b; - } - - @Override - public boolean removeAll(final Collection c) { - final boolean b = super.removeAll(c); - updateJournal(); - return b; - } - }; - protected ConcurrentHashMap completedTimes = new ConcurrentHashMap<>(); - protected ConcurrentHashMap amountsCompleted = new ConcurrentHashMap() { - - private static final long serialVersionUID = 5475202358792520975L; - - @Override - public Integer put(final @NotNull Quest key, final @NotNull Integer val) { - final Integer data = super.put(key, val); - updateJournal(); - return data; - } - - @Override - public Integer remove(final @NotNull Object key) { - final Integer i = super.remove(key); - updateJournal(); - return i; - } - - @Override - public void clear() { - super.clear(); - updateJournal(); - } - - @Override - public void putAll(final Map m) { - super.putAll(m); - updateJournal(); - } - }; - protected ConcurrentHashMap questData = new ConcurrentHashMap() { - - private static final long serialVersionUID = -4607112433003926066L; - - @Override - public QuestData put(final @NotNull Quest key, final @NotNull QuestData val) { - final QuestData data = super.put(key, val); - updateJournal(); - return data; - } - - @Override - public QuestData remove(final @NotNull Object key) { - final QuestData data = super.remove(key); - updateJournal(); - return data; - } - - @Override - public void clear() { - super.clear(); - updateJournal(); - } - - @Override - public void putAll(final Map m) { - super.putAll(m); - updateJournal(); - } - }; - - /** - * @deprecated Use {@link #Quester(Quests, UUID)} - */ - @Deprecated - public Quester(final Quests plugin) { - this.plugin = plugin; - } - - public Quester(final Quests plugin, final UUID uuid) { - this.plugin = plugin; - this.id = uuid; - if (getPlayer() != null) { - this.lastKnownName = getPlayer().getName(); - } else { - this.lastKnownName = getOfflinePlayer().getName(); - } - } - - @Override - public int compareTo(final Quester quester) { - return id.compareTo(quester.getUUID()); - } - - public UUID getUUID() { - return id; - } - - public void setUUID(final UUID id) { - this.id = id; - } - - public String getQuestIdToTake() { - return questIdToTake; - } - - public void setQuestIdToTake(final String questIdToTake) { - this.questIdToTake = questIdToTake; - } - - public String getLastKnownName() { - return lastKnownName; - } - - public void setLastKnownName(final String lastKnownName) { - this.lastKnownName = lastKnownName; - } - - public int getQuestPoints() { - return questPoints; - } - - public void setQuestPoints(final int questPoints) { - this.questPoints = questPoints; - } - /** * Get compass target quest. Returns null if not set - * + * * @return Quest or null */ - public Quest getCompassTarget() { - return compassTargetQuestId != null ? plugin.getQuestById(compassTargetQuestId) : null; - } - + public Quest getCompassTarget(); + /** * Set compass target quest. Does not update in-game - * + * * @param quest The target quest */ - public void setCompassTarget(final Quest quest) { - compassTargetQuestId = quest.getId(); - } + public void setCompassTarget(final Quest quest); - public ConcurrentHashMap getTimers() { - return timers; - } + public ConcurrentHashMap getTimers(); - public void setTimers(final ConcurrentHashMap timers) { - this.timers = timers; - } - - public void removeTimer(final Integer timerId) { - this.timers.remove(timerId); - } + public void setTimers(final ConcurrentHashMap timers); - public ConcurrentHashMap getCurrentQuests() { - return currentQuests; - } + public void removeTimer(final Integer timerId); - public void setCurrentQuests(final ConcurrentHashMap currentQuests) { - this.currentQuests = currentQuests; - } + public ConcurrentHashMap getCurrentQuests(); - public ConcurrentSkipListSet getCompletedQuests() { - return completedQuests; - } + public void setCurrentQuests(final ConcurrentHashMap currentQuests); - public void setCompletedQuests(final ConcurrentSkipListSet completedQuests) { - this.completedQuests = completedQuests; - } + public ConcurrentSkipListSet getCompletedQuests(); - public ConcurrentHashMap getCompletedTimes() { - return completedTimes; - } + public void setCompletedQuests(final ConcurrentSkipListSet completedQuests); - public void setCompletedTimes(final ConcurrentHashMap completedTimes) { - this.completedTimes = completedTimes; - } + public ConcurrentHashMap getCompletedTimes(); - public ConcurrentHashMap getAmountsCompleted() { - return amountsCompleted; - } + public void setCompletedTimes(final ConcurrentHashMap completedTimes); - public void setAmountsCompleted(final ConcurrentHashMap amountsCompleted) { - this.amountsCompleted = amountsCompleted; - } + public ConcurrentHashMap getAmountsCompleted(); - public ConcurrentHashMap getQuestData() { - return questData; - } + public void setAmountsCompleted(final ConcurrentHashMap amountsCompleted); - public void setQuestData(final ConcurrentHashMap questData) { - this.questData = questData; - } + public ConcurrentHashMap getQuestData(); - public Player getPlayer() { - return plugin.getServer().getPlayer(id); - } - - public OfflinePlayer getOfflinePlayer() { - return plugin.getServer().getOfflinePlayer(id); - } - - public void sendMessage(final String message) { - if (getPlayer() == null || !getPlayer().isOnline() || message.trim().isEmpty()) { - return; - } - getPlayer().sendMessage(message); - } - - public Stage getCurrentStage(final Quest quest) { - if (currentQuests.containsKey(quest)) { - return quest.getStage(currentQuests.get(quest)); - } - return null; - } - - public QuestData getQuestData(final Quest quest) { - for (final Quest q : questData.keySet()) { - if (q.getId().equals(quest.getId())) { - return questData.get(q); - } - } - if (currentQuests.get(quest) != null) { - addEmptiesFor(quest, currentQuests.get(quest)); - } - return new QuestData(this); - } - - public boolean hasJournal() { - return getJournal() != null; - } - - public ItemStack getJournal() { - if (getPlayer() == null || !getPlayer().isOnline()) { - return null; - } - for (final ItemStack is : getPlayer().getInventory().getContents()) { - if (ItemUtil.isJournal(is)) { - return is; - } - } - return null; - } - - public int getJournalIndex() { - if (getPlayer() == null || !getPlayer().isOnline()) { - return -1; - } - final ItemStack[] arr = getPlayer().getInventory().getContents(); - for (int i = 0; i < arr.length; i++) { - if (arr[i] != null) { - if (ItemUtil.isJournal(arr[i])) { - return i; - } - } - } - return -1; - } - - public void updateJournal() { - if (getPlayer() == null) { - return; - } - if (!getPlayer().isOnline()) { - plugin.getLogger().info("Could not update Quests Journal for " + getPlayer().getName() + " while offline"); - return; - } - final int index = getJournalIndex(); - if (index != -1) { - final QuestJournal journal = new QuestJournal(this); - getPlayer().getInventory().setItem(index, journal.toItemStack()); - } - } - - /** - * Start a quest for this Quester - * - * @param quest The quest to start - * @param ignoreRequirements Whether to ignore Requirements - */ - @SuppressWarnings("deprecation") - public void takeQuest(final Quest quest, final boolean ignoreRequirements) { - if (quest == null) { - return; - } - final QuesterPreStartQuestEvent preEvent = new QuesterPreStartQuestEvent(this, quest); - plugin.getServer().getPluginManager().callEvent(preEvent); - if (preEvent.isCancelled()) { - return; - } - final OfflinePlayer offlinePlayer = getOfflinePlayer(); - if (offlinePlayer.isOnline()) { - final Planner pln = quest.getPlanner(); - final long currentTime = System.currentTimeMillis(); - final long start = pln.getStartInMillis(); // Start time in milliseconds since UTC epoch - final long end = pln.getEndInMillis(); // End time in milliseconds since UTC epoch - final long duration = end - start; // How long the quest can be active for - final long repeat = pln.getRepeat(); // Length to wait in-between start times - if (start != -1) { - if (currentTime < start) { - String early = Lang.get("plnTooEarly"); - early = early.replace("", ChatColor.AQUA + quest.getName() + ChatColor.YELLOW); - early = early.replace("

- * - * Accepted strings are: breakBlock, damageBlock, placeBlock, useBlock, - * cutBlock, craftItem, smeltItem, enchantItem, brewItem, consumeItem, - * milkCow, catchFish, killMob, deliverItem, killPlayer, talkToNPC, - * killNPC, tameMob, shearSheep, password, reachLocation - * - * @deprecated Use {@link Stage#containsObjective(ObjectiveType)} - * @param quest The quest to check objectives of - * @param name The type of objective to check for - * @return true if stage contains specified objective - */ - @Deprecated - public boolean containsObjective(final Quest quest, final String name) { - if (quest == null || getCurrentStage(quest) == null) { - return false; - } - return getCurrentStage(quest).containsObjective(ObjectiveType.fromName(name)); - } - - /** - * Check if player's current stage has the specified custom objective - * - * @param quest The quest to check custom objectives of - * @param name The exact name of custom objective to check for - * @return true if stage contains specified objective - */ - public boolean hasCustomObjective(final Quest quest, final String name) { - if (quest == null || getCurrentStage(quest) == null) { - return false; - } - for (final CustomObjective co : getCurrentStage(quest).customObjectives) { - if (co.getName().equals(name)) { - return true; - } - } - return false; - } - - /** - * Marks block as broken if Quester has such an objective - * - * @param quest The quest for which the block is being broken - * @param itemStack The block being broken - */ - @SuppressWarnings("deprecation") - public void breakBlock(final Quest quest, final ItemStack itemStack) { - itemStack.setAmount(0); - ItemStack broken = itemStack; - ItemStack toBreak = itemStack; - for (final ItemStack is : getQuestData(quest).blocksBroken) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - broken = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - broken = is; - } - } else if (itemStack.getData() instanceof Crops && is.getData() instanceof Crops) { - if (is.getDurability() > 0) { - // Age is specified so check for durability - if (itemStack.getDurability() == is.getDurability()) { - broken = is; - } - } else { - // Age is unspecified so ignore durability - broken = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - broken = is; - } - } else { - // Blocks are not solid so ignore durability - broken = is; - } - } - } - for (final ItemStack is : getCurrentStage(quest).blocksToBreak) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toBreak = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - toBreak = is; - } - } else if (itemStack.getData() instanceof Crops && is.getData() instanceof Crops) { - if (is.getDurability() > 0) { - // Age is specified so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toBreak = is; - } - } else { - // Age is unspecified so ignore durability - toBreak = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toBreak = is; - } - } else { - // Blocks are not solid so ignore durability - toBreak = is; - } - } - } - - final ObjectiveType type = ObjectiveType.BREAK_BLOCK; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, broken.getAmount(), toBreak.getAmount())); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final ItemStack newBroken = broken; - if (broken.getAmount() < toBreak.getAmount()) { - newBroken.setAmount(broken.getAmount() + 1); - if (getQuestData(quest).blocksBroken.contains(broken)) { - getQuestData(quest).blocksBroken.set(getQuestData(quest).blocksBroken.indexOf(broken), newBroken); - if (broken.getAmount() == toBreak.getAmount()) { - finishObjective(quest, new Objective(type, itemStack, toBreak), null, null, null, null, null, null, null); - - // Multiplayer - final ItemStack finalBroken = broken; - final ItemStack finalToBreak = toBreak; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).blocksBroken.set(getQuestData(quest).blocksBroken - .indexOf(finalBroken), newBroken); - q.finishObjective(quest, new Objective(type, itemStack, finalToBreak), null, null, null, null, null, - null, null); - return null; - }); - } - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newBroken.getAmount(), toBreak.getAmount())); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks block as damaged if Quester has such an objective - * - * @param quest The quest for which the block is being damaged - * @param itemStack The block being damaged - */ - @SuppressWarnings("deprecation") - public void damageBlock(final Quest quest, final ItemStack itemStack) { - itemStack.setAmount(0); - ItemStack damaged = itemStack; - ItemStack toDamage = itemStack; - for (final ItemStack is : getQuestData(quest).blocksDamaged) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - damaged = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - damaged = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - damaged = is; - } - } else { - // Blocks are not solid so ignore durability - damaged = is; - } - } - } - for (final ItemStack is : getCurrentStage(quest).blocksToDamage) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toDamage = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - toDamage = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toDamage = is; - } - } else { - // Blocks are not solid so ignore durability - toDamage = is; - } - } - } - - final ObjectiveType type = ObjectiveType.DAMAGE_BLOCK; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, damaged.getAmount(), toDamage.getAmount())); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final ItemStack newDamaged = damaged; - if (damaged.getAmount() < toDamage.getAmount()) { - - newDamaged.setAmount(damaged.getAmount() + 1); - if (getQuestData(quest).blocksDamaged.contains(damaged)) { - getQuestData(quest).blocksDamaged.set(getQuestData(quest).blocksDamaged.indexOf(damaged), newDamaged); - if (damaged.getAmount() == toDamage.getAmount()) { - finishObjective(quest, new Objective(type, itemStack, toDamage), null, null, null, null, null, null, null); - - // Multiplayer - final ItemStack finalDamaged = damaged; - final ItemStack finalToDamage = toDamage; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).blocksDamaged.set(getQuestData(quest).blocksDamaged - .indexOf(finalDamaged), newDamaged); - q.finishObjective(quest, new Objective(type, itemStack, finalToDamage), null, null, null, null, null, - null, null); - return null; - }); - } - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newDamaged.getAmount(), toDamage.getAmount())); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks block as placed if Quester has such an objective - * - * @param quest The quest for which the block is being placed - * @param itemStack The block being placed - */ - @SuppressWarnings("deprecation") - public void placeBlock(final Quest quest, final ItemStack itemStack) { - itemStack.setAmount(0); - ItemStack placed = itemStack; - ItemStack toPlace = itemStack; - for (final ItemStack is : getQuestData(quest).blocksPlaced) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - placed = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - placed = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - placed = is; - } - } else { - // Blocks are not solid so ignore durability - placed = is; - } - } - } - for (final ItemStack is : getCurrentStage(quest).blocksToPlace) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toPlace = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - toPlace = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toPlace = is; - } - } else { - // Blocks are not solid so ignore durability - toPlace = is; - } - } - } - - final ObjectiveType type = ObjectiveType.PLACE_BLOCK; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, placed.getAmount(), toPlace.getAmount())); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final ItemStack newPlaced = placed; - if (placed.getAmount() < toPlace.getAmount()) { - newPlaced.setAmount(placed.getAmount() + 1); - if (getQuestData(quest).blocksPlaced.contains(placed)) { - getQuestData(quest).blocksPlaced.set(getQuestData(quest).blocksPlaced.indexOf(placed), newPlaced); - if (placed.getAmount() == toPlace.getAmount()) { - finishObjective(quest, new Objective(type, itemStack, toPlace), null, null, null, null, null, null, null); - - // Multiplayer - final ItemStack finalPlaced = placed; - final ItemStack finalToPlace = toPlace; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).blocksPlaced.set(getQuestData(quest).blocksPlaced - .indexOf(finalPlaced), newPlaced); - q.finishObjective(quest, new Objective(type, itemStack, finalToPlace), null, null, null, null, null, - null, null); - return null; - }); - } - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newPlaced.getAmount(), toPlace.getAmount())); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks block as used if Quester has such an objective - * - * @param quest The quest for which the block is being used - * @param itemStack The block being used - */ - @SuppressWarnings("deprecation") - public void useBlock(final Quest quest, final ItemStack itemStack) { - itemStack.setAmount(0); - ItemStack used = itemStack; - ItemStack toUse = itemStack; - for (final ItemStack is : getQuestData(quest).blocksUsed) { - if (itemStack.getType() == is.getType() ) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - used = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - used = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - used = is; - } - } else { - // Blocks are not solid so ignore durability - used = is; - } - } - } - for (final ItemStack is : getCurrentStage(quest).blocksToUse) { - if (itemStack.getType() == is.getType() ) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid, so check durability - if (itemStack.getDurability() == is.getDurability()) { - toUse = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - toUse = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toUse = is; - } - } else { - // Blocks are not solid, so ignore durability - toUse = is; - } - } - } - - final ObjectiveType type = ObjectiveType.USE_BLOCK; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, used.getAmount(), toUse.getAmount())); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final ItemStack newUsed = used; - if (used.getAmount() < toUse.getAmount()) { - newUsed.setAmount(used.getAmount() + 1); - if (getQuestData(quest).blocksUsed.contains(used)) { - getQuestData(quest).blocksUsed.set(getQuestData(quest).blocksUsed.indexOf(used), newUsed); - if (used.getAmount() == toUse.getAmount()) { - finishObjective(quest, new Objective(type, itemStack, toUse), null, null, null, null, null, null, null); - - // Multiplayer - final ItemStack finalUsed = used; - final ItemStack finalToUse = toUse; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).blocksUsed.set(getQuestData(quest).blocksUsed - .indexOf(finalUsed), newUsed); - q.finishObjective(quest, new Objective(type, itemStack, finalToUse), null, null, null, null, null, null, - null); - return null; - }); - } - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newUsed.getAmount(), toUse.getAmount())); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks block as cut if Quester has such an objective - * - * @param quest The quest for which the block is being cut - * @param itemStack The block being cut - */ - @SuppressWarnings("deprecation") - public void cutBlock(final Quest quest, final ItemStack itemStack) { - itemStack.setAmount(0); - ItemStack cut = itemStack; - ItemStack toCut = itemStack; - for (final ItemStack is : getQuestData(quest).blocksCut) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - cut = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - cut = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - cut = is; - } - } else { - // Blocks are not solid so ignore durability - cut = is; - } - } - } - for (final ItemStack is : getCurrentStage(quest).blocksToCut) { - if (itemStack.getType() == is.getType()) { - if (itemStack.getType().isSolid() && is.getType().isSolid()) { - // Blocks are solid so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toCut = is; - } else if (!plugin.getLocaleManager().isBelow113()) { - // Ignore durability for 1.13+ - toCut = is; - } - } else if (itemStack.getType().name().equals("RED_ROSE")) { - // Flowers are unique so check for durability - if (itemStack.getDurability() == is.getDurability()) { - toCut = is; - } - } else { - // Blocks are not solid so ignore durability - toCut = is; - } - } - } - - final ObjectiveType type = ObjectiveType.CUT_BLOCK; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, cut.getAmount(), toCut.getAmount())); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final ItemStack newCut = cut; - if (cut.getAmount() < toCut.getAmount()) { - newCut.setAmount(cut.getAmount() + 1); - if (getQuestData(quest).blocksCut.contains(cut)) { - getQuestData(quest).blocksCut.set(getQuestData(quest).blocksCut.indexOf(cut), newCut); - if (cut.getAmount() == toCut.getAmount()) { - finishObjective(quest, new Objective(type, itemStack, toCut), null, null, null, null, null, null, null); - - // Multiplayer - final ItemStack finalCut = cut; - final ItemStack finalToCut = toCut; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).blocksCut.set(getQuestData(quest).blocksCut.indexOf(finalCut), newCut); - q.finishObjective(quest, new Objective(type, itemStack, finalToCut), null, null, null, null, null, null, - null); - return null; - }); - } - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newCut.getAmount(), toCut.getAmount())); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark item as crafted if Quester has such an objective - * - * @param quest The quest for which the item is being crafted - * @param itemStack The item being crafted - */ - public void craftItem(final Quest quest, final ItemStack itemStack) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsCrafted) { - currentIndex++; - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsCrafted); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toCraft = getCurrentStage(quest).itemsToCraft.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.CRAFT_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toCraft)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toCraft) { - if (newAmount >= toCraft) { - found.setAmount(toCraft); - getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newAmount, toCraft)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark item as smelted if Quester has such an objective - * - * @param quest The quest for which the item is being smelted - * @param itemStack The item being smelted - */ - public void smeltItem(final Quest quest, final ItemStack itemStack) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsSmelted) { - currentIndex++; - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsSmelted); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toSmelt = getCurrentStage(quest).itemsToSmelt.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.SMELT_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toSmelt)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toSmelt) { - if (newAmount >= toSmelt) { - found.setAmount(toSmelt); - getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newAmount, toSmelt)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark book as enchanted if Quester has such an objective - * - * @param quest The quest for which the item is being enchanted - * @param itemStack The book being enchanted - */ - public void enchantBook(final Quest quest, final ItemStack itemStack, - final Map enchantsToAdd) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsEnchanted) { - currentIndex++; - if (is.getItemMeta() instanceof EnchantmentStorageMeta) { - if (((EnchantmentStorageMeta)is.getItemMeta()).getStoredEnchants().equals(enchantsToAdd)) { - matches.add(currentIndex); - } - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsEnchanted); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toEnchant = getCurrentStage(quest).itemsToEnchant.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.ENCHANT_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toEnchant)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toEnchant) { - if (newAmount >= toEnchant) { - found.setAmount(toEnchant); - getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, itemStack.getAmount() + amount, toEnchant)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark item as enchanted if Quester has such an objective - * - * @param quest The quest for which the item is being enchanted - * @param itemStack The item being enchanted - */ - public void enchantItem(final Quest quest, final ItemStack itemStack) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - if (!itemStack.getType().equals(Material.BOOK)) { - for (final ItemStack is : getQuestData(quest).itemsEnchanted) { - currentIndex++; - if (!is.getEnchantments().isEmpty()) { - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } else { - if (ItemUtil.compareItems(itemStack, is, true) == -4) { - matches.add(currentIndex); - } - } - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsEnchanted); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toEnchant = getCurrentStage(quest).itemsToEnchant.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.ENCHANT_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toEnchant)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toEnchant) { - if (newAmount >= toEnchant) { - found.setAmount(toEnchant); - getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, itemStack.getAmount() + amount, toEnchant)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark item as brewed if Quester has such an objective - * - * @param quest The quest for which the item is being brewed - * @param itemStack The item being brewed - */ - public void brewItem(final Quest quest, final ItemStack itemStack) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsBrewed) { - currentIndex++; - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsBrewed); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toBrew = getCurrentStage(quest).itemsToBrew.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.BREW_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toBrew)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toBrew) { - if (newAmount >= toBrew) { - found.setAmount(toBrew); - getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newAmount, toBrew)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark item as consumed if Quester has such an objective - * - * @param quest The quest for which the item is being consumed - * @param itemStack The item being consumed - */ - public void consumeItem(final Quest quest, final ItemStack itemStack) { - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsConsumed) { - currentIndex++; - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } - if (matches.isEmpty()) { - return; - } - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsConsumed); - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toConsume = getCurrentStage(quest).itemsToConsume.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.CONSUME_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toConsume)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toConsume) { - if (newAmount >= toConsume) { - found.setAmount(toConsume); - getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); - } - return; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newAmount, toConsume)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark item as delivered to a NPC if Quester has such an objective - * - * @param quest The quest for which the item is being delivered - * @param npc The NPC being delivered to - * @param itemStack The item being delivered - */ - public void deliverToNPC(final Quest quest, final NPC npc, final ItemStack itemStack) { - if (npc == null) { - return; - } - - int currentIndex = -1; - final LinkedList matches = new LinkedList<>(); - for (final ItemStack is : getQuestData(quest).itemsDelivered) { - currentIndex++; - if (ItemUtil.compareItems(itemStack, is, true) == 0) { - matches.add(currentIndex); - } - } - if (matches.isEmpty()) { - return; - } - final Player player = getPlayer(); - for (final Integer match : matches) { - final LinkedList items = new LinkedList<>(getQuestData(quest).itemsDelivered); - if (!getCurrentStage(quest).getItemDeliveryTargets().get(match).equals(npc.getId())) { - continue; - } - final ItemStack found = items.get(match); - final int amount = found.getAmount(); - final int toDeliver = getCurrentStage(quest).itemsToDeliver.get(match).getAmount(); - - final ObjectiveType type = ObjectiveType.DELIVER_ITEM; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, amount, toDeliver)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newAmount = itemStack.getAmount() + amount; - final Material m = itemStack.getType(); - if (amount < toDeliver) { - final int index = player.getInventory().first(itemStack); - if (index == -1) { - // Already delivered in previous loop - return; - } - if (newAmount >= toDeliver) { - found.setAmount(toDeliver); - getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); - if ((itemStack.getAmount() + amount) >= toDeliver) { - // Take away remaining amount to be delivered - final ItemStack clone = itemStack.clone(); - clone.setAmount(itemStack.getAmount() - (toDeliver - amount)); - player.getInventory().setItem(index, clone); - } else { - player.getInventory().setItem(index, null); - } - player.updateInventory(); - finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, null, - null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); - q.finishObjective(quest, new Objective(type, new ItemStack(m, 1), found), null, null, null, - null, null, null, null); - return null; - }); - } else { - found.setAmount(newAmount); - getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); - player.getInventory().setItem(index, null); - player.updateInventory(); - final String[] message = ConfigUtil.parseStringWithPossibleLineBreaks(getCurrentStage(quest) - .deliverMessages.get(new Random().nextInt(getCurrentStage(quest).deliverMessages - .size())), plugin.getDependencies().getCitizens().getNPCRegistry() - .getById(getCurrentStage(quest).itemDeliveryTargets.get(items.indexOf(found)))); - player.sendMessage(message); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newAmount, toDeliver)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark NPC as interacted with if Quester has such an objective - * - * @param quest The quest for which the NPC is being interacted with - * @param npc The NPC being interacted with - */ - public void interactWithNPC(final Quest quest, final NPC npc) { - if (!getCurrentStage(quest).getCitizensToInteract().contains(npc.getId())) { - return; - } - - final int index = getCurrentStage(quest).getCitizensToInteract().indexOf(npc.getId()); - final boolean npcsInteracted = getQuestData(quest).citizensInteracted.get(index); - - final ObjectiveType type = ObjectiveType.TALK_TO_NPC; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, 1, 1)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - if (!npcsInteracted) { - getQuestData(quest).citizensInteracted.set(index, true); - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), new ItemStack(Material.AIR, 1)), - null, null, npc, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).citizensInteracted.set(index, true); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, 1)), null, null, npc, null, null, null, null); - return null; - }); - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, 1, 1)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - } - - /** - * Mark NPC as killed if the Quester has such an objective - * - * @param quest The quest for which the NPC is being killed - * @param npc The NPC being killed - */ - public void killNPC(final Quest quest, final NPC npc) { - if (!getCurrentStage(quest).getCitizensToKill().contains(npc.getId())) { - return; - } - - final int index = getCurrentStage(quest).getCitizensToKill().indexOf(npc.getId()); - final int npcsKilled = getQuestData(quest).citizensNumKilled.get(index); - final int npcsToKill = getCurrentStage(quest).citizenNumToKill.get(index); - - final ObjectiveType type = ObjectiveType.KILL_NPC; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, npcsKilled, npcsToKill)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newNpcsKilled = getQuestData(quest).citizensNumKilled.get(index) + 1; - if (npcsKilled < npcsToKill) { - getQuestData(quest).citizensNumKilled.set(index, newNpcsKilled); - if (newNpcsKilled >= npcsToKill) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, npcsToKill)), null, null, npc, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).citizensNumKilled.set(index, getQuestData(quest).citizensNumKilled - .get(index)); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, npcsToKill)), null, null, npc, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newNpcsKilled, npcsToKill)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks cow as milked if Quester has such an objective - * - * @param quest The quest for which the fish is being caught - */ - public void milkCow(final Quest quest) { - final QuestData questData = getQuestData(quest); - if (questData == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage == null) { - return; - } - if (currentStage.cowsToMilk == null) { - return; - } - - final int cowsMilked = questData.getCowsMilked(); - final int cowsToMilk = currentStage.cowsToMilk; - - final ObjectiveType type = ObjectiveType.MILK_COW; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, cowsMilked, cowsToMilk)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newCowsMilked = cowsMilked + 1; - if (cowsMilked < cowsToMilk) { - questData.setCowsMilked(newCowsMilked); - - if (newCowsMilked >= cowsToMilk) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, cowsToMilk)), null, null, null, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).setCowsMilked(cowsToMilk); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, cowsToMilk)), null, null, null, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newCowsMilked, cowsToMilk)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Marks fish as caught if Quester has such an objective - * - * @param quest The quest for which the fish is being caught - */ - public void catchFish(final Quest quest) { - final QuestData questData = getQuestData(quest); - if (questData == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage == null) { - return; - } - if (currentStage.fishToCatch == null) { - return; - } - - final int fishCaught = questData.getFishCaught(); - final int fishToCatch = currentStage.fishToCatch; - - final ObjectiveType type = ObjectiveType.CATCH_FISH; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, fishCaught, fishToCatch)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newFishCaught = fishCaught + 1; - if (fishCaught < fishToCatch) { - questData.setFishCaught(newFishCaught); - - if (newFishCaught >= fishToCatch) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, fishToCatch)), null, null, null, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).setFishCaught(fishToCatch); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, fishToCatch)), null, null, null, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newFishCaught, fishToCatch)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark mob as killed if Quester has such an objective - * - * @param quest The quest for which the mob is being killed - * @param killedLocation The optional location to kill at - * @param entityType The mob to be killed - */ - public void killMob(final Quest quest, final Location killedLocation, final EntityType entityType) { - final QuestData questData = getQuestData(quest); - if (entityType == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage.mobsToKill == null) { - return; - } - final int index = currentStage.getMobsToKill().indexOf(entityType); - if (index == -1) { - return; - } - final int mobsKilled = questData.mobNumKilled.get(index); - final int mobsToKill = currentStage.mobNumToKill.get(index); - if (!currentStage.locationsToKillWithin.isEmpty()) { - final Location locationToKillWithin = currentStage.locationsToKillWithin.get(index); - final double radius = currentStage.radiiToKillWithin.get(index); - if (killedLocation.getWorld() == null || locationToKillWithin.getWorld() == null) { - return; - } - if (!(killedLocation.getWorld().getName().equals(locationToKillWithin.getWorld().getName()))) { - return; - } - if (!(killedLocation.getX() < (locationToKillWithin.getX() + radius) && killedLocation.getX() - > (locationToKillWithin.getX() - radius))) { - return; - } - if (!(killedLocation.getZ() < (locationToKillWithin.getZ() + radius) && killedLocation.getZ() - > (locationToKillWithin.getZ() - radius))) { - return; - } - if (!(killedLocation.getY() < (locationToKillWithin.getY() + radius) && killedLocation.getY() - > (locationToKillWithin.getY() - radius))) { - return; - } - } - final ObjectiveType type = ObjectiveType.KILL_MOB; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, mobsKilled, mobsToKill)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newMobsKilled = mobsKilled + 1; - if (mobsKilled < mobsToKill) { - questData.mobNumKilled.set(index, newMobsKilled); - if (newMobsKilled >= mobsToKill) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, mobsToKill)), entityType, null, null, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, currentStage, (final Quester q) -> { - q.getQuestData(quest).mobNumKilled.set(index, newMobsKilled); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, mobsToKill)), entityType, null, null, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newMobsKilled, mobsToKill)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark player as killed if Quester has such an objective - * - * @param quest The quest for which the player is being killed - * @param player The player to be killed - */ - public void killPlayer(final Quest quest, final Player player) { - final QuestData questData = getQuestData(quest); - if (questData == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage == null) { - return; - } - if (currentStage.playersToKill == null) { - return; - } - - final int playersKilled = questData.getPlayersKilled(); - final int playersToKill = currentStage.playersToKill; - - final ObjectiveType type = ObjectiveType.KILL_PLAYER; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, playersKilled, playersToKill)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newPlayersKilled = playersKilled + 1; - if (playersKilled < playersToKill) { - questData.setPlayersKilled(newPlayersKilled); - if (newPlayersKilled >= playersToKill) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, playersToKill)), null, null, null, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).setPlayersKilled(getQuestData(quest).getPlayersKilled()); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, playersToKill)), null, null, null, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newPlayersKilled, playersToKill)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark location as reached if the Quester has such an objective - * - * @param quest The quest for which the location is being reached - * @param location The location being reached - */ - public void reachLocation(final Quest quest, final Location location) { - if (getQuestData(quest) == null || getCurrentStage(quest) == null - || getCurrentStage(quest).locationsToReach == null || getQuestData(quest).locationsReached == null) { - return; - } - - // TODO redo this - int locationsReached = 0; - for (final Boolean b : getQuestData(quest).locationsReached) { - if (b) { - locationsReached++; - } - } - final int locationsToReach = getCurrentStage(quest).locationsToReach.size(); - - int index = 0; - try { - for (final Location toReach : getCurrentStage(quest).locationsToReach) { - if (location.getWorld() == null || toReach.getWorld() == null) { - index++; - continue; - } - if (!location.getWorld().getName().equals(toReach.getWorld().getName())) { - index++; - continue; - } - final double radius = getCurrentStage(quest).radiiToReachWithin.get(index); - if (toReach.distanceSquared(location) <= radius * radius) { - if (!getQuestData(quest).locationsReached.get(index)) { - final ObjectiveType type = ObjectiveType.REACH_LOCATION; - final QuesterPreUpdateObjectiveEvent preEvent - = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, locationsReached, locationsToReach)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - getQuestData(quest).locationsReached.set(index, true); - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, 1)), null, null, null, toReach, null, null, - null); - - // Multiplayer - final int finalIndex = index; - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).locationsReached.set(finalIndex, true); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, 1)), null, null, null, toReach, null, - null, null); - return null; - }); - - final QuesterPostUpdateObjectiveEvent postEvent - = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, locationsReached + 1, locationsToReach)); - plugin.getServer().getPluginManager().callEvent(postEvent); - - break; - } - } - index++; - } - } catch (final Exception e) { - plugin.getLogger().severe("An error has occurred with Quests. Please report on Github with info below"); - plugin.getLogger().warning("quest = " + quest.getId()); - plugin.getLogger().warning("index = " + index); - plugin.getLogger().warning("location = " + location.toString()); - plugin.getLogger().warning("locationsToReach = " + getCurrentStage(quest).locationsToReach.size()); - plugin.getLogger().warning("locationsReached = " + getQuestData(quest).locationsReached.size()); - plugin.getLogger().warning("hasReached = " + getQuestData(quest).locationsReached.size()); - e.printStackTrace(); - } - } - - /** - * Mark mob as tamed if the Quester has such an objective - * - * @param quest The quest for which the mob is being tamed - * @param entityType The type of mob being tamed - */ - public void tameMob(final Quest quest, final EntityType entityType) { - final QuestData questData = getQuestData(quest); - if (entityType == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage.mobsToTame == null) { - return; - } - - final int index = currentStage.mobsToTame.indexOf(entityType); - if (index == -1) { - return; - } - - final int mobsToTame = currentStage.mobNumToTame.get(index); - final int mobsTamed = questData.mobsTamed.get(index); - - final ObjectiveType type = ObjectiveType.TAME_MOB; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, mobsToTame, mobsTamed)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newMobsToTame = mobsTamed + 1; - if (mobsTamed < mobsToTame) { - getQuestData(quest).mobsTamed.set(index, newMobsToTame); - if (newMobsToTame >= mobsToTame) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, mobsToTame)), entityType, null, null, null, null, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).mobsTamed.set(index, newMobsToTame); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, mobsToTame)), entityType, null, null, null, null, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newMobsToTame, mobsTamed)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark sheep as sheared if the Quester has such an objective - * - * @param quest The quest for which the sheep is being sheared - * @param color The wool color of the sheep being sheared - */ - public void shearSheep(final Quest quest, final DyeColor color) { - final QuestData questData = getQuestData(quest); - if (color == null) { - return; - } - final Stage currentStage = getCurrentStage(quest); - if (currentStage.sheepToShear == null) { - return; - } - - final int index = currentStage.sheepToShear.indexOf(color); - if (index == -1) { - return; - } - - final int sheepToShear = getCurrentStage(quest).sheepNumToShear.get(index); - final int sheepSheared = questData.sheepSheared.get(index); - - final ObjectiveType type = ObjectiveType.SHEAR_SHEEP; - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, sheepSheared, sheepToShear)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - final int newSheepSheared = sheepSheared + 1; - if (sheepSheared < sheepToShear) { - getQuestData(quest).sheepSheared.set(index, newSheepSheared); - if (newSheepSheared >= sheepToShear) { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, sheepToShear)), null, null, null, null, color, null, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).sheepSheared.set(index, newSheepSheared); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, sheepToShear)), null, null, null, null, color, null, null); - return null; - }); - } - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, newSheepSheared, sheepToShear)); - plugin.getServer().getPluginManager().callEvent(postEvent); - } - - /** - * Mark password as entered if the Quester has such an objective - * - * @param quest The quest for which the password is being entered - * @param evt The event during which the password was entered - */ - public void sayPassword(final Quest quest, final AsyncPlayerChatEvent evt) { - final ObjectiveType type = ObjectiveType.PASSWORD; - plugin.getServer().getScheduler().runTask(plugin, () -> { - final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, - new Objective(type, 1, 1)); - plugin.getServer().getPluginManager().callEvent(preEvent); - - int index = 0; - for (final String pass : getCurrentStage(quest).passwordPhrases) { - if (pass.equalsIgnoreCase(evt.getMessage())) { - final String display = getCurrentStage(quest).passwordDisplays.get(index); - getQuestData(quest).passwordsSaid.set(index, true); - - final int finalIndex = index; - plugin.getServer().getScheduler().runTask(plugin, () -> { - finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, 1)), null, null, null, null, null, display, null); - - // Multiplayer - dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final Quester q) -> { - q.getQuestData(quest).passwordsSaid.set(finalIndex, true); - q.finishObjective(quest, new Objective(type, new ItemStack(Material.AIR, 1), - new ItemStack(Material.AIR, 1)), null, null, null, null, null, display, null); - return null; - }); - }); - break; - } - index++; - } - - final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, - new Objective(type, 1, 1)); - plugin.getServer().getPluginManager().callEvent(postEvent); - }); - } - - /** - * Complete a quest objective - * - * @param quest - * Quest containing the objective - * @param objective - * Objective for type, progress and goal - * @param mob - * Mob being killed or tamed, if any - * @param extra - * Extra mob enum like career or ocelot type, if any - * @param npc - * NPC being talked to or killed, if any - * @param location - * Location for user to reach, if any - * @param color - * Shear color, if any - * @param pass - * Password, if any - * @param co - * Custom objective, if any. See {@link me.blackvein.quests.CustomObjective} - */ - @SuppressWarnings("deprecation") - public void finishObjective(final Quest quest, final Objective objective, final EntityType mob, final String extra, - final NPC npc, final Location location, final DyeColor color, final String pass, final CustomObjective co) { - if (objective == null) { - return; - } - final Player p = getPlayer(); - final ObjectiveType type = objective.getType(); - final ItemStack increment = objective.getItemProgress() != null ? objective.getItemProgress() - : new ItemStack(Material.AIR, objective.getProgress()); - final ItemStack goal = objective.getItemGoal() != null ? objective.getItemGoal() - : new ItemStack(Material.AIR, objective.getGoal()); - if (!getCurrentStage(quest).objectiveOverrides.isEmpty()) { - for (final String s: getCurrentStage(quest).objectiveOverrides) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " - + ConfigUtil.parseString(ChatColor.translateAlternateColorCodes('&', s), quest, p); - if (plugin.getDependencies().getPlaceholderApi() != null) { - message = PlaceholderAPI.setPlaceholders(p, message); - } - sendMessage(message); - } - } else if (type.equals(ObjectiveType.BREAK_BLOCK)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "break"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else if (type.equals(ObjectiveType.DAMAGE_BLOCK)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "damage"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else if (type.equals(ObjectiveType.PLACE_BLOCK)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "place"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else if (type.equals(ObjectiveType.USE_BLOCK)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "use"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else if (type.equals(ObjectiveType.CUT_BLOCK)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "cut"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(increment))); - } - } else if (type.equals(ObjectiveType.CRAFT_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToCraft.get(getCurrentStage(quest).itemsToCraft.indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "craftItem"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (type.equals(ObjectiveType.SMELT_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToSmelt.get(getCurrentStage(quest).itemsToSmelt.indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "smeltItem"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (type.equals(ObjectiveType.ENCHANT_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToEnchant.get(getCurrentStage(quest).itemsToEnchant.indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "enchItem"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && is.hasItemMeta() && !is.getItemMeta().hasDisplayName()) { - // Bukkit version is 1.9+ - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), - goal.getEnchantments(), goal.getItemMeta())) { - for (final Entry e : is.getEnchantments().entrySet()) { - sendMessage(message.replace("", ItemUtil.getName(is)) - .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) - .replace("", RomanNumeral.getNumeral(e.getValue()))); - } - } - } else if (plugin.getSettings().canTranslateNames() && !is.hasItemMeta() - && Material.getMaterial("LINGERING_POTION") == null) { - // Bukkit version is below 1.9 - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), - goal.getEnchantments())) { - for (final Entry e : is.getEnchantments().entrySet()) { - sendMessage(message.replace("", ItemUtil.getName(is)) - .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) - .replace("", RomanNumeral.getNumeral(e.getValue()))); - } - } - } else { - for (final Entry e : is.getEnchantments().entrySet()) { - sendMessage(message.replace("", ItemUtil.getName(is)) - .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) - .replace("", RomanNumeral.getNumeral(e.getValue()))); - } - } - } else if (type.equals(ObjectiveType.BREW_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToBrew.get(getCurrentStage(quest).itemsToBrew.indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "brewItem"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && is.hasItemMeta() && !is.getItemMeta().hasDisplayName()) { - // Bukkit version is 1.9+ - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), - goal.getEnchantments(), goal.getItemMeta())) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (plugin.getSettings().canTranslateNames() && !is.hasItemMeta() - && Material.getMaterial("LINGERING_POTION") == null) { - // Bukkit version is below 1.9 - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), - goal.getEnchantments())) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (type.equals(ObjectiveType.CONSUME_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToConsume.get(getCurrentStage(quest).itemsToConsume - .indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "consumeItem"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (type.equals(ObjectiveType.DELIVER_ITEM)) { - final ItemStack is = getCurrentStage(quest).itemsToDeliver.get(getCurrentStage(quest).itemsToDeliver - .indexOf(goal)); - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "deliver") - .replace("", plugin.getDependencies().getNPCName(getCurrentStage(quest).itemDeliveryTargets - .get(getCurrentStage(quest).itemsToDeliver.indexOf(goal)))); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); - } - if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() - && !goal.getItemMeta().hasDisplayName()) { - if (!plugin.getLocaleManager().sendMessage(p, message, is.getType(), is.getDurability(), null)) { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else { - sendMessage(message.replace("", ItemUtil.getName(is))); - } - } else if (type.equals(ObjectiveType.MILK_COW)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "milkCow"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - sendMessage(message); - } else if (type.equals(ObjectiveType.CATCH_FISH)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "catchFish"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - sendMessage(message); - } else if (type.equals(ObjectiveType.KILL_MOB)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "kill"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.AQUA + " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" - + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames()) { - if (!plugin.getLocaleManager().sendMessage(p, message, mob, extra)) { - sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); - } - } else { - sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); - } - } else if (type.equals(ObjectiveType.KILL_PLAYER)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "killPlayer"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - sendMessage(message); - } else if (type.equals(ObjectiveType.TALK_TO_NPC)) { - final String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "talkTo") - .replace("", plugin.getDependencies().getNPCName(npc.getId())); - sendMessage(message); - } else if (type.equals(ObjectiveType.KILL_NPC)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "kill"); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.AQUA + " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" - + goal.getAmount(); - } - sendMessage(message.replace("", plugin.getDependencies().getNPCName(npc.getId()))); - } else if (type.equals(ObjectiveType.TAME_MOB)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "tame"); - if (!message.contains("")) { - message += " "; - } - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - if (plugin.getSettings().canTranslateNames()) { - if (!plugin.getLocaleManager().sendMessage(p, message, mob, extra)) { - sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); - } - } else { - sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); - } - } else if (type.equals(ObjectiveType.SHEAR_SHEEP)) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "shearSheep"); - message = message.replace("", MiscUtil.getPrettyDyeColorName(color)); - if (message.contains("")) { - message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); - } else { - // Legacy - message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); - } - sendMessage(message); - } else if (type.equals(ObjectiveType.REACH_LOCATION)) { - String obj = Lang.get(p, "goTo"); - try { - obj = obj.replace("", getCurrentStage(quest).locationNames.get(getCurrentStage(quest) - .locationsToReach.indexOf(location))); - } catch(final IndexOutOfBoundsException e) { - plugin.getLogger().severe("Unable to get final location " + location + " for quest ID " - + quest.getId() + ", please report on Github"); - obj = obj.replace("", "ERROR"); - } - final String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + obj; - sendMessage(message); - } else if (type.equals(ObjectiveType.PASSWORD)) { - sendMessage(ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + pass); - } else if (co != null) { - String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + co.getDisplay(); - int index = -1; - for (int i = 0; i < getCurrentStage(quest).customObjectives.size(); i++) { - if (getCurrentStage(quest).customObjectives.get(i).getName().equals(co.getName())) { - index = i; - break; - } - } - final List> sub = new LinkedList<>(getCurrentStage(quest).customObjectiveData.subList(index, getCurrentStage(quest) - .customObjectiveData.size())); - final List> end = new LinkedList<>(sub); - sub.clear(); // Since sub is backed by end, this removes all sub-list items from end - for (final Entry dataMap : end) { - message = message.replace("%" + (dataMap.getKey()) + "%", String.valueOf(dataMap.getValue())); - } - - if (co.canShowCount()) { - message = message.replace("%count%", goal.getAmount() + "/" + goal.getAmount()); - } - sendMessage(ConfigUtil.parseString(ChatColor.translateAlternateColorCodes('&', message))); - } - if (testComplete(quest)) { - quest.nextStage(this, true); - } - } - - /** - * Complete quest objective - * - * @deprecated Use {@link #finishObjective(Quest, Objective, EntityType, - * String, NPC, Location, DyeColor, String, CustomObjective)} - * - * @param quest - * Quest containing the objective - * @param objective - * Type of objective, e.g. "password" or "damageBlock" - * @param increment - * Final amount material being applied - * @param goal - * Total required amount of material - * @param enchantment - * Enchantment being applied by user - * @param mob - * Mob being killed or tamed - * @param extra - * Extra mob enum like career or ocelot type - * @param npc - * NPC being talked to or killed - * @param location - * Location for user to reach - * @param color - * Shear color - * @param pass - * Password - * @param co - * See CustomObjective class - */ - @Deprecated - public void finishObjective(final Quest quest, final String objective, final ItemStack increment, - final ItemStack goal, final Enchantment enchantment, final EntityType mob, final String extra, - final NPC npc, final Location location, final DyeColor color, final String pass, final CustomObjective co) { - if (objective == null) { - return; - } - if (increment == null || goal == null) { - finishObjective(quest, new Objective(ObjectiveType.fromName(objective), 1, 1), mob, extra, npc, - location, color, pass, co); - } else { - finishObjective(quest, new Objective(ObjectiveType.fromName(objective), increment, goal), mob, extra, npc, - location, color, pass, co); - } - } - - /** - * Check whether this Quester has completed all objectives for their current stage - * - * @param quest The quest with the current stage being checked - * @return true if all stage objectives are marked complete - */ - public boolean testComplete(final Quest quest) { - for (final String s : getCurrentObjectives(quest, true)) { - if (s.startsWith(ChatColor.GREEN.toString())) { - return false; - } - } - return true; - } - - /** - * Add empty map values per Quest stage - * - * @param quest Quest with at least one stage - * @param stage Where first stage is '0' - */ - @SuppressWarnings("deprecation") - public void addEmptiesFor(final Quest quest, final int stage) { - final QuestData data = new QuestData(this); - data.setDoJournalUpdate(false); - if (quest == null) { - plugin.getLogger().warning("Unable to find quest for player " + this.lastKnownName); - return; - } - if (quest.getStage(stage) == null) { - plugin.getLogger().severe("Unable to find Stage " + stage + " of quest ID " + quest.getId()); - return; - } - if (!quest.getStage(stage).blocksToBreak.isEmpty()) { - for (final ItemStack toBreak : quest.getStage(stage).blocksToBreak) { - final ItemStack temp = new ItemStack(toBreak.getType(), 0, toBreak.getDurability()); - if (data.blocksBroken.contains(toBreak)) { - data.blocksBroken.set(data.blocksBroken.indexOf(temp), temp); - } else { - data.blocksBroken.add(temp); - } - } - } - if (!quest.getStage(stage).blocksToDamage.isEmpty()) { - for (final ItemStack toDamage : quest.getStage(stage).blocksToDamage) { - final ItemStack temp = new ItemStack(toDamage.getType(), 0, toDamage.getDurability()); - if (data.blocksDamaged.contains(toDamage)) { - data.blocksDamaged.set(data.blocksDamaged.indexOf(temp), temp); - } else { - data.blocksDamaged.add(temp); - } - } - } - if (!quest.getStage(stage).blocksToPlace.isEmpty()) { - for (final ItemStack toPlace : quest.getStage(stage).blocksToPlace) { - final ItemStack temp = new ItemStack(toPlace.getType(), 0, toPlace.getDurability()); - if (data.blocksPlaced.contains(toPlace)) { - data.blocksPlaced.set(data.blocksPlaced.indexOf(temp), temp); - } else { - data.blocksPlaced.add(temp); - } - } - } - if (!quest.getStage(stage).blocksToUse.isEmpty()) { - for (final ItemStack toUse : quest.getStage(stage).blocksToUse) { - final ItemStack temp = new ItemStack(toUse.getType(), 0, toUse.getDurability()); - if (data.blocksUsed.contains(toUse)) { - data.blocksUsed.set(data.blocksUsed.indexOf(temp), temp); - } else { - data.blocksUsed.add(temp); - } - } - } - if (!quest.getStage(stage).blocksToCut.isEmpty()) { - for (final ItemStack toCut : quest.getStage(stage).blocksToCut) { - final ItemStack temp = new ItemStack(toCut.getType(), 0, toCut.getDurability()); - if (data.blocksCut.contains(toCut)) { - data.blocksCut.set(data.blocksCut.indexOf(temp), temp); - } else { - data.blocksCut.add(temp); - } - } - } - if (!quest.getStage(stage).itemsToCraft.isEmpty()) { - for (final ItemStack toCraft : quest.getStage(stage).itemsToCraft) { - final ItemStack temp = new ItemStack(toCraft.getType(), 0, toCraft.getDurability()); - temp.addUnsafeEnchantments(toCraft.getEnchantments()); - temp.setItemMeta(toCraft.getItemMeta()); - data.itemsCrafted.add(temp); - } - } - if (!quest.getStage(stage).itemsToSmelt.isEmpty()) { - for (final ItemStack toSmelt : quest.getStage(stage).itemsToSmelt) { - final ItemStack temp = new ItemStack(toSmelt.getType(), 0, toSmelt.getDurability()); - temp.addUnsafeEnchantments(toSmelt.getEnchantments()); - temp.setItemMeta(toSmelt.getItemMeta()); - data.itemsSmelted.add(temp); - } - } - if (!quest.getStage(stage).itemsToEnchant.isEmpty()) { - for (final ItemStack toEnchant : quest.getStage(stage).itemsToEnchant) { - final ItemStack temp = new ItemStack(toEnchant.getType(), 0, toEnchant.getDurability()); - temp.addUnsafeEnchantments(toEnchant.getEnchantments()); - temp.setItemMeta(toEnchant.getItemMeta()); - data.itemsEnchanted.add(temp); - } - } - if (!quest.getStage(stage).itemsToBrew.isEmpty()) { - for (final ItemStack toBrew : quest.getStage(stage).itemsToBrew) { - final ItemStack temp = new ItemStack(toBrew.getType(), 0, toBrew.getDurability()); - temp.addUnsafeEnchantments(toBrew.getEnchantments()); - temp.setItemMeta(toBrew.getItemMeta()); - data.itemsBrewed.add(temp); - } - } - if (!quest.getStage(stage).itemsToConsume.isEmpty()) { - for (final ItemStack toConsume : quest.getStage(stage).itemsToConsume) { - final ItemStack temp = new ItemStack(toConsume.getType(), 0, toConsume.getDurability()); - temp.addUnsafeEnchantments(toConsume.getEnchantments()); - temp.setItemMeta(toConsume.getItemMeta()); - data.itemsConsumed.add(temp); - } - } - if (!quest.getStage(stage).itemsToDeliver.isEmpty()) { - for (final ItemStack toDeliver : quest.getStage(stage).itemsToDeliver) { - final ItemStack temp = new ItemStack(toDeliver.getType(), 0, toDeliver.getDurability()); - temp.addUnsafeEnchantments(toDeliver.getEnchantments()); - temp.setItemMeta(toDeliver.getItemMeta()); - data.itemsDelivered.add(temp); - } - } - if (!quest.getStage(stage).citizensToInteract.isEmpty()) { - for (final Integer ignored : quest.getStage(stage).citizensToInteract) { - data.citizensInteracted.add(false); - } - } - if (!quest.getStage(stage).citizensToKill.isEmpty()) { - for (final Integer ignored : quest.getStage(stage).citizensToKill) { - data.citizensNumKilled.add(0); - } - } - if (!quest.getStage(stage).mobsToKill.isEmpty()) { - for (final EntityType ignored : quest.getStage(stage).mobsToKill) { - data.mobNumKilled.add(0); - } - } - data.setCowsMilked(0); - data.setFishCaught(0); - data.setPlayersKilled(0); - if (!quest.getStage(stage).locationsToReach.isEmpty()) { - for (final Location ignored : quest.getStage(stage).locationsToReach) { - data.locationsReached.add(false); - } - } - if (!quest.getStage(stage).mobsToTame.isEmpty()) { - for (final EntityType ignored : quest.getStage(stage).mobsToTame) { - data.mobsTamed.add(0); - } - } - if (!quest.getStage(stage).sheepToShear.isEmpty()) { - for (final DyeColor ignored : quest.getStage(stage).sheepToShear) { - data.sheepSheared.add(0); - } - } - if (!quest.getStage(stage).passwordDisplays.isEmpty()) { - for (final String ignored : quest.getStage(stage).passwordDisplays) { - data.passwordsSaid.add(false); - } - } - if (!quest.getStage(stage).customObjectives.isEmpty()) { - for (final CustomObjective ignored : quest.getStage(stage).customObjectives) { - data.customObjectiveCounts.add(0); - } - } - data.setDoJournalUpdate(true); - hardDataPut(quest, data); - } - - - /** - * Save data of the Quester to file - * - * @return true if successful - */ - public boolean saveData() { - try { - final Storage storage = plugin.getStorage(); - storage.saveQuester(this); - } catch (final Exception e) { - return false; - } - return true; - } - - /** - * Get the difference between System.currentTimeMillis() and the last completed time for a quest - * - * @param quest The quest to get the last completed time of - * @return Difference between now and then in milliseconds - */ - public long getCompletionDifference(final Quest quest) { - final long currentTime = System.currentTimeMillis(); - final long lastTime; - if (!completedTimes.containsKey(quest)) { - lastTime = System.currentTimeMillis(); - completedTimes.put(quest, System.currentTimeMillis()); - } else { - lastTime = completedTimes.get(quest); - } - return currentTime - lastTime; - } - - /** - * Get the difference between player cooldown and time since last completion of a quest - * - * @deprecated Use {@link #getRemainingCooldown(Quest)} - * @param quest The quest to get the last completed time of - * @return Difference between now and then in milliseconds - */ - @Deprecated - public long getCooldownDifference(final Quest quest) { - return quest.getPlanner().getCooldown() - getCompletionDifference(quest); - } - - /** - * Get the amount of time left before Quester may take a completed quest again - * - * @param quest The quest to calculate the cooldown for - * @return Length of time in milliseconds - */ - public long getRemainingCooldown(final Quest quest) { - return quest.getPlanner().getCooldown() - getCompletionDifference(quest); - } - - public FileConfiguration getBaseData() { - final FileConfiguration data = new YamlConfiguration(); - if (!currentQuests.isEmpty()) { - final ArrayList questIds = new ArrayList<>(); - final ArrayList questStages = new ArrayList<>(); - for (final Quest quest : currentQuests.keySet()) { - questIds.add(quest.getId()); - questStages.add(currentQuests.get(quest)); - } - data.set("currentQuests", questIds); - data.set("currentStages", questStages); - data.set("quest-points", questPoints); - final ConfigurationSection dataSec = data.createSection("questData"); - for (final Quest quest : currentQuests.keySet()) { - if (quest.getName() == null || quest.getName().isEmpty()) { - plugin.getLogger().severe("Quest name was null or empty while loading data"); - return null; - } - final ConfigurationSection questSec = dataSec.createSection(quest.getId()); - final QuestData questData = getQuestData(quest); - if (questData == null) { - continue; - } - if (!questData.blocksBroken.isEmpty()) { - final LinkedList blockAmounts = new LinkedList<>(); - for (final ItemStack m : questData.blocksBroken) { - blockAmounts.add(m.getAmount()); - } - questSec.set("blocks-broken-amounts", blockAmounts); - } - if (!questData.blocksDamaged.isEmpty()) { - final LinkedList blockAmounts = new LinkedList<>(); - for (final ItemStack m : questData.blocksDamaged) { - blockAmounts.add(m.getAmount()); - } - questSec.set("blocks-damaged-amounts", blockAmounts); - } - if (!questData.blocksPlaced.isEmpty()) { - final LinkedList blockAmounts = new LinkedList<>(); - for (final ItemStack m : questData.blocksPlaced) { - blockAmounts.add(m.getAmount()); - } - questSec.set("blocks-placed-amounts", blockAmounts); - } - if (!questData.blocksUsed.isEmpty()) { - final LinkedList blockAmounts = new LinkedList<>(); - for (final ItemStack m : questData.blocksUsed) { - blockAmounts.add(m.getAmount()); - } - questSec.set("blocks-used-amounts", blockAmounts); - } - if (!questData.blocksCut.isEmpty()) { - final LinkedList blockAmounts = new LinkedList<>(); - for (final ItemStack m : questData.blocksCut) { - blockAmounts.add(m.getAmount()); - } - questSec.set("blocks-cut-amounts", blockAmounts); - } - if (!questData.itemsCrafted.isEmpty()) { - final LinkedList craftAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsCrafted) { - craftAmounts.add(m.getAmount()); - } - questSec.set("item-craft-amounts", craftAmounts); - } - if (!questData.itemsSmelted.isEmpty()) { - final LinkedList smeltAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsSmelted) { - smeltAmounts.add(m.getAmount()); - } - questSec.set("item-smelt-amounts", smeltAmounts); - } - if (!questData.itemsEnchanted.isEmpty()) { - final LinkedList enchantAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsEnchanted) { - enchantAmounts.add(m.getAmount()); - } - questSec.set("item-enchant-amounts", enchantAmounts); - } - if (!questData.itemsBrewed.isEmpty()) { - final LinkedList brewAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsBrewed) { - brewAmounts.add(m.getAmount()); - } - questSec.set("item-brew-amounts", brewAmounts); - } - if (!questData.itemsConsumed.isEmpty()) { - final LinkedList consumeAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsConsumed) { - consumeAmounts.add(m.getAmount()); - } - questSec.set("item-consume-amounts", consumeAmounts); - } - if (!questData.itemsDelivered.isEmpty()) { - final LinkedList deliveryAmounts = new LinkedList<>(); - for (final ItemStack m : questData.itemsDelivered) { - deliveryAmounts.add(m.getAmount()); - } - questSec.set("item-delivery-amounts", deliveryAmounts); - } - if (!questData.citizensInteracted.isEmpty()) { - questSec.set("has-talked-to", questData.citizensInteracted); - } - if (!questData.citizensNumKilled.isEmpty()) { - questSec.set("citizen-amounts-killed", questData.citizensNumKilled); - } - if (!questData.mobNumKilled.isEmpty()) { - questSec.set("mobs-killed-amounts", questData.mobNumKilled); - } - if (!questData.mobsTamed.isEmpty()) { - questSec.set("mob-tame-amounts", questData.mobsTamed); - } - final Stage stage = getCurrentStage(quest); - if (stage != null) { - if (stage.fishToCatch != null) { - questSec.set("fish-caught", questData.getFishCaught()); - } - if (stage.cowsToMilk != null) { - questSec.set("cows-milked", questData.getCowsMilked()); - } - if (stage.playersToKill != null) { - questSec.set("players-killed", questData.getPlayersKilled()); - } - } - if (!questData.sheepSheared.isEmpty()) { - questSec.set("sheep-sheared", questData.sheepSheared); - } - if (!questData.locationsReached.isEmpty()) { - questSec.set("has-reached-location", questData.locationsReached); - } - if (!questData.passwordsSaid.isEmpty()) { - questSec.set("passwords-said", questData.passwordsSaid); - } - if (!questData.customObjectiveCounts.isEmpty()) { - questSec.set("custom-objective-counts", questData.customObjectiveCounts); - } - if (questData.getDelayTimeLeft() > 0) { - questSec.set("stage-delay", questData.getDelayTimeLeft()); - } - } - } else { - data.set("currentQuests", "none"); - data.set("currentStages", "none"); - data.set("quest-points", questPoints); - } - if (completedQuests.isEmpty()) { - data.set("completed-Quests", "none"); - } else { - final List questIds = new LinkedList<>(); - for (final Quest quest : completedQuests) { - questIds.add(quest.getId()); - } - data.set("completed-Quests", questIds); - } - if (!completedTimes.isEmpty()) { - final List questIds = new LinkedList<>(); - final List questTimes = new LinkedList<>(); - for (final Entry entry : completedTimes.entrySet()) { - questIds.add(entry.getKey().getId()); - questTimes.add(entry.getValue()); - } - data.set("completedRedoableQuests", questIds); - data.set("completedQuestTimes", questTimes); - } - if (!amountsCompleted.isEmpty()) { - final List questIds = new LinkedList<>(); - final List questAmounts = new LinkedList<>(); - for (final Entry entry : amountsCompleted.entrySet()) { - questIds.add(entry.getKey().getId()); - questAmounts.add(entry.getValue()); - } - data.set("amountsCompletedQuests", questIds); - data.set("amountsCompleted", questAmounts); - } - // #getPlayer is faster - OfflinePlayer representedPlayer = getPlayer(); - if (representedPlayer == null) { - representedPlayer = getOfflinePlayer(); - } - data.set("lastKnownName", representedPlayer.getName()); - return data; - } - - /** - * Load data of the Quester from storage - * - * @deprecated Use {@link #hasData()} - * @return true if successful - */ - @Deprecated - public boolean loadData() { - return plugin.getStorage().loadQuester(id) != null; - } - - /** - * Check whether the Quester has data saved to hard storage - * - * @return true if successful - */ - public boolean hasData() { - return plugin.getStorage().loadQuester(id) != null; - } - - /** - * Check whether the Quester has base data in memory, indicating they have participated in quests - * - * @return false if empty - */ - public boolean hasBaseData() { - return !currentQuests.isEmpty() || !questData.isEmpty() || !completedQuests.isEmpty(); - } - - /** - * Initiate the stage timer - * @param quest The quest of which the timer is for - */ - public void startStageTimer(final Quest quest) { - if (getQuestData(quest).getDelayTimeLeft() > -1) { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new StageTimer(plugin, this, quest), - (long) (getQuestData(quest).getDelayTimeLeft() * 0.02)); - } else { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new StageTimer(plugin, this, quest), - (long) (getCurrentStage(quest).delay * 0.02)); - if (getCurrentStage(quest).delayMessage != null) { - final Player p = plugin.getServer().getPlayer(id); - if (p != null) { - p.sendMessage(ConfigUtil.parseStringWithPossibleLineBreaks((getCurrentStage(quest) - .delayMessage), quest, p)); - } - } - } - getQuestData(quest).setDelayStartTime(System.currentTimeMillis()); - } - - /** - * Pause the stage timer. Useful when a player quits - * @param quest The quest of which the timer is for - */ - public void stopStageTimer(final Quest quest) { - if (getQuestData(quest).getDelayTimeLeft() > -1) { - getQuestData(quest).setDelayTimeLeft(getQuestData(quest).getDelayTimeLeft() - (System.currentTimeMillis() - - getQuestData(quest).getDelayStartTime())); - } else { - getQuestData(quest).setDelayTimeLeft(getCurrentStage(quest).delay - (System.currentTimeMillis() - - getQuestData(quest).getDelayStartTime())); - } - } - - /** - * Get remaining stage delay time - * @param quest The quest of which the timer is for - * @return Remaining time in milliseconds - */ - public long getStageTime(final Quest quest) { - if (getQuestData(quest).getDelayTimeLeft() > -1) { - return getQuestData(quest).getDelayTimeLeft() - (System.currentTimeMillis() - - getQuestData(quest).getDelayStartTime()); - } else { - return getCurrentStage(quest).delay - (System.currentTimeMillis() - getQuestData(quest).getDelayStartTime()); - } - } - - /** - * Check whether the provided quest is valid and, if not, inform the Quester - * - * @param quest The quest to check - */ - public void checkQuest(final Quest quest) { - if (quest != null) { - boolean exists = false; - for (final Quest q : plugin.getLoadedQuests()) { - if (q.getId().equalsIgnoreCase(quest.getId())) { - final Stage stage = getCurrentStage(quest); - if (stage != null) { - quest.updateCompass(this, stage); - // TODO - decide whether or not to handle this - /*if (q.equals(quest) == false) { - if (getPlayer() != null && getPlayer().isOnline()) { - quitQuest(quest, ChatColor.GOLD + Lang.get("questModified") - .replace("", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.GOLD)); - } - }*/ - } - exists = true; - break; - } - } - if (!exists) { - sendMessage(ChatColor.RED + Lang.get("questNotExist").replace("", ChatColor.DARK_PURPLE - + quest.getName() + ChatColor.RED)); - } - } - } - - /** - * Show an inventory GUI with quest items to the specified player - * - * @param npc The NPC from which the GUI is bound - * @param quests List of quests to use for displaying items - */ - public void showGUIDisplay(final NPC npc, final LinkedList quests) { - if (npc == null || quests == null) { - return; - } - final QuesterPreOpenGUIEvent preEvent = new QuesterPreOpenGUIEvent(this, npc, quests); - plugin.getServer().getPluginManager().callEvent(preEvent); - if (preEvent.isCancelled()) { - return; - } - final Player player = getPlayer(); - final Inventory inv = plugin.getServer().createInventory(player, ((quests.size() / 9) + 1) * 9, - Lang.get(player, "quests") + " | " + npc.getName()); - int i = 0; - for (final Quest quest : quests) { - if (quest.guiDisplay != null) { - if (i > 53) { - // Protocol-enforced size limit has been exceeded - break; - } - final ItemStack display = quest.guiDisplay; - final ItemMeta meta = display.getItemMeta(); - if (meta != null) { - if (completedQuests.contains(quest)) { - meta.setDisplayName(ChatColor.DARK_PURPLE + ConfigUtil.parseString(quest.getName() - + " " + ChatColor.GREEN + Lang.get(player, "redoCompleted"), npc)); - } else { - meta.setDisplayName(ChatColor.DARK_PURPLE + ConfigUtil.parseString(quest.getName(), npc)); - } - if (!meta.hasLore()) { - final LinkedList lines; - String desc = quest.description; - if (plugin.getDependencies().getPlaceholderApi() != null) { - desc = PlaceholderAPI.setPlaceholders(player, desc); - } - if (desc.equals(ChatColor.stripColor(desc))) { - lines = MiscUtil.makeLines(desc, " ", 40, ChatColor.DARK_GREEN); - } else { - lines = MiscUtil.makeLines(desc, " ", 40, null); - } - meta.setLore(lines); - } - meta.addItemFlags(ItemFlag.values()); - display.setItemMeta(meta); - } - inv.setItem(i, display); - i++; - } - } - player.openInventory(inv); - } - - /** - * Force Quester to quit the specified quest (canceling any timers), then update Quest Journal

- * - * Does not save changes to disk. Consider {@link #quitQuest(Quest, String)} or {@link #quitQuest(Quest, String[])} - * - * @param quest The quest to quit - */ - public void hardQuit(final Quest quest) { - try { - currentQuests.remove(quest); - questData.remove(quest); - if (!timers.isEmpty()) { - for (final Map.Entry entry : timers.entrySet()) { - if (entry.getValue().getName().equals(quest.getName())) { - plugin.getServer().getScheduler().cancelTask(entry.getKey()); - timers.remove(entry.getKey()); - } - } - } - } catch (final Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Forcibly remove quest from Quester's list of completed quests, then update Quest Journal

- * - * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} - * - * @param quest The quest to remove - */ - public void hardRemove(final Quest quest) { - try { - completedQuests.remove(quest); - } catch (final Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Forcibly clear Quester's list of current quests and data, then update Quest Journal

- * - * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} - */ - public void hardClear() { - try { - currentQuests.clear(); - questData.clear(); - amountsCompleted.clear(); - } catch (final Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Forcibly set Quester's current stage, then update Quest Journal - * - * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} - * - * @param key The quest to set stage of - * @param val The stage number to set - */ - public void hardStagePut(final Quest key, final Integer val) { - try { - currentQuests.put(key, val); - } catch (final Exception ex) { - ex.printStackTrace(); - } - } - - /** - * Forcibly set Quester's quest data, then update Quest Journal

- * - * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} - * - * @param key The quest to set stage of - * @param val The data to set - */ - public void hardDataPut(final Quest key, final QuestData val) { - try { - questData.put(key, val); - } catch (final Exception ex) { - ex.printStackTrace(); - } - } - - public boolean canUseCompass() { - if (getPlayer() != null) { - if (!getPlayer().hasPermission("worldedit.navigation.jumpto")) { - return getPlayer().hasPermission("quests.compass"); - } - } - return false; - } - - /** - * Reset compass target to Quester's bed spawn location

- * - * Will set to Quester's spawn location if bed spawn does not exist - */ - public void resetCompass() { - final Player player = getPlayer(); - if (player == null) { - return; - } - if (!canUseCompass()) { - return; - } - - Location defaultLocation = player.getBedSpawnLocation(); - if (defaultLocation == null) { - defaultLocation = player.getWorld().getSpawnLocation(); - } - compassTargetQuestId = null; - player.setCompassTarget(defaultLocation); - } - - /** - * Update compass target to current stage of first available current quest, if possible - */ - public void findCompassTarget() { - if (!canUseCompass()) { - return; - } - for (final Quest quest : currentQuests.keySet()) { - final Stage stage = getCurrentStage(quest); - if (stage != null && quest.updateCompass(this, stage)) { - break; - } - } - } - - /** - * Update compass target to current stage of next available current quest, if possible - * - * @param notify Whether to notify this quester of result - */ - public void findNextCompassTarget(final boolean notify) { - if (!canUseCompass()) { - return; - } - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - final LinkedList list = currentQuests.keySet().stream() - .sorted(Comparator.comparing(Quest::getName)).map(Quest::getId) - .collect(Collectors.toCollection(LinkedList::new)); - int index = 0; - if (compassTargetQuestId != null) { - if (!list.contains(compassTargetQuestId) && notify) { - return; - } - index = list.indexOf(compassTargetQuestId) + 1; - if (index >= list.size()) { - index = 0; - } - } - if (list.size() > 0) { - final Quest quest = plugin.getQuestById(list.get(index)); - compassTargetQuestId = quest.getId(); - final Stage stage = getCurrentStage(quest); - if (stage != null) { - quest.updateCompass(Quester.this, stage); - if (notify) { - sendMessage(ChatColor.YELLOW + Lang.get(getPlayer(), "compassSet") - .replace("", ChatColor.GOLD + quest.getName() + ChatColor.YELLOW)); - } - } - } else { - sendMessage(ChatColor.RED + Lang.get(getPlayer(), "journalNoQuests") - .replace("", Lang.get(getPlayer(), "journalTitle"))); - } - }); - } - - /** - * Check whether the Quester's inventory contains the specified item - * - * @param is The item with a specified amount to check - * @return true if the inventory contains at least the amount of the specified stack - */ - public boolean hasItem(final ItemStack is) { - final Inventory inv = getPlayer().getInventory(); - int playerAmount = 0; - for (final ItemStack stack : inv.getContents()) { - if (stack != null) { - if (ItemUtil.compareItems(is, stack, false) == 0) { - playerAmount += stack.getAmount(); - } - } - } - return playerAmount >= is.getAmount(); - } - - /** - * Dispatch player event to fellow questers

- * - * Accepted strings are: breakBlock, damageBlock, placeBlock, useBlock, - * cutBlock, craftItem, smeltItem, enchantItem, brewItem, consumeItem, - * milkCow, catchFish, killMob, deliverItem, killPlayer, talkToNPC, - * killNPC, tameMob, shearSheep, password, reachLocation - * - * @deprecated Use {@link #dispatchMultiplayerEverything(Quest, ObjectiveType, BiFunction)} - * - * @param objectiveType The type of objective to progress - * @param fun The function to execute, the event call - */ - @Deprecated - public void dispatchMultiplayerEverything(final Quest quest, final String objectiveType, - final BiFunction fun) { - dispatchMultiplayerEverything(quest, ObjectiveType.fromName(objectiveType), fun); - } - - /** - * Dispatch player event to fellow questers

- * - * @param type The type of objective to progress - * @param fun The function to execute, the event call - */ - public Set dispatchMultiplayerEverything(final Quest quest, final ObjectiveType type, - final BiFunction fun) { - final Set appliedQuestIDs = new HashSet<>(); - if (quest != null) { - try { - if (quest.getOptions().getShareProgressLevel() == 1) { - final List mq = getMultiplayerQuesters(quest); - if (mq == null) { - return appliedQuestIDs; - } - for (final Quester q : mq) { - if (q == null) { - continue; - } - if (quest.getOptions().canShareSameQuestOnly()) { - if (q.getCurrentStage(quest) != null) { - fun.apply(q, quest); - appliedQuestIDs.add(quest.getId()); - } - } - q.getCurrentQuests().forEach((otherQuest, i) -> { - if (otherQuest.getStage(i).containsObjective(type)) { - if (!otherQuest.getOptions().canShareSameQuestOnly()) { - fun.apply(q, otherQuest); - appliedQuestIDs.add(otherQuest.getId()); - } - } - }); - } - } - } catch (final Exception e) { - plugin.getLogger().severe("Error occurred while dispatching " + type.name() + " for quest ID " - + quest.getId()); - e.printStackTrace(); - } - } - return appliedQuestIDs; - } - - /** - * Dispatch finish objective to fellow questers - * - * @param quest The current quest - * @param currentStage The current stage of the quest - * @param fun The function to execute, the event call - */ - public Set dispatchMultiplayerObjectives(final Quest quest, final Stage currentStage, - final Function fun) { - final Set appliedQuestIDs = new HashSet<>(); - if (quest.getOptions().getShareProgressLevel() == 2) { - final List mq = getMultiplayerQuesters(quest); - if (mq == null) { - return appliedQuestIDs; - } - for (final Quester q : mq) { - if (q == null) { - continue; - } - // Share only same quest is not necessary here - // The function must be applied to the same quest - if ((q.getCurrentQuests().containsKey(quest) && currentStage.equals(q.getCurrentStage(quest)))) { - fun.apply(q); - } - } - } - return appliedQuestIDs; - } - - /** - * Get a list of fellow Questers in a party or group - * - * @param quest The quest which uses a linked plugin, i.e. Parties or DungeonsXL - * @return Potentially empty list of Questers or null for invalid quest - */ - public List getMultiplayerQuesters(final Quest quest) { - if (quest == null) { - return null; - } - final List mq = new LinkedList<>(); - if (plugin.getDependencies().getPartyProvider() != null) { - final PartyProvider partyProvider = plugin.getDependencies().getPartyProvider(); - if (partyProvider != null) { - if (quest.getOptions().canUsePartiesPlugin() || quest.getOptions().getExternalPartyPlugin() != null) { - if (getUUID() != null && partyProvider.getPartyId(getUUID()) != null) { - final String partyId = partyProvider.getPartyId(getUUID()); - final double distanceSquared = quest.getOptions().getShareDistance() - * quest.getOptions().getShareDistance(); - final boolean offlinePlayers = quest.getOptions().canHandleOfflinePlayers(); - if (offlinePlayers) { - for (final UUID id : partyProvider.getMembers(partyId)) { - if (!id.equals(getUUID())) { - mq.add(plugin.getQuester(id)); - } - } - } else { - for (final UUID id : partyProvider.getOnlineMembers(partyId)) { - if (!id.equals(getUUID())) { - if (distanceSquared > 0) { - final Player player = Bukkit.getPlayer(id); - if (player != null && distanceSquared >= getPlayer().getLocation() - .distanceSquared(player.getLocation())) { - mq.add(plugin.getQuester(id)); - } - } else { - mq.add(plugin.getQuester(id)); - } - } - } - } - return mq; - } - } - } - } else if (plugin.getDependencies().getPartiesApi() != null) { - if (quest.getOptions().canUsePartiesPlugin()) { - final PartyPlayer partyPlayer = plugin.getDependencies().getPartiesApi().getPartyPlayer(getUUID()); - if (partyPlayer != null && partyPlayer.getPartyId() != null) { - final Party party = plugin.getDependencies().getPartiesApi().getParty(partyPlayer.getPartyId()); - if (party != null) { - final double distanceSquared = quest.getOptions().getShareDistance() - * quest.getOptions().getShareDistance(); - final boolean offlinePlayers = quest.getOptions().canHandleOfflinePlayers(); - if (offlinePlayers) { - for (final UUID id : party.getMembers()) { - if (!id.equals(getUUID())) { - mq.add(plugin.getQuester(id)); - } - } - } else { - for (final PartyPlayer pp : party.getOnlineMembers(true)) { - if (!pp.getPlayerUUID().equals(getUUID())) { - if (distanceSquared > 0) { - final Player player = Bukkit.getPlayer(pp.getPlayerUUID()); - if (player != null) { - final Location locationOne = getPlayer().getLocation(); - final Location locationTwo = player.getLocation(); - if (locationOne.getWorld() != null && locationTwo.getWorld() != null) { - if (locationOne.getWorld().getName().equals(locationTwo.getWorld() - .getName())) { - if (distanceSquared >= getPlayer().getLocation() - .distanceSquared(player.getLocation())) { - mq.add(plugin.getQuester(pp.getPlayerUUID())); - } - } - } - } - } else { - mq.add(plugin.getQuester(pp.getPlayerUUID())); - } - } - } - } - return mq; - } - } - } - } - return mq; - } - - /** - * Check if quest is available and, if so, ask Quester if they would like to start it

- * - * @param quest The quest to check and then offer - * @param giveReason Whether to inform Quester of unavailability - * @return true if successful - */ - public boolean offerQuest(final Quest quest, final boolean giveReason) { - if (quest == null) { - return false; - } - final QuestTakeEvent event = new QuestTakeEvent(quest, this); - plugin.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return false; - } - if (canAcceptOffer(quest, giveReason)) { - if (getPlayer() != null) { - if (!getPlayer().isConversing()) { - setQuestIdToTake(quest.getId()); - final String s = ChatColor.GOLD + Lang.get("questObjectivesTitle") - .replace("", quest.getName()) + "\n" + ChatColor.RESET + quest.getDescription(); - for (final String msg : s.split("
")) { - sendMessage(msg); - } - if (!plugin.getSettings().canAskConfirmation()) { - takeQuest(quest, false); - } else { - plugin.getConversationFactory().buildConversation(getPlayer()).begin(); - } - return true; - } else { - sendMessage(ChatColor.YELLOW + Lang.get(getPlayer(), "alreadyConversing")); - } - } - } - return false; - } - - /** - * Check if quest is available to this Quester

- * - * @param quest The quest to check - * @param giveReason Whether to inform Quester of unavailability - * @return true if available - */ - public boolean canAcceptOffer(final Quest quest, final boolean giveReason) { - if (quest == null) { - return false; - } - if (getCurrentQuests().size() >= plugin.getSettings().getMaxQuests() && plugin.getSettings().getMaxQuests() - > 0) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "questMaxAllowed").replace("", - String.valueOf(plugin.getSettings().getMaxQuests())); - sendMessage(ChatColor.YELLOW + msg); - } - return false; - } else if (getCurrentQuests().containsKey(quest)) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "questAlreadyOn"); - sendMessage(ChatColor.YELLOW + msg); - } - return false; - } else if (getCompletedQuests().contains(quest) && quest.getPlanner().getCooldown() < 0) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "questAlreadyCompleted") - .replace("", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.YELLOW); - sendMessage(ChatColor.YELLOW + msg); - } - return false; - } else if (plugin.getDependencies().getCitizens() != null - && !plugin.getSettings().canAllowCommandsForNpcQuests() - && quest.getNpcStart() != null && quest.getNpcStart().getEntity() != null - && quest.getNpcStart().getEntity().getLocation().getWorld() != null - && getPlayer().getLocation().getWorld() != null - && quest.getNpcStart().getEntity().getLocation().getWorld().getName().equals( - getPlayer().getLocation().getWorld().getName()) - && quest.getNpcStart().getEntity().getLocation().distance(getPlayer().getLocation()) > 6.0) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "mustSpeakTo").replace("", ChatColor.DARK_PURPLE - + quest.getNpcStart().getName() + ChatColor.YELLOW); - sendMessage(ChatColor.YELLOW + msg); - } - return false; - } else if (quest.getBlockStart() != null) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "noCommandStart").replace("", ChatColor.DARK_PURPLE - + quest.getName() + ChatColor.YELLOW); - sendMessage(ChatColor.YELLOW + msg); - } - return false; - } else if (getCompletedQuests().contains(quest) && getRemainingCooldown(quest) > 0 - && !quest.getPlanner().getOverride()) { - if (giveReason) { - final String msg = Lang.get(getPlayer(), "questTooEarly").replace("", ChatColor.AQUA - + quest.getName()+ ChatColor.YELLOW).replace("

- * + * * Excludes start/complete message, delay, and objective-override - * + * * @return true if stage contains an objective */ - public boolean hasObjective() { - if (!blocksToBreak.isEmpty()) { return true; } - if (!blocksToDamage.isEmpty()) { return true; } - if (!blocksToPlace.isEmpty()) { return true; } - if (!blocksToUse.isEmpty()) { return true; } - if (!blocksToCut.isEmpty()) { return true; } - if (cowsToMilk != null) { return true; } - if (fishToCatch != null) { return true; } - if (playersToKill != null) { return true; } - if (!itemsToCraft.isEmpty()) { return true; } - if (!itemsToSmelt.isEmpty()) { return true; } - if (!itemsToEnchant.isEmpty()) { return true; } - if (!itemsToBrew.isEmpty()) { return true; } - if (!itemsToConsume.isEmpty()) { return true; } - if (!itemsToDeliver.isEmpty()) { return true; } - if (!citizensToInteract.isEmpty()) { return true; } - if (!citizensToKill.isEmpty()) { return true; } - if (!locationsToReach.isEmpty()) { return true; } - if (!mobsToTame.isEmpty()) { return true; } - if (!sheepToShear.isEmpty()) { return true; } - if (!passwordDisplays.isEmpty()) { return true; } - return !customObjectives.isEmpty(); - } - + boolean hasObjective(); + /** * Check if stage has the specified type of objective

- * - * Accepted strings are: breakBlock, damageBlock, placeBlock, useBlock, - * cutBlock, craftItem, smeltItem, enchantItem, brewItem, milkCow, catchFish, - * killMob, deliverItem, killPlayer, talkToNPC, killNPC, tameMob, - * shearSheep, password, reachLocation - * - * @deprecated Use {@link #containsObjective(ObjectiveType)} - * + * * @param type The type of objective to check for * @return true if stage contains specified objective */ - @Deprecated - public boolean containsObjective(final String type) { - return containsObjective(ObjectiveType.fromName(type)); - } - - /** - * Check if stage has the specified type of objective

- * - * @param type The type of objective to check for - * @return true if stage contains specified objective - */ - public boolean containsObjective(final ObjectiveType type) { - if (type.equals(ObjectiveType.BREAK_BLOCK)) { - return !blocksToBreak.isEmpty(); - } else if (type.equals(ObjectiveType.DAMAGE_BLOCK)) { - return !blocksToDamage.isEmpty(); - } else if (type.equals(ObjectiveType.PLACE_BLOCK)) { - return !blocksToPlace.isEmpty(); - } else if (type.equals(ObjectiveType.USE_BLOCK)) { - return !blocksToUse.isEmpty(); - } else if (type.equals(ObjectiveType.CUT_BLOCK)) { - return !blocksToCut.isEmpty(); - } else if (type.equals(ObjectiveType.CRAFT_ITEM)) { - return !itemsToCraft.isEmpty(); - } else if (type.equals(ObjectiveType.SMELT_ITEM)) { - return !itemsToSmelt.isEmpty(); - } else if (type.equals(ObjectiveType.ENCHANT_ITEM)) { - return !itemsToEnchant.isEmpty(); - } else if (type.equals(ObjectiveType.BREW_ITEM)) { - return !itemsToBrew.isEmpty(); - } else if (type.equals(ObjectiveType.CONSUME_ITEM)) { - return !itemsToConsume.isEmpty(); - } else if (type.equals(ObjectiveType.DELIVER_ITEM)) { - return !itemsToDeliver.isEmpty(); - } else if (type.equals(ObjectiveType.MILK_COW)) { - return cowsToMilk != null; - } else if (type.equals(ObjectiveType.CATCH_FISH)) { - return fishToCatch != null; - } else if (type.equals(ObjectiveType.KILL_MOB)) { - return !mobsToKill.isEmpty(); - } else if (type.equals(ObjectiveType.KILL_PLAYER)) { - return playersToKill != null; - } else if (type.equals(ObjectiveType.TALK_TO_NPC)) { - return !citizensToInteract.isEmpty(); - } else if (type.equals(ObjectiveType.KILL_NPC)) { - return !citizensToKill.isEmpty(); - } else if (type.equals(ObjectiveType.TAME_MOB)) { - return !mobsToTame.isEmpty(); - } else if (type.equals(ObjectiveType.SHEAR_SHEEP)) { - return !sheepToShear.isEmpty(); - } else if (type.equals(ObjectiveType.REACH_LOCATION)) { - return !locationsToReach.isEmpty(); - } else if (type.equals(ObjectiveType.PASSWORD)) { - return !passwordPhrases.isEmpty(); - } else { - return false; - } - } + boolean containsObjective(final ObjectiveType type); } diff --git a/api/src/main/java/me/blackvein/quests/actions/Action.java b/api/src/main/java/me/blackvein/quests/actions/Action.java index 053e81c74..dbbf817a2 100644 --- a/api/src/main/java/me/blackvein/quests/actions/Action.java +++ b/api/src/main/java/me/blackvein/quests/actions/Action.java @@ -1,421 +1,108 @@ -/* - * Copyright (c) 2014 PikaMug and contributors. All rights reserved. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ package me.blackvein.quests.actions; import me.blackvein.quests.Quest; -import me.blackvein.quests.QuestMob; import me.blackvein.quests.Quester; -import me.blackvein.quests.Quests; -import me.blackvein.quests.tasks.ActionTimer; -import me.blackvein.quests.util.ConfigUtil; -import me.blackvein.quests.util.InventoryUtil; -import me.blackvein.quests.util.Lang; -import org.bukkit.ChatColor; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import java.util.HashMap; import java.util.LinkedList; import java.util.Map; -public class Action implements Comparable { +public interface Action { + String getName(); - private final Quests plugin; - private String name = ""; - protected String message = null; - protected boolean clearInv = false; - protected boolean failQuest = false; - protected LinkedList explosions = new LinkedList<>(); - protected Map effects = new HashMap<>(); - protected LinkedList items = new LinkedList<>(); - protected World stormWorld = null; - protected int stormDuration = 0; - protected World thunderWorld = null; - protected int thunderDuration = 0; - protected int timer = 0; - protected boolean cancelTimer = false; - protected LinkedList mobSpawns = new LinkedList() { + void setName(final String name); - private static final long serialVersionUID = -761974607799449780L; + String getMessage(); - @Override - public boolean equals(final Object o) { - if (o instanceof LinkedList) { - @SuppressWarnings("unchecked") - final - LinkedList other = (LinkedList) o; - if (size() != other.size()) { - return false; - } - for (int i = 0; i < size(); i++) { - if (!get(i).equals(other.get(i))) { - return false; - } - } - } - return false; - } - }; - protected LinkedList lightningStrikes = new LinkedList<>(); - protected LinkedList commands = new LinkedList<>(); - protected LinkedList potionEffects = new LinkedList<>(); - protected int hunger = -1; - protected int saturation = -1; - protected float health = -1; - protected Location teleport; - protected String book = ""; - protected String denizenScript; + void setMessage(final String message); - public Action(final Quests plugin) { - this.plugin = plugin; - } - - @Override - public int compareTo(final Action action) { - return name.compareTo(action.getName()); - } + boolean isClearInv(); - public String getName() { - return name; - } - - public void setName(final String name) { - this.name = name; - } + void setClearInv(final boolean clearInv); - public String getMessage() { - return message; - } + boolean isFailQuest(); - public void setMessage(final String message) { - this.message = message; - } + void setFailQuest(final boolean failQuest); - public boolean isClearInv() { - return clearInv; - } + LinkedList getExplosions(); - public void setClearInv(final boolean clearInv) { - this.clearInv = clearInv; - } + void setExplosions(final LinkedList explosions); - public boolean isFailQuest() { - return failQuest; - } + Map getEffects(); - public void setFailQuest(final boolean failQuest) { - this.failQuest = failQuest; - } + void setEffects(final Map effects); - public LinkedList getExplosions() { - return explosions; - } + LinkedList getItems(); - public void setExplosions(final LinkedList explosions) { - this.explosions = explosions; - } + void setItems(final LinkedList items); - public Map getEffects() { - return effects; - } + World getStormWorld(); - public void setEffects(final Map effects) { - this.effects = effects; - } + void setStormWorld(final World stormWorld); - public LinkedList getItems() { - return items; - } + int getStormDuration(); - public void setItems(final LinkedList items) { - this.items = items; - } + void setStormDuration(final int stormDuration); - public World getStormWorld() { - return stormWorld; - } + World getThunderWorld(); - public void setStormWorld(final World stormWorld) { - this.stormWorld = stormWorld; - } + void setThunderWorld(final World thunderWorld); - public int getStormDuration() { - return stormDuration; - } + int getThunderDuration(); - public void setStormDuration(final int stormDuration) { - this.stormDuration = stormDuration; - } + void setThunderDuration(final int thunderDuration); - public World getThunderWorld() { - return thunderWorld; - } + int getTimer(); - public void setThunderWorld(final World thunderWorld) { - this.thunderWorld = thunderWorld; - } + void setTimer(final int timer); - public int getThunderDuration() { - return thunderDuration; - } + boolean isCancelTimer(); - public void setThunderDuration(final int thunderDuration) { - this.thunderDuration = thunderDuration; - } + void setCancelTimer(final boolean cancelTimer); - public int getTimer() { - return timer; - } + LinkedList getMobSpawns(); - public void setTimer(final int timer) { - this.timer = timer; - } + void setMobSpawns(final LinkedList mobSpawns); - public boolean isCancelTimer() { - return cancelTimer; - } + LinkedList getLightningStrikes(); - public void setCancelTimer(final boolean cancelTimer) { - this.cancelTimer = cancelTimer; - } + void setLightningStrikes(final LinkedList lightningStrikes); - public LinkedList getMobSpawns() { - return mobSpawns; - } + LinkedList getCommands(); - public void setMobSpawns(final LinkedList mobSpawns) { - this.mobSpawns = mobSpawns; - } + void setCommands(final LinkedList commands); - public LinkedList getLightningStrikes() { - return lightningStrikes; - } + LinkedList getPotionEffects(); - public void setLightningStrikes(final LinkedList lightningStrikes) { - this.lightningStrikes = lightningStrikes; - } + void setPotionEffects(final LinkedList potionEffects); - public LinkedList getCommands() { - return commands; - } + int getHunger(); - public void setCommands(final LinkedList commands) { - this.commands = commands; - } + void setHunger(final int hunger); - public LinkedList getPotionEffects() { - return potionEffects; - } + int getSaturation(); - public void setPotionEffects(final LinkedList potionEffects) { - this.potionEffects = potionEffects; - } + void setSaturation(final int saturation); - public int getHunger() { - return hunger; - } + float getHealth(); - public void setHunger(final int hunger) { - this.hunger = hunger; - } + void setHealth(final float health); - public int getSaturation() { - return saturation; - } + Location getTeleport(); - public void setSaturation(final int saturation) { - this.saturation = saturation; - } + void setTeleport(final Location teleport); - public float getHealth() { - return health; - } + String getBook(); - public void setHealth(final float health) { - this.health = health; - } + void setBook(final String book); - public Location getTeleport() { - return teleport; - } + String getDenizenScript(); - public void setTeleport(final Location teleport) { - this.teleport = teleport; - } + void setDenizenScript(final String scriptName); - public String getBook() { - return book; - } - - public void setBook(final String book) { - this.book = book; - } - - public String getDenizenScript() { - return book; - } - - public void setDenizenScript(final String scriptName) { - this.denizenScript = scriptName; - } - - public void fire(final Quester quester, final Quest quest) { - final Player player = quester.getPlayer(); - if (message != null) { - player.sendMessage(ConfigUtil.parseStringWithPossibleLineBreaks(message, quest, player)); - } - if (clearInv) { - player.getInventory().clear(); - } - if (!explosions.isEmpty()) { - for (final Location l : explosions) { - if (l.getWorld() != null) { - l.getWorld().createExplosion(l, 4F, false); - } - } - } - if (!effects.isEmpty()) { - for (final Location l : effects.keySet()) { - if (l.getWorld() != null) { - l.getWorld().playEffect(l, effects.get(l), 1); - } - } - } - if (!items.isEmpty()) { - for (final ItemStack is : items) { - try { - InventoryUtil.addItem(player, is); - } catch (final Exception e) { - plugin.getLogger().severe("Unable to add null item to inventory of " - + player.getName() + " during quest " + quest.getName() + " event " + name); - player.sendMessage(ChatColor.RED + "Quests encountered a problem with an item. " - + "Please contact an administrator."); - } - } - } - if (stormWorld != null) { - stormWorld.setStorm(true); - stormWorld.setWeatherDuration(stormDuration); - } - if (thunderWorld != null) { - thunderWorld.setThundering(true); - thunderWorld.setThunderDuration(thunderDuration); - } - if (!mobSpawns.isEmpty()) { - for (final QuestMob questMob : mobSpawns) { - questMob.spawn(); - } - } - if (!lightningStrikes.isEmpty()) { - for (final Location l : lightningStrikes) { - if (l.getWorld() != null) { - l.getWorld().strikeLightning(l); - } - } - } - if (!commands.isEmpty()) { - for (final String s : commands) { - plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), - s.replace("", quester.getPlayer().getName())); - } - } - if (!potionEffects.isEmpty()) { - for (final PotionEffect p : potionEffects) { - player.addPotionEffect(p); - } - } - if (hunger != -1) { - player.setFoodLevel(hunger); - } - if (saturation != -1) { - player.setSaturation(saturation); - } - if (health != -1) { - player.setHealth(health); - } - if (teleport != null) { - if (player.isDead()) { - plugin.getLogger().warning("Tried to fire Action " + name + " but player " + player.getUniqueId() - + " was dead (known Bukkit limitation)."); - } else { - player.teleport(teleport); - } - } - if (book != null) { - if (!book.isEmpty()) { - if (plugin.getDependencies().getCitizensBooksApi() != null) { - if (plugin.getDependencies().getCitizensBooksApi().hasFilter(book)) { - plugin.getDependencies().getCitizensBooksApi().openBook(player, plugin.getDependencies() - .getCitizensBooksApi().getFilter(book)); - } - } - } - } - if (failQuest) { - quest.failQuest(quester, true); - } - if (timer > 0) { - player.sendMessage(ChatColor.GREEN + Lang.get(player, "timerStart") - .replace("

+ * + * Note that the "defaultValue" Object will be cast to a String internally + * + * @param title Prompt name + * @param description Description of expected input + * @param defaultValue Value to be used if input is not received + */ + @Override + public void addStringPrompt(final String title, final String description, final Object defaultValue) { + final Entry prompt = new AbstractMap.SimpleEntry<>(title, defaultValue); + data.add(prompt); + descriptions.put(title, description); + } + + @Override + public Map getDescriptions() { + return descriptions; + } + + @Override + public int getCount() { + return count; + } + + @Override + public void setCount(final int count) { + this.count = count; + } + + @Override + public String getCountPrompt() { + return countPrompt; + } + + @Override + public void setCountPrompt(final String countPrompt) { + this.countPrompt = countPrompt; + } + + /** + * Check whether to let user set required amount for objective + */ + @Override + public boolean canShowCount() { + return showCount; + } + + /** + * Set whether to let user set required amount for objective + * + * @param showCount Whether to show the count + */ + @Override + public void setShowCount(final boolean showCount) { + this.showCount = showCount; + } + + @Override + public Map getDataForPlayer(final Player player, final CustomObjective customObj, + final Quest quest) { + final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); + if (quester != null) { + final BukkitStage currentStage = quester.getCurrentStage((BukkitQuest) quest); + if (currentStage == null) { + return null; + } + CustomObjective found = null; + for (final CustomObjective co : currentStage.getCustomObjectives()) { + if (co.getName().equals(customObj.getName())) { + found = co; + break; + } + } + if (found != null) { + final Map m = new HashMap<>(); + for (final Entry dataMap : found.getData()) { + for (final Entry e : currentStage.getCustomObjectiveData()) { + if (e.getKey().equals(dataMap.getKey())) { + m.put(e.getKey(), e.getValue()); + } + } + } + if (!m.isEmpty()) { + return m; + } + } + } + return null; + } + + @Override + public void incrementObjective(final Player player, final CustomObjective obj, final int count, final Quest quest) { + final BukkitQuest bQuest = (BukkitQuest) quest; + final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); + if (quester != null) { + if (quester.hasCustomObjective(bQuest, obj.getName())) { + int index = -1; + final LinkedList customObjCounts = quester.getQuestData(bQuest).customObjectiveCounts; + for (final CustomObjective co : quester.getCurrentStage(bQuest).getCustomObjectives()) { + index++; + if (co.getName().equals(this.getName())) { + if (index >= customObjCounts.size()) { + plugin.getLogger().severe("Index was larger than count for " + obj.getName() + " by " + + obj.getAuthor()); + continue; + } + final int old = customObjCounts.get(index); + plugin.getQuester(player.getUniqueId()).getQuestData(bQuest).customObjectiveCounts + .set(index, old + count); + break; + } + } + if (index > -1) { + final int progress = customObjCounts.get(index); + final int goal = quester.getCurrentStage(bQuest).getCustomObjectiveCounts().get(index); + + final ObjectiveType type = ObjectiveType.CUSTOM; + final QuesterPreUpdateObjectiveEvent preEvent + = new QuesterPreUpdateObjectiveEvent(quester, quest, new BukkitObjective(type, progress, goal)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + if (progress >= goal) { + quester.finishObjective(bQuest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, goal)), null, null, null, null, null, null, obj); + + // Multiplayer + final int finalIndex = index; + quester.dispatchMultiplayerObjectives(bQuest, quester.getCurrentStage(bQuest), (final BukkitQuester q) -> { + final int old = q.getQuestData(bQuest).customObjectiveCounts.get(finalIndex); + q.getQuestData(bQuest).customObjectiveCounts.set(finalIndex, old + count); + q.finishObjective(bQuest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, goal)), null, null, null, null, null, null, obj); + return null; + }); + } + + final QuesterPostUpdateObjectiveEvent postEvent + = new QuesterPostUpdateObjectiveEvent(quester, quest, new BukkitObjective(type, progress, goal)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + } + } +} diff --git a/api/src/main/java/me/blackvein/quests/particle/ParticleProvider.java b/core/src/main/java/me/blackvein/quests/particle/ParticleProvider.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/particle/ParticleProvider.java rename to core/src/main/java/me/blackvein/quests/particle/ParticleProvider.java diff --git a/api/src/main/java/me/blackvein/quests/particle/ParticleProvider_Bukkit.java b/core/src/main/java/me/blackvein/quests/particle/ParticleProvider_Bukkit.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/particle/ParticleProvider_Bukkit.java rename to core/src/main/java/me/blackvein/quests/particle/ParticleProvider_Bukkit.java diff --git a/api/src/main/java/me/blackvein/quests/particle/PreBuiltParticle.java b/core/src/main/java/me/blackvein/quests/particle/PreBuiltParticle.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/particle/PreBuiltParticle.java rename to core/src/main/java/me/blackvein/quests/particle/PreBuiltParticle.java diff --git a/core/src/main/java/me/blackvein/quests/player/BukkitQuester.java b/core/src/main/java/me/blackvein/quests/player/BukkitQuester.java new file mode 100644 index 000000000..de9d68364 --- /dev/null +++ b/core/src/main/java/me/blackvein/quests/player/BukkitQuester.java @@ -0,0 +1,4352 @@ +/* + * Copyright (c) 2014 PikaMug and contributors. All rights reserved. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package me.blackvein.quests.player; + +import com.alessiodp.parties.api.interfaces.Party; +import com.alessiodp.parties.api.interfaces.PartyPlayer; +import com.gmail.nossr50.datatypes.skills.SkillType; +import com.gmail.nossr50.util.player.UserManager; +import me.blackvein.quests.CustomObjective; +import me.blackvein.quests.CustomRequirement; +import me.blackvein.quests.Dependencies; +import me.blackvein.quests.Quest; +import me.blackvein.quests.QuestData; +import me.blackvein.quests.Quester; +import me.blackvein.quests.Quests; +import me.blackvein.quests.Requirements; +import me.blackvein.quests.Stage; +import me.blackvein.quests.conditions.Condition; +import me.blackvein.quests.enums.ObjectiveType; +import me.blackvein.quests.events.quest.QuestTakeEvent; +import me.blackvein.quests.events.quester.QuesterPostStartQuestEvent; +import me.blackvein.quests.events.quester.QuesterPostUpdateObjectiveEvent; +import me.blackvein.quests.events.quester.QuesterPreOpenGUIEvent; +import me.blackvein.quests.events.quester.QuesterPreStartQuestEvent; +import me.blackvein.quests.events.quester.QuesterPreUpdateObjectiveEvent; +import me.blackvein.quests.item.QuestJournal; +import me.blackvein.quests.quests.BukkitObjective; +import me.blackvein.quests.quests.BukkitPlanner; +import me.blackvein.quests.quests.BukkitQuest; +import me.blackvein.quests.quests.BukkitRequirements; +import me.blackvein.quests.quests.BukkitStage; +import me.blackvein.quests.storage.Storage; +import me.blackvein.quests.tasks.StageTimer; +import me.blackvein.quests.util.ConfigUtil; +import me.blackvein.quests.util.InventoryUtil; +import me.blackvein.quests.util.ItemUtil; +import me.blackvein.quests.util.Lang; +import me.blackvein.quests.util.MiscUtil; +import me.blackvein.quests.util.RomanNumeral; +import me.clip.placeholderapi.PlaceholderAPI; +import me.pikamug.unite.api.objects.PartyProvider; +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.npc.NPC; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.material.Crops; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class BukkitQuester implements Quester, Comparable { + + private final Quests plugin; + private UUID id; + protected String questIdToTake; + private String lastKnownName; + protected int questPoints = 0; + private String compassTargetQuestId; + private long lastNotifiedCondition = 0L; + protected ConcurrentHashMap timers = new ConcurrentHashMap<>(); + protected ConcurrentHashMap currentQuests = new ConcurrentHashMap() { + + private static final long serialVersionUID = 6361484975823846780L; + + @Override + public Integer put(final @NotNull Quest key, final @NotNull Integer val) { + final Integer data = super.put(key, val); + updateJournal(); + return data; + } + + @Override + public Integer remove(final @NotNull Object key) { + final Integer i = super.remove(key); + updateJournal(); + return i; + } + + @Override + public void clear() { + super.clear(); + updateJournal(); + } + + @Override + public void putAll(final Map m) { + super.putAll(m); + updateJournal(); + } + }; + protected ConcurrentSkipListSet completedQuests = new ConcurrentSkipListSet() { + + private static final long serialVersionUID = -269110128568487000L; + + @Override + public boolean add(final Quest e) { + final boolean b = super.add(e); + updateJournal(); + return b; + } + + @Override + public boolean addAll(final @NotNull Collection c) { + final boolean b = super.addAll(c); + updateJournal(); + return b; + } + + @Override + public void clear() { + super.clear(); + updateJournal(); + } + + @Override + public boolean remove(final Object o) { + final boolean b = super.remove(o); + updateJournal(); + return b; + } + + @Override + public boolean removeAll(final Collection c) { + final boolean b = super.removeAll(c); + updateJournal(); + return b; + } + }; + protected ConcurrentHashMap completedTimes = new ConcurrentHashMap<>(); + protected ConcurrentHashMap amountsCompleted = new ConcurrentHashMap() { + + private static final long serialVersionUID = 5475202358792520975L; + + @Override + public Integer put(final @NotNull BukkitQuest key, final @NotNull Integer val) { + final Integer data = super.put(key, val); + updateJournal(); + return data; + } + + @Override + public Integer remove(final @NotNull Object key) { + final Integer i = super.remove(key); + updateJournal(); + return i; + } + + @Override + public void clear() { + super.clear(); + updateJournal(); + } + + @Override + public void putAll(final Map m) { + super.putAll(m); + updateJournal(); + } + }; + protected ConcurrentHashMap questData = new ConcurrentHashMap() { + + private static final long serialVersionUID = -4607112433003926066L; + + @Override + public QuestData put(final @NotNull BukkitQuest key, final @NotNull QuestData val) { + final QuestData data = super.put(key, val); + updateJournal(); + return data; + } + + @Override + public QuestData remove(final @NotNull Object key) { + final QuestData data = super.remove(key); + updateJournal(); + return data; + } + + @Override + public void clear() { + super.clear(); + updateJournal(); + } + + @Override + public void putAll(final Map m) { + super.putAll(m); + updateJournal(); + } + }; + + /** + * @deprecated Use {@link #BukkitQuester(Quests, UUID)} + */ + @Deprecated + public BukkitQuester(final Quests plugin) { + this.plugin = plugin; + } + + public BukkitQuester(final Quests plugin, final UUID uuid) { + this.plugin = plugin; + this.id = uuid; + if (getPlayer() != null) { + this.lastKnownName = getPlayer().getName(); + } else { + this.lastKnownName = getOfflinePlayer().getName(); + } + } + + @Override + public int compareTo(final BukkitQuester quester) { + return id.compareTo(quester.getUUID()); + } + + public UUID getUUID() { + return id; + } + + public void setUUID(final UUID id) { + this.id = id; + } + + public String getQuestIdToTake() { + return questIdToTake; + } + + public void setQuestIdToTake(final String questIdToTake) { + this.questIdToTake = questIdToTake; + } + + public String getLastKnownName() { + return lastKnownName; + } + + public void setLastKnownName(final String lastKnownName) { + this.lastKnownName = lastKnownName; + } + + public int getQuestPoints() { + return questPoints; + } + + public void setQuestPoints(final int questPoints) { + this.questPoints = questPoints; + } + + /** + * Get compass target quest. Returns null if not set + * + * @return Quest or null + */ + public BukkitQuest getCompassTarget() { + return compassTargetQuestId != null ? plugin.getQuestById(compassTargetQuestId) : null; + } + + /** + * Set compass target quest. Does not update in-game + * + * @param quest The target quest + */ + public void setCompassTarget(final BukkitQuest quest) { + compassTargetQuestId = quest.getId(); + } + + public ConcurrentHashMap getTimers() { + return timers; + } + + public void setTimers(final ConcurrentHashMap timers) { + this.timers = timers; + } + + public void removeTimer(final Integer timerId) { + this.timers.remove(timerId); + } + + public ConcurrentHashMap getCurrentQuests() { + return currentQuests; + } + + public void setCurrentQuests(final ConcurrentHashMap currentQuests) { + this.currentQuests = currentQuests; + } + + public ConcurrentSkipListSet getCompletedQuests() { + return completedQuests; + } + + public void setCompletedQuests(final ConcurrentSkipListSet completedQuests) { + this.completedQuests = completedQuests; + } + + public ConcurrentHashMap getCompletedTimes() { + return completedTimes; + } + + public void setCompletedTimes(final ConcurrentHashMap completedTimes) { + this.completedTimes = completedTimes; + } + + public ConcurrentHashMap getAmountsCompleted() { + return amountsCompleted; + } + + public void setAmountsCompleted(final ConcurrentHashMap amountsCompleted) { + this.amountsCompleted = amountsCompleted; + } + + public ConcurrentHashMap getQuestData() { + return questData; + } + + public void setQuestData(final ConcurrentHashMap questData) { + this.questData = questData; + } + + public Player getPlayer() { + return plugin.getServer().getPlayer(id); + } + + public OfflinePlayer getOfflinePlayer() { + return plugin.getServer().getOfflinePlayer(id); + } + + public void sendMessage(final String message) { + if (getPlayer() == null || !getPlayer().isOnline() || message.trim().isEmpty()) { + return; + } + getPlayer().sendMessage(message); + } + + public Stage getCurrentStage(final Quest quest) { + if (currentQuests.containsKey(quest)) { + return quest.getStage(currentQuests.get(quest)); + } + return null; + } + + public QuestData getQuestData(final BukkitQuest quest) { + for (final BukkitQuest q : questData.keySet()) { + if (q.getId().equals(quest.getId())) { + return questData.get(q); + } + } + if (currentQuests.get(quest) != null) { + addEmptiesFor(quest, currentQuests.get(quest)); + } + return new QuestData(this); + } + + public boolean hasJournal() { + return getJournal() != null; + } + + public ItemStack getJournal() { + if (getPlayer() == null || !getPlayer().isOnline()) { + return null; + } + for (final ItemStack is : getPlayer().getInventory().getContents()) { + if (ItemUtil.isJournal(is)) { + return is; + } + } + return null; + } + + public int getJournalIndex() { + if (getPlayer() == null || !getPlayer().isOnline()) { + return -1; + } + final ItemStack[] arr = getPlayer().getInventory().getContents(); + for (int i = 0; i < arr.length; i++) { + if (arr[i] != null) { + if (ItemUtil.isJournal(arr[i])) { + return i; + } + } + } + return -1; + } + + public void updateJournal() { + if (getPlayer() == null) { + return; + } + if (!getPlayer().isOnline()) { + plugin.getLogger().info("Could not update Quests Journal for " + getPlayer().getName() + " while offline"); + return; + } + final int index = getJournalIndex(); + if (index != -1) { + final QuestJournal journal = new QuestJournal(this); + getPlayer().getInventory().setItem(index, journal.toItemStack()); + } + } + + /** + * Start a quest for this Quester + * + * @param quest The quest to start + * @param ignoreRequirements Whether to ignore Requirements + */ + @SuppressWarnings("deprecation") + public void takeQuest(final BukkitQuest quest, final boolean ignoreRequirements) { + if (quest == null) { + return; + } + final QuesterPreStartQuestEvent preEvent = new QuesterPreStartQuestEvent(this, quest); + plugin.getServer().getPluginManager().callEvent(preEvent); + if (preEvent.isCancelled()) { + return; + } + final OfflinePlayer offlinePlayer = getOfflinePlayer(); + if (offlinePlayer.isOnline()) { + final BukkitPlanner pln = quest.getPlanner(); + final long currentTime = System.currentTimeMillis(); + final long start = pln.getStartInMillis(); // Start time in milliseconds since UTC epoch + final long end = pln.getEndInMillis(); // End time in milliseconds since UTC epoch + final long duration = end - start; // How long the quest can be active for + final long repeat = pln.getRepeat(); // Length to wait in-between start times + if (start != -1) { + if (currentTime < start) { + String early = Lang.get("plnTooEarly"); + early = early.replace("", ChatColor.AQUA + quest.getName() + ChatColor.YELLOW); + early = early.replace("

+ * + * Accepted strings are: breakBlock, damageBlock, placeBlock, useBlock, + * cutBlock, craftItem, smeltItem, enchantItem, brewItem, consumeItem, + * milkCow, catchFish, killMob, deliverItem, killPlayer, talkToNPC, + * killNPC, tameMob, shearSheep, password, reachLocation + * + * @deprecated Use {@link BukkitStage#containsObjective(ObjectiveType)} + * @param quest The quest to check objectives of + * @param name The type of objective to check for + * @return true if stage contains specified objective + */ + @Deprecated + public boolean containsObjective(final BukkitQuest quest, final String name) { + if (quest == null || getCurrentStage(quest) == null) { + return false; + } + return getCurrentStage(quest).containsObjective(ObjectiveType.fromName(name)); + } + + /** + * Check if player's current stage has the specified custom objective + * + * @param quest The quest to check custom objectives of + * @param name The exact name of custom objective to check for + * @return true if stage contains specified objective + */ + public boolean hasCustomObjective(final BukkitQuest quest, final String name) { + if (quest == null || getCurrentStage(quest) == null) { + return false; + } + for (final CustomObjective co : getCurrentStage(quest).getCustomObjectives()) { + if (co.getName().equals(name)) { + return true; + } + } + return false; + } + + /** + * Marks block as broken if Quester has such an objective + * + * @param quest The quest for which the block is being broken + * @param itemStack The block being broken + */ + @SuppressWarnings("deprecation") + public void breakBlock(final BukkitQuest quest, final ItemStack itemStack) { + itemStack.setAmount(0); + ItemStack broken = itemStack; + ItemStack toBreak = itemStack; + for (final ItemStack is : getQuestData(quest).blocksBroken) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + broken = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + broken = is; + } + } else if (itemStack.getData() instanceof Crops && is.getData() instanceof Crops) { + if (is.getDurability() > 0) { + // Age is specified so check for durability + if (itemStack.getDurability() == is.getDurability()) { + broken = is; + } + } else { + // Age is unspecified so ignore durability + broken = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + broken = is; + } + } else { + // Blocks are not solid so ignore durability + broken = is; + } + } + } + for (final ItemStack is : getCurrentStage(quest).getBlocksToBreak()) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toBreak = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + toBreak = is; + } + } else if (itemStack.getData() instanceof Crops && is.getData() instanceof Crops) { + if (is.getDurability() > 0) { + // Age is specified so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toBreak = is; + } + } else { + // Age is unspecified so ignore durability + toBreak = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toBreak = is; + } + } else { + // Blocks are not solid so ignore durability + toBreak = is; + } + } + } + + final ObjectiveType type = ObjectiveType.BREAK_BLOCK; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, broken.getAmount(), toBreak.getAmount())); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final ItemStack newBroken = broken; + if (broken.getAmount() < toBreak.getAmount()) { + newBroken.setAmount(broken.getAmount() + 1); + if (getQuestData(quest).blocksBroken.contains(broken)) { + getQuestData(quest).blocksBroken.set(getQuestData(quest).blocksBroken.indexOf(broken), newBroken); + if (broken.getAmount() == toBreak.getAmount()) { + finishObjective(quest, new BukkitObjective(type, itemStack, toBreak), null, null, null, null, null, null, null); + + // Multiplayer + final ItemStack finalBroken = broken; + final ItemStack finalToBreak = toBreak; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).blocksBroken.set(getQuestData(quest).blocksBroken + .indexOf(finalBroken), newBroken); + q.finishObjective(quest, new BukkitObjective(type, itemStack, finalToBreak), null, null, null, null, null, + null, null); + return null; + }); + } + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newBroken.getAmount(), toBreak.getAmount())); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks block as damaged if Quester has such an objective + * + * @param quest The quest for which the block is being damaged + * @param itemStack The block being damaged + */ + @SuppressWarnings("deprecation") + public void damageBlock(final BukkitQuest quest, final ItemStack itemStack) { + itemStack.setAmount(0); + ItemStack damaged = itemStack; + ItemStack toDamage = itemStack; + for (final ItemStack is : getQuestData(quest).blocksDamaged) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + damaged = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + damaged = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + damaged = is; + } + } else { + // Blocks are not solid so ignore durability + damaged = is; + } + } + } + for (final ItemStack is : getCurrentStage(quest).getBlocksToDamage()) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toDamage = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + toDamage = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toDamage = is; + } + } else { + // Blocks are not solid so ignore durability + toDamage = is; + } + } + } + + final ObjectiveType type = ObjectiveType.DAMAGE_BLOCK; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, damaged.getAmount(), toDamage.getAmount())); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final ItemStack newDamaged = damaged; + if (damaged.getAmount() < toDamage.getAmount()) { + + newDamaged.setAmount(damaged.getAmount() + 1); + if (getQuestData(quest).blocksDamaged.contains(damaged)) { + getQuestData(quest).blocksDamaged.set(getQuestData(quest).blocksDamaged.indexOf(damaged), newDamaged); + if (damaged.getAmount() == toDamage.getAmount()) { + finishObjective(quest, new BukkitObjective(type, itemStack, toDamage), null, null, null, null, null, null, null); + + // Multiplayer + final ItemStack finalDamaged = damaged; + final ItemStack finalToDamage = toDamage; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).blocksDamaged.set(getQuestData(quest).blocksDamaged + .indexOf(finalDamaged), newDamaged); + q.finishObjective(quest, new BukkitObjective(type, itemStack, finalToDamage), null, null, null, null, null, + null, null); + return null; + }); + } + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newDamaged.getAmount(), toDamage.getAmount())); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks block as placed if Quester has such an objective + * + * @param quest The quest for which the block is being placed + * @param itemStack The block being placed + */ + @SuppressWarnings("deprecation") + public void placeBlock(final BukkitQuest quest, final ItemStack itemStack) { + itemStack.setAmount(0); + ItemStack placed = itemStack; + ItemStack toPlace = itemStack; + for (final ItemStack is : getQuestData(quest).blocksPlaced) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + placed = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + placed = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + placed = is; + } + } else { + // Blocks are not solid so ignore durability + placed = is; + } + } + } + for (final ItemStack is : getCurrentStage(quest).getBlocksToPlace()) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toPlace = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + toPlace = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toPlace = is; + } + } else { + // Blocks are not solid so ignore durability + toPlace = is; + } + } + } + + final ObjectiveType type = ObjectiveType.PLACE_BLOCK; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, placed.getAmount(), toPlace.getAmount())); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final ItemStack newPlaced = placed; + if (placed.getAmount() < toPlace.getAmount()) { + newPlaced.setAmount(placed.getAmount() + 1); + if (getQuestData(quest).blocksPlaced.contains(placed)) { + getQuestData(quest).blocksPlaced.set(getQuestData(quest).blocksPlaced.indexOf(placed), newPlaced); + if (placed.getAmount() == toPlace.getAmount()) { + finishObjective(quest, new BukkitObjective(type, itemStack, toPlace), null, null, null, null, null, null, null); + + // Multiplayer + final ItemStack finalPlaced = placed; + final ItemStack finalToPlace = toPlace; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).blocksPlaced.set(getQuestData(quest).blocksPlaced + .indexOf(finalPlaced), newPlaced); + q.finishObjective(quest, new BukkitObjective(type, itemStack, finalToPlace), null, null, null, null, null, + null, null); + return null; + }); + } + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newPlaced.getAmount(), toPlace.getAmount())); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks block as used if Quester has such an objective + * + * @param quest The quest for which the block is being used + * @param itemStack The block being used + */ + @SuppressWarnings("deprecation") + public void useBlock(final BukkitQuest quest, final ItemStack itemStack) { + itemStack.setAmount(0); + ItemStack used = itemStack; + ItemStack toUse = itemStack; + for (final ItemStack is : getQuestData(quest).blocksUsed) { + if (itemStack.getType() == is.getType() ) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + used = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + used = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + used = is; + } + } else { + // Blocks are not solid so ignore durability + used = is; + } + } + } + for (final ItemStack is : getCurrentStage(quest).getBlocksToUse()) { + if (itemStack.getType() == is.getType() ) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid, so check durability + if (itemStack.getDurability() == is.getDurability()) { + toUse = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + toUse = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toUse = is; + } + } else { + // Blocks are not solid, so ignore durability + toUse = is; + } + } + } + + final ObjectiveType type = ObjectiveType.USE_BLOCK; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, used.getAmount(), toUse.getAmount())); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final ItemStack newUsed = used; + if (used.getAmount() < toUse.getAmount()) { + newUsed.setAmount(used.getAmount() + 1); + if (getQuestData(quest).blocksUsed.contains(used)) { + getQuestData(quest).blocksUsed.set(getQuestData(quest).blocksUsed.indexOf(used), newUsed); + if (used.getAmount() == toUse.getAmount()) { + finishObjective(quest, new BukkitObjective(type, itemStack, toUse), null, null, null, null, null, null, null); + + // Multiplayer + final ItemStack finalUsed = used; + final ItemStack finalToUse = toUse; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).blocksUsed.set(getQuestData(quest).blocksUsed + .indexOf(finalUsed), newUsed); + q.finishObjective(quest, new BukkitObjective(type, itemStack, finalToUse), null, null, null, null, null, null, + null); + return null; + }); + } + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newUsed.getAmount(), toUse.getAmount())); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks block as cut if Quester has such an objective + * + * @param quest The quest for which the block is being cut + * @param itemStack The block being cut + */ + @SuppressWarnings("deprecation") + public void cutBlock(final BukkitQuest quest, final ItemStack itemStack) { + itemStack.setAmount(0); + ItemStack cut = itemStack; + ItemStack toCut = itemStack; + for (final ItemStack is : getQuestData(quest).blocksCut) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + cut = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + cut = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + cut = is; + } + } else { + // Blocks are not solid so ignore durability + cut = is; + } + } + } + for (final ItemStack is : getCurrentStage(quest).getBlocksToCut()) { + if (itemStack.getType() == is.getType()) { + if (itemStack.getType().isSolid() && is.getType().isSolid()) { + // Blocks are solid so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toCut = is; + } else if (!plugin.getLocaleManager().isBelow113()) { + // Ignore durability for 1.13+ + toCut = is; + } + } else if (itemStack.getType().name().equals("RED_ROSE")) { + // Flowers are unique so check for durability + if (itemStack.getDurability() == is.getDurability()) { + toCut = is; + } + } else { + // Blocks are not solid so ignore durability + toCut = is; + } + } + } + + final ObjectiveType type = ObjectiveType.CUT_BLOCK; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, cut.getAmount(), toCut.getAmount())); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final ItemStack newCut = cut; + if (cut.getAmount() < toCut.getAmount()) { + newCut.setAmount(cut.getAmount() + 1); + if (getQuestData(quest).blocksCut.contains(cut)) { + getQuestData(quest).blocksCut.set(getQuestData(quest).blocksCut.indexOf(cut), newCut); + if (cut.getAmount() == toCut.getAmount()) { + finishObjective(quest, new BukkitObjective(type, itemStack, toCut), null, null, null, null, null, null, null); + + // Multiplayer + final ItemStack finalCut = cut; + final ItemStack finalToCut = toCut; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).blocksCut.set(getQuestData(quest).blocksCut.indexOf(finalCut), newCut); + q.finishObjective(quest, new BukkitObjective(type, itemStack, finalToCut), null, null, null, null, null, null, + null); + return null; + }); + } + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newCut.getAmount(), toCut.getAmount())); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark item as crafted if Quester has such an objective + * + * @param quest The quest for which the item is being crafted + * @param itemStack The item being crafted + */ + public void craftItem(final BukkitQuest quest, final ItemStack itemStack) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsCrafted) { + currentIndex++; + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsCrafted); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toCraft = getCurrentStage(quest).getItemsToCraft().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.CRAFT_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toCraft)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toCraft) { + if (newAmount >= toCraft) { + found.setAmount(toCraft); + getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsCrafted.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newAmount, toCraft)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark item as smelted if Quester has such an objective + * + * @param quest The quest for which the item is being smelted + * @param itemStack The item being smelted + */ + public void smeltItem(final BukkitQuest quest, final ItemStack itemStack) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsSmelted) { + currentIndex++; + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsSmelted); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toSmelt = getCurrentStage(quest).getItemsToSmelt().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.SMELT_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toSmelt)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toSmelt) { + if (newAmount >= toSmelt) { + found.setAmount(toSmelt); + getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsSmelted.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newAmount, toSmelt)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark book as enchanted if Quester has such an objective + * + * @param quest The quest for which the item is being enchanted + * @param itemStack The book being enchanted + */ + public void enchantBook(final BukkitQuest quest, final ItemStack itemStack, + final Map enchantsToAdd) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsEnchanted) { + currentIndex++; + if (is.getItemMeta() instanceof EnchantmentStorageMeta) { + if (((EnchantmentStorageMeta)is.getItemMeta()).getStoredEnchants().equals(enchantsToAdd)) { + matches.add(currentIndex); + } + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsEnchanted); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toEnchant = getCurrentStage(quest).getItemsToEnchant().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.ENCHANT_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toEnchant)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toEnchant) { + if (newAmount >= toEnchant) { + found.setAmount(toEnchant); + getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, itemStack.getAmount() + amount, toEnchant)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark item as enchanted if Quester has such an objective + * + * @param quest The quest for which the item is being enchanted + * @param itemStack The item being enchanted + */ + public void enchantItem(final BukkitQuest quest, final ItemStack itemStack) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + if (!itemStack.getType().equals(Material.BOOK)) { + for (final ItemStack is : getQuestData(quest).itemsEnchanted) { + currentIndex++; + if (!is.getEnchantments().isEmpty()) { + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } else { + if (ItemUtil.compareItems(itemStack, is, true) == -4) { + matches.add(currentIndex); + } + } + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsEnchanted); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toEnchant = getCurrentStage(quest).getItemsToEnchant().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.ENCHANT_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toEnchant)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toEnchant) { + if (newAmount >= toEnchant) { + found.setAmount(toEnchant); + getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsEnchanted.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, itemStack.getAmount() + amount, toEnchant)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark item as brewed if Quester has such an objective + * + * @param quest The quest for which the item is being brewed + * @param itemStack The item being brewed + */ + public void brewItem(final BukkitQuest quest, final ItemStack itemStack) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsBrewed) { + currentIndex++; + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsBrewed); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toBrew = getCurrentStage(quest).getItemsToBrew().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.BREW_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toBrew)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toBrew) { + if (newAmount >= toBrew) { + found.setAmount(toBrew); + getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsBrewed.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newAmount, toBrew)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark item as consumed if Quester has such an objective + * + * @param quest The quest for which the item is being consumed + * @param itemStack The item being consumed + */ + public void consumeItem(final BukkitQuest quest, final ItemStack itemStack) { + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsConsumed) { + currentIndex++; + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } + if (matches.isEmpty()) { + return; + } + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsConsumed); + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toConsume = getCurrentStage(quest).getItemsToConsume().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.CONSUME_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toConsume)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toConsume) { + if (newAmount >= toConsume) { + found.setAmount(toConsume); + getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsConsumed.set(items.indexOf(found), found); + } + return; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newAmount, toConsume)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark item as delivered to a NPC if Quester has such an objective + * + * @param quest The quest for which the item is being delivered + * @param npc The NPC being delivered to + * @param itemStack The item being delivered + */ + public void deliverToNPC(final BukkitQuest quest, final NPC npc, final ItemStack itemStack) { + if (npc == null) { + return; + } + + int currentIndex = -1; + final LinkedList matches = new LinkedList<>(); + for (final ItemStack is : getQuestData(quest).itemsDelivered) { + currentIndex++; + if (ItemUtil.compareItems(itemStack, is, true) == 0) { + matches.add(currentIndex); + } + } + if (matches.isEmpty()) { + return; + } + final Player player = getPlayer(); + for (final Integer match : matches) { + final LinkedList items = new LinkedList<>(getQuestData(quest).itemsDelivered); + if (!getCurrentStage(quest).getItemDeliveryTargets().get(match).equals(npc.getId())) { + continue; + } + final ItemStack found = items.get(match); + final int amount = found.getAmount(); + final int toDeliver = getCurrentStage(quest).getItemsToDeliver().get(match).getAmount(); + + final ObjectiveType type = ObjectiveType.DELIVER_ITEM; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, amount, toDeliver)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newAmount = itemStack.getAmount() + amount; + final Material m = itemStack.getType(); + if (amount < toDeliver) { + final int index = player.getInventory().first(itemStack); + if (index == -1) { + // Already delivered in previous loop + return; + } + if (newAmount >= toDeliver) { + found.setAmount(toDeliver); + getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); + if ((itemStack.getAmount() + amount) >= toDeliver) { + // Take away remaining amount to be delivered + final ItemStack clone = itemStack.clone(); + clone.setAmount(itemStack.getAmount() - (toDeliver - amount)); + player.getInventory().setItem(index, clone); + } else { + player.getInventory().setItem(index, null); + } + player.updateInventory(); + finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, null, + null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(m, 1), found), null, null, null, + null, null, null, null); + return null; + }); + } else { + found.setAmount(newAmount); + getQuestData(quest).itemsDelivered.set(items.indexOf(found), found.clone()); + player.getInventory().setItem(index, null); + player.updateInventory(); + final String[] message = ConfigUtil.parseStringWithPossibleLineBreaks(getCurrentStage(quest) + .getDeliverMessages().get(new Random().nextInt(getCurrentStage(quest).getDeliverMessages() + .size())), plugin.getDependencies().getCitizens().getNPCRegistry() + .getById(getCurrentStage(quest).getItemDeliveryTargets().get(items.indexOf(found)))); + player.sendMessage(message); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newAmount, toDeliver)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark NPC as interacted with if Quester has such an objective + * + * @param quest The quest for which the NPC is being interacted with + * @param npc The NPC being interacted with + */ + public void interactWithNPC(final BukkitQuest quest, final NPC npc) { + if (!getCurrentStage(quest).getCitizensToInteract().contains(npc.getId())) { + return; + } + + final int index = getCurrentStage(quest).getCitizensToInteract().indexOf(npc.getId()); + final boolean npcsInteracted = getQuestData(quest).citizensInteracted.get(index); + + final ObjectiveType type = ObjectiveType.TALK_TO_NPC; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, 1, 1)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + if (!npcsInteracted) { + getQuestData(quest).citizensInteracted.set(index, true); + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, npc, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).citizensInteracted.set(index, true); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, npc, null, null, null, null); + return null; + }); + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, 1, 1)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + } + + /** + * Mark NPC as killed if the Quester has such an objective + * + * @param quest The quest for which the NPC is being killed + * @param npc The NPC being killed + */ + public void killNPC(final BukkitQuest quest, final NPC npc) { + if (!getCurrentStage(quest).getCitizensToKill().contains(npc.getId())) { + return; + } + + final int index = getCurrentStage(quest).getCitizensToKill().indexOf(npc.getId()); + final int npcsKilled = getQuestData(quest).citizensNumKilled.get(index); + final int npcsToKill = getCurrentStage(quest).getMobNumToKill().get(index); + + final ObjectiveType type = ObjectiveType.KILL_NPC; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, npcsKilled, npcsToKill)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newNpcsKilled = getQuestData(quest).citizensNumKilled.get(index) + 1; + if (npcsKilled < npcsToKill) { + getQuestData(quest).citizensNumKilled.set(index, newNpcsKilled); + if (newNpcsKilled >= npcsToKill) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, npcsToKill)), null, null, npc, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).citizensNumKilled.set(index, getQuestData(quest).citizensNumKilled + .get(index)); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, npcsToKill)), null, null, npc, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newNpcsKilled, npcsToKill)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks cow as milked if Quester has such an objective + * + * @param quest The quest for which the fish is being caught + */ + public void milkCow(final BukkitQuest quest) { + final QuestData questData = getQuestData(quest); + if (questData == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage == null) { + return; + } + if (currentStage.getCowsToMilk() == null) { + return; + } + + final int cowsMilked = questData.getCowsMilked(); + final int cowsToMilk = currentStage.getCowsToMilk(); + + final ObjectiveType type = ObjectiveType.MILK_COW; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, cowsMilked, cowsToMilk)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newCowsMilked = cowsMilked + 1; + if (cowsMilked < cowsToMilk) { + questData.setCowsMilked(newCowsMilked); + + if (newCowsMilked >= cowsToMilk) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, cowsToMilk)), null, null, null, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).setCowsMilked(cowsToMilk); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, cowsToMilk)), null, null, null, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newCowsMilked, cowsToMilk)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Marks fish as caught if Quester has such an objective + * + * @param quest The quest for which the fish is being caught + */ + public void catchFish(final BukkitQuest quest) { + final QuestData questData = getQuestData(quest); + if (questData == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage == null) { + return; + } + if (currentStage.getFishToCatch() == null) { + return; + } + + final int fishCaught = questData.getFishCaught(); + final int fishToCatch = currentStage.getFishToCatch(); + + final ObjectiveType type = ObjectiveType.CATCH_FISH; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, fishCaught, fishToCatch)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newFishCaught = fishCaught + 1; + if (fishCaught < fishToCatch) { + questData.setFishCaught(newFishCaught); + + if (newFishCaught >= fishToCatch) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, fishToCatch)), null, null, null, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).setFishCaught(fishToCatch); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, fishToCatch)), null, null, null, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newFishCaught, fishToCatch)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark mob as killed if Quester has such an objective + * + * @param quest The quest for which the mob is being killed + * @param killedLocation The optional location to kill at + * @param entityType The mob to be killed + */ + public void killMob(final BukkitQuest quest, final Location killedLocation, final EntityType entityType) { + final QuestData questData = getQuestData(quest); + if (entityType == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage.getMobsToKill() == null) { + return; + } + final int index = currentStage.getMobsToKill().indexOf(entityType); + if (index == -1) { + return; + } + final int mobsKilled = questData.mobNumKilled.get(index); + final int mobsToKill = currentStage.getMobNumToKill().get(index); + if (!currentStage.getLocationsToKillWithin().isEmpty()) { + final Location locationToKillWithin = currentStage.getLocationsToKillWithin().get(index); + final double radius = currentStage.getRadiiToKillWithin().get(index); + if (killedLocation.getWorld() == null || locationToKillWithin.getWorld() == null) { + return; + } + if (!(killedLocation.getWorld().getName().equals(locationToKillWithin.getWorld().getName()))) { + return; + } + if (!(killedLocation.getX() < (locationToKillWithin.getX() + radius) && killedLocation.getX() + > (locationToKillWithin.getX() - radius))) { + return; + } + if (!(killedLocation.getZ() < (locationToKillWithin.getZ() + radius) && killedLocation.getZ() + > (locationToKillWithin.getZ() - radius))) { + return; + } + if (!(killedLocation.getY() < (locationToKillWithin.getY() + radius) && killedLocation.getY() + > (locationToKillWithin.getY() - radius))) { + return; + } + } + final ObjectiveType type = ObjectiveType.KILL_MOB; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, mobsKilled, mobsToKill)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newMobsKilled = mobsKilled + 1; + if (mobsKilled < mobsToKill) { + questData.mobNumKilled.set(index, newMobsKilled); + if (newMobsKilled >= mobsToKill) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, mobsToKill)), entityType, null, null, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, currentStage, (final BukkitQuester q) -> { + q.getQuestData(quest).mobNumKilled.set(index, newMobsKilled); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, mobsToKill)), entityType, null, null, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newMobsKilled, mobsToKill)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark player as killed if Quester has such an objective + * + * @param quest The quest for which the player is being killed + * @param player The player to be killed + */ + public void killPlayer(final BukkitQuest quest, final Player player) { + final QuestData questData = getQuestData(quest); + if (questData == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage == null) { + return; + } + if (currentStage.getPlayersToKill() == null) { + return; + } + + final int playersKilled = questData.getPlayersKilled(); + final int playersToKill = currentStage.getPlayersToKill(); + + final ObjectiveType type = ObjectiveType.KILL_PLAYER; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, playersKilled, playersToKill)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newPlayersKilled = playersKilled + 1; + if (playersKilled < playersToKill) { + questData.setPlayersKilled(newPlayersKilled); + if (newPlayersKilled >= playersToKill) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, playersToKill)), null, null, null, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).setPlayersKilled(getQuestData(quest).getPlayersKilled()); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, playersToKill)), null, null, null, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newPlayersKilled, playersToKill)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark location as reached if the Quester has such an objective + * + * @param quest The quest for which the location is being reached + * @param location The location being reached + */ + public void reachLocation(final BukkitQuest quest, final Location location) { + if (getQuestData(quest) == null || getCurrentStage(quest) == null + || getCurrentStage(quest).getLocationsToReach() == null + || getQuestData(quest).locationsReached == null) { + return; + } + + // TODO redo this + int locationsReached = 0; + for (final Boolean b : getQuestData(quest).locationsReached) { + if (b) { + locationsReached++; + } + } + final int locationsToReach = getCurrentStage(quest).getLocationsToReach().size(); + + int index = 0; + try { + for (final Location toReach : getCurrentStage(quest).getLocationsToReach()) { + if (location.getWorld() == null || toReach.getWorld() == null) { + index++; + continue; + } + if (!location.getWorld().getName().equals(toReach.getWorld().getName())) { + index++; + continue; + } + final double radius = getCurrentStage(quest).getRadiiToReachWithin().get(index); + if (toReach.distanceSquared(location) <= radius * radius) { + if (!getQuestData(quest).locationsReached.get(index)) { + final ObjectiveType type = ObjectiveType.REACH_LOCATION; + final QuesterPreUpdateObjectiveEvent preEvent + = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, locationsReached, locationsToReach)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + getQuestData(quest).locationsReached.set(index, true); + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, null, toReach, null, null, + null); + + // Multiplayer + final int finalIndex = index; + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).locationsReached.set(finalIndex, true); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, null, toReach, null, + null, null); + return null; + }); + + final QuesterPostUpdateObjectiveEvent postEvent + = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, locationsReached + 1, locationsToReach)); + plugin.getServer().getPluginManager().callEvent(postEvent); + + break; + } + } + index++; + } + } catch (final Exception e) { + plugin.getLogger().severe("An error has occurred with Quests. Please report on Github with info below"); + plugin.getLogger().warning("quest = " + quest.getId()); + plugin.getLogger().warning("index = " + index); + plugin.getLogger().warning("location = " + location.toString()); + plugin.getLogger().warning("locationsToReach = " + getCurrentStage(quest).getLocationsToReach().size()); + plugin.getLogger().warning("locationsReached = " + getQuestData(quest).locationsReached.size()); + plugin.getLogger().warning("hasReached = " + getQuestData(quest).locationsReached.size()); + e.printStackTrace(); + } + } + + /** + * Mark mob as tamed if the Quester has such an objective + * + * @param quest The quest for which the mob is being tamed + * @param entityType The type of mob being tamed + */ + public void tameMob(final BukkitQuest quest, final EntityType entityType) { + final QuestData questData = getQuestData(quest); + if (entityType == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage.getMobsToTame() == null) { + return; + } + + final int index = currentStage.getMobsToTame().indexOf(entityType); + if (index == -1) { + return; + } + + final int mobsToTame = currentStage.getMobNumToTame().get(index); + final int mobsTamed = questData.mobsTamed.get(index); + + final ObjectiveType type = ObjectiveType.TAME_MOB; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, mobsToTame, mobsTamed)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newMobsToTame = mobsTamed + 1; + if (mobsTamed < mobsToTame) { + getQuestData(quest).mobsTamed.set(index, newMobsToTame); + if (newMobsToTame >= mobsToTame) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, mobsToTame)), entityType, null, null, null, null, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).mobsTamed.set(index, newMobsToTame); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, mobsToTame)), entityType, null, null, null, null, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newMobsToTame, mobsTamed)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark sheep as sheared if the Quester has such an objective + * + * @param quest The quest for which the sheep is being sheared + * @param color The wool color of the sheep being sheared + */ + public void shearSheep(final BukkitQuest quest, final DyeColor color) { + final QuestData questData = getQuestData(quest); + if (color == null) { + return; + } + final BukkitStage currentStage = getCurrentStage(quest); + if (currentStage.getSheepToShear() == null) { + return; + } + + final int index = currentStage.getSheepToShear().indexOf(color); + if (index == -1) { + return; + } + + final int sheepToShear = getCurrentStage(quest).getSheepNumToShear().get(index); + final int sheepSheared = questData.sheepSheared.get(index); + + final ObjectiveType type = ObjectiveType.SHEAR_SHEEP; + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, sheepSheared, sheepToShear)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + final int newSheepSheared = sheepSheared + 1; + if (sheepSheared < sheepToShear) { + getQuestData(quest).sheepSheared.set(index, newSheepSheared); + if (newSheepSheared >= sheepToShear) { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, sheepToShear)), null, null, null, null, color, null, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).sheepSheared.set(index, newSheepSheared); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, sheepToShear)), null, null, null, null, color, null, null); + return null; + }); + } + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, newSheepSheared, sheepToShear)); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Mark password as entered if the Quester has such an objective + * + * @param quest The quest for which the password is being entered + * @param evt The event during which the password was entered + */ + public void sayPassword(final BukkitQuest quest, final AsyncPlayerChatEvent evt) { + final ObjectiveType type = ObjectiveType.PASSWORD; + plugin.getServer().getScheduler().runTask(plugin, () -> { + final QuesterPreUpdateObjectiveEvent preEvent = new QuesterPreUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, 1, 1)); + plugin.getServer().getPluginManager().callEvent(preEvent); + + int index = 0; + for (final String pass : getCurrentStage(quest).getPasswordPhrases()) { + if (pass.equalsIgnoreCase(evt.getMessage())) { + final String display = getCurrentStage(quest).getPasswordDisplays().get(index); + getQuestData(quest).passwordsSaid.set(index, true); + + final int finalIndex = index; + plugin.getServer().getScheduler().runTask(plugin, () -> { + finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, null, null, null, display, null); + + // Multiplayer + dispatchMultiplayerObjectives(quest, getCurrentStage(quest), (final BukkitQuester q) -> { + q.getQuestData(quest).passwordsSaid.set(finalIndex, true); + q.finishObjective(quest, new BukkitObjective(type, new ItemStack(Material.AIR, 1), + new ItemStack(Material.AIR, 1)), null, null, null, null, null, display, null); + return null; + }); + }); + break; + } + index++; + } + + final QuesterPostUpdateObjectiveEvent postEvent = new QuesterPostUpdateObjectiveEvent(this, quest, + new BukkitObjective(type, 1, 1)); + plugin.getServer().getPluginManager().callEvent(postEvent); + }); + } + + /** + * Complete a quest objective + * + * @param quest + * Quest containing the objective + * @param objective + * Objective for type, progress and goal + * @param mob + * Mob being killed or tamed, if any + * @param extra + * Extra mob enum like career or ocelot type, if any + * @param npc + * NPC being talked to or killed, if any + * @param location + * Location for user to reach, if any + * @param color + * Shear color, if any + * @param pass + * Password, if any + * @param co + * Custom objective, if any. See {@link CustomObjective} + */ + @SuppressWarnings("deprecation") + public void finishObjective(final BukkitQuest quest, final BukkitObjective objective, final EntityType mob, + final String extra, final NPC npc, final Location location, final DyeColor color, + final String pass, final CustomObjective co) { + if (objective == null) { + return; + } + final Player p = getPlayer(); + final ObjectiveType type = objective.getType(); + final ItemStack increment = objective.getItemProgress() != null ? objective.getItemProgress() + : new ItemStack(Material.AIR, objective.getProgress()); + final ItemStack goal = objective.getItemGoal() != null ? objective.getItemGoal() + : new ItemStack(Material.AIR, objective.getGoal()); + if (!getCurrentStage(quest).getObjectiveOverrides().isEmpty()) { + for (final String s: getCurrentStage(quest).getObjectiveOverrides()) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + + ConfigUtil.parseString(ChatColor.translateAlternateColorCodes('&', s), quest, p); + if (plugin.getDependencies().getPlaceholderApi() != null) { + message = PlaceholderAPI.setPlaceholders(p, message); + } + sendMessage(message); + } + } else if (type.equals(ObjectiveType.BREAK_BLOCK)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "break"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), + null)) { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else if (type.equals(ObjectiveType.DAMAGE_BLOCK)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "damage"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), + null)) { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else if (type.equals(ObjectiveType.PLACE_BLOCK)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "place"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), + null)) { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else if (type.equals(ObjectiveType.USE_BLOCK)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "use"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), + null)) { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else if (type.equals(ObjectiveType.CUT_BLOCK)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "cut"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, increment.getType(), increment.getDurability(), + null)) { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(increment))); + } + } else if (type.equals(ObjectiveType.CRAFT_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToCraft().get(getCurrentStage(quest).getItemsToCraft() + .indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "craftItem"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (type.equals(ObjectiveType.SMELT_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToSmelt().get(getCurrentStage(quest).getItemsToSmelt() + .indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "smeltItem"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (type.equals(ObjectiveType.ENCHANT_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToEnchant().get(getCurrentStage(quest) + .getItemsToEnchant().indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "enchItem"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && is.hasItemMeta() && !is.getItemMeta().hasDisplayName()) { + // Bukkit version is 1.9+ + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), + goal.getEnchantments(), goal.getItemMeta())) { + for (final Entry e : is.getEnchantments().entrySet()) { + sendMessage(message.replace("", ItemUtil.getName(is)) + .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) + .replace("", RomanNumeral.getNumeral(e.getValue()))); + } + } + } else if (plugin.getSettings().canTranslateNames() && !is.hasItemMeta() + && Material.getMaterial("LINGERING_POTION") == null) { + // Bukkit version is below 1.9 + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), + goal.getEnchantments())) { + for (final Entry e : is.getEnchantments().entrySet()) { + sendMessage(message.replace("", ItemUtil.getName(is)) + .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) + .replace("", RomanNumeral.getNumeral(e.getValue()))); + } + } + } else { + for (final Entry e : is.getEnchantments().entrySet()) { + sendMessage(message.replace("", ItemUtil.getName(is)) + .replace("", ItemUtil.getPrettyEnchantmentName(e.getKey())) + .replace("", RomanNumeral.getNumeral(e.getValue()))); + } + } + } else if (type.equals(ObjectiveType.BREW_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToBrew().get(getCurrentStage(quest).getItemsToBrew() + .indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "brewItem"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && is.hasItemMeta() && !is.getItemMeta().hasDisplayName()) { + // Bukkit version is 1.9+ + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), + goal.getEnchantments(), goal.getItemMeta())) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (plugin.getSettings().canTranslateNames() && !is.hasItemMeta() + && Material.getMaterial("LINGERING_POTION") == null) { + // Bukkit version is below 1.9 + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), + goal.getEnchantments())) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (type.equals(ObjectiveType.CONSUME_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToConsume().get(getCurrentStage(quest) + .getItemsToConsume().indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "consumeItem"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, goal.getType(), goal.getDurability(), null)) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (type.equals(ObjectiveType.DELIVER_ITEM)) { + final ItemStack is = getCurrentStage(quest).getItemsToDeliver().get(getCurrentStage(quest) + .getItemsToDeliver().indexOf(goal)); + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "deliver") + .replace("", plugin.getDependencies().getNPCName(getCurrentStage(quest) + .getItemDeliveryTargets().get(getCurrentStage(quest).getItemsToDeliver().indexOf(goal)))); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + is.getAmount() + "/" + is.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + is.getAmount() + "/" + is.getAmount(); + } + if (plugin.getSettings().canTranslateNames() && !goal.hasItemMeta() + && !goal.getItemMeta().hasDisplayName()) { + if (!plugin.getLocaleManager().sendMessage(p, message, is.getType(), is.getDurability(), null)) { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else { + sendMessage(message.replace("", ItemUtil.getName(is))); + } + } else if (type.equals(ObjectiveType.MILK_COW)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "milkCow"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + sendMessage(message); + } else if (type.equals(ObjectiveType.CATCH_FISH)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "catchFish"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + sendMessage(message); + } else if (type.equals(ObjectiveType.KILL_MOB)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "kill"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.AQUA + " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames()) { + if (!plugin.getLocaleManager().sendMessage(p, message, mob, extra)) { + sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); + } + } else { + sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); + } + } else if (type.equals(ObjectiveType.KILL_PLAYER)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "killPlayer"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + sendMessage(message); + } else if (type.equals(ObjectiveType.TALK_TO_NPC)) { + final String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "talkTo") + .replace("", plugin.getDependencies().getNPCName(npc.getId())); + sendMessage(message); + } else if (type.equals(ObjectiveType.KILL_NPC)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "kill"); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.AQUA + " " + ChatColor.GREEN + ": " + goal.getAmount() + "/" + + goal.getAmount(); + } + sendMessage(message.replace("", plugin.getDependencies().getNPCName(npc.getId()))); + } else if (type.equals(ObjectiveType.TAME_MOB)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "tame"); + if (!message.contains("")) { + message += " "; + } + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + if (plugin.getSettings().canTranslateNames()) { + if (!plugin.getLocaleManager().sendMessage(p, message, mob, extra)) { + sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); + } + } else { + sendMessage(message.replace("", MiscUtil.snakeCaseToUpperCamelCase(mob.name()))); + } + } else if (type.equals(ObjectiveType.SHEAR_SHEEP)) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + Lang.get(p, "shearSheep"); + message = message.replace("", MiscUtil.getPrettyDyeColorName(color)); + if (message.contains("")) { + message = message.replace("", "" + ChatColor.GREEN + goal.getAmount() + "/" + goal.getAmount()); + } else { + // Legacy + message += ChatColor.GREEN + ": " + goal.getAmount() + "/" + goal.getAmount(); + } + sendMessage(message); + } else if (type.equals(ObjectiveType.REACH_LOCATION)) { + String obj = Lang.get(p, "goTo"); + try { + obj = obj.replace("", getCurrentStage(quest).getLocationNames().get(getCurrentStage(quest) + .getLocationsToReach().indexOf(location))); + } catch(final IndexOutOfBoundsException e) { + plugin.getLogger().severe("Unable to get final location " + location + " for quest ID " + + quest.getId() + ", please report on Github"); + obj = obj.replace("", "ERROR"); + } + final String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + obj; + sendMessage(message); + } else if (type.equals(ObjectiveType.PASSWORD)) { + sendMessage(ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + pass); + } else if (co != null) { + String message = ChatColor.GREEN + "(" + Lang.get(p, "completed") + ") " + co.getDisplay(); + int index = -1; + for (int i = 0; i < getCurrentStage(quest).getCustomObjectives().size(); i++) { + if (getCurrentStage(quest).getCustomObjectives().get(i).getName().equals(co.getName())) { + index = i; + break; + } + } + final List> sub = new LinkedList<>(getCurrentStage(quest).getCustomObjectiveData() + .subList(index, getCurrentStage(quest).getCustomObjectiveData().size())); + final List> end = new LinkedList<>(sub); + sub.clear(); // Since sub is backed by end, this removes all sub-list items from end + for (final Entry dataMap : end) { + message = message.replace("%" + (dataMap.getKey()) + "%", String.valueOf(dataMap.getValue())); + } + + if (co.canShowCount()) { + message = message.replace("%count%", goal.getAmount() + "/" + goal.getAmount()); + } + sendMessage(ConfigUtil.parseString(ChatColor.translateAlternateColorCodes('&', message))); + } + if (testComplete(quest)) { + quest.nextStage(this, true); + } + } + + /** + * Complete quest objective + * + * @deprecated Use {@link #finishObjective(BukkitQuest, BukkitObjective, EntityType, + * String, NPC, Location, DyeColor, String, CustomObjective)} + * + * @param quest + * Quest containing the objective + * @param objective + * Type of objective, e.g. "password" or "damageBlock" + * @param increment + * Final amount material being applied + * @param goal + * Total required amount of material + * @param enchantment + * Enchantment being applied by user + * @param mob + * Mob being killed or tamed + * @param extra + * Extra mob enum like career or ocelot type + * @param npc + * NPC being talked to or killed + * @param location + * Location for user to reach + * @param color + * Shear color + * @param pass + * Password + * @param co + * See CustomObjective class + */ + @Deprecated + public void finishObjective(final BukkitQuest quest, final String objective, final ItemStack increment, + final ItemStack goal, final Enchantment enchantment, final EntityType mob, + final String extra, final NPC npc, final Location location, final DyeColor color, + final String pass, final CustomObjective co) { + if (objective == null) { + return; + } + if (increment == null || goal == null) { + finishObjective(quest, new BukkitObjective(ObjectiveType.fromName(objective), 1, 1), mob, extra, npc, + location, color, pass, co); + } else { + finishObjective(quest, new BukkitObjective(ObjectiveType.fromName(objective), increment, goal), mob, extra, + npc, location, color, pass, co); + } + } + + /** + * Check whether this Quester has completed all objectives for their current stage + * + * @param quest The quest with the current stage being checked + * @return true if all stage objectives are marked complete + */ + public boolean testComplete(final BukkitQuest quest) { + for (final String s : getCurrentObjectives(quest, true)) { + if (s.startsWith(ChatColor.GREEN.toString())) { + return false; + } + } + return true; + } + + /** + * Add empty map values per Quest stage + * + * @param quest Quest with at least one stage + * @param stage Where first stage is '0' + */ + @SuppressWarnings("deprecation") + public void addEmptiesFor(final BukkitQuest quest, final int stage) { + final QuestData data = new QuestData(this); + data.setDoJournalUpdate(false); + if (quest == null) { + plugin.getLogger().warning("Unable to find quest for player " + this.lastKnownName); + return; + } + if (quest.getStage(stage) == null) { + plugin.getLogger().severe("Unable to find Stage " + stage + " of quest ID " + quest.getId()); + return; + } + if (!quest.getStage(stage).getBlocksToBreak().isEmpty()) { + for (final ItemStack toBreak : quest.getStage(stage).getBlocksToBreak()) { + final ItemStack temp = new ItemStack(toBreak.getType(), 0, toBreak.getDurability()); + if (data.blocksBroken.contains(toBreak)) { + data.blocksBroken.set(data.blocksBroken.indexOf(temp), temp); + } else { + data.blocksBroken.add(temp); + } + } + } + if (!quest.getStage(stage).getBlocksToDamage().isEmpty()) { + for (final ItemStack toDamage : quest.getStage(stage).getBlocksToDamage()) { + final ItemStack temp = new ItemStack(toDamage.getType(), 0, toDamage.getDurability()); + if (data.blocksDamaged.contains(toDamage)) { + data.blocksDamaged.set(data.blocksDamaged.indexOf(temp), temp); + } else { + data.blocksDamaged.add(temp); + } + } + } + if (!quest.getStage(stage).getBlocksToPlace().isEmpty()) { + for (final ItemStack toPlace : quest.getStage(stage).getBlocksToPlace()) { + final ItemStack temp = new ItemStack(toPlace.getType(), 0, toPlace.getDurability()); + if (data.blocksPlaced.contains(toPlace)) { + data.blocksPlaced.set(data.blocksPlaced.indexOf(temp), temp); + } else { + data.blocksPlaced.add(temp); + } + } + } + if (!quest.getStage(stage).getBlocksToUse().isEmpty()) { + for (final ItemStack toUse : quest.getStage(stage).getBlocksToUse()) { + final ItemStack temp = new ItemStack(toUse.getType(), 0, toUse.getDurability()); + if (data.blocksUsed.contains(toUse)) { + data.blocksUsed.set(data.blocksUsed.indexOf(temp), temp); + } else { + data.blocksUsed.add(temp); + } + } + } + if (!quest.getStage(stage).getBlocksToCut().isEmpty()) { + for (final ItemStack toCut : quest.getStage(stage).getBlocksToCut()) { + final ItemStack temp = new ItemStack(toCut.getType(), 0, toCut.getDurability()); + if (data.blocksCut.contains(toCut)) { + data.blocksCut.set(data.blocksCut.indexOf(temp), temp); + } else { + data.blocksCut.add(temp); + } + } + } + if (!quest.getStage(stage).getItemsToCraft().isEmpty()) { + for (final ItemStack toCraft : quest.getStage(stage).getItemsToCraft()) { + final ItemStack temp = new ItemStack(toCraft.getType(), 0, toCraft.getDurability()); + temp.addUnsafeEnchantments(toCraft.getEnchantments()); + temp.setItemMeta(toCraft.getItemMeta()); + data.itemsCrafted.add(temp); + } + } + if (!quest.getStage(stage).getItemsToSmelt().isEmpty()) { + for (final ItemStack toSmelt : quest.getStage(stage).getItemsToSmelt()) { + final ItemStack temp = new ItemStack(toSmelt.getType(), 0, toSmelt.getDurability()); + temp.addUnsafeEnchantments(toSmelt.getEnchantments()); + temp.setItemMeta(toSmelt.getItemMeta()); + data.itemsSmelted.add(temp); + } + } + if (!quest.getStage(stage).getItemsToEnchant().isEmpty()) { + for (final ItemStack toEnchant : quest.getStage(stage).getItemsToEnchant()) { + final ItemStack temp = new ItemStack(toEnchant.getType(), 0, toEnchant.getDurability()); + temp.addUnsafeEnchantments(toEnchant.getEnchantments()); + temp.setItemMeta(toEnchant.getItemMeta()); + data.itemsEnchanted.add(temp); + } + } + if (!quest.getStage(stage).getItemsToBrew().isEmpty()) { + for (final ItemStack toBrew : quest.getStage(stage).getItemsToBrew()) { + final ItemStack temp = new ItemStack(toBrew.getType(), 0, toBrew.getDurability()); + temp.addUnsafeEnchantments(toBrew.getEnchantments()); + temp.setItemMeta(toBrew.getItemMeta()); + data.itemsBrewed.add(temp); + } + } + if (!quest.getStage(stage).getItemsToConsume().isEmpty()) { + for (final ItemStack toConsume : quest.getStage(stage).getItemsToConsume()) { + final ItemStack temp = new ItemStack(toConsume.getType(), 0, toConsume.getDurability()); + temp.addUnsafeEnchantments(toConsume.getEnchantments()); + temp.setItemMeta(toConsume.getItemMeta()); + data.itemsConsumed.add(temp); + } + } + if (!quest.getStage(stage).getItemsToDeliver().isEmpty()) { + for (final ItemStack toDeliver : quest.getStage(stage).getItemsToDeliver()) { + final ItemStack temp = new ItemStack(toDeliver.getType(), 0, toDeliver.getDurability()); + temp.addUnsafeEnchantments(toDeliver.getEnchantments()); + temp.setItemMeta(toDeliver.getItemMeta()); + data.itemsDelivered.add(temp); + } + } + if (!quest.getStage(stage).getCitizensToInteract().isEmpty()) { + for (final Integer ignored : quest.getStage(stage).getCitizensToInteract()) { + data.citizensInteracted.add(false); + } + } + if (!quest.getStage(stage).getCitizensToKill().isEmpty()) { + for (final Integer ignored : quest.getStage(stage).getCitizensToKill()) { + data.citizensNumKilled.add(0); + } + } + if (!quest.getStage(stage).getMobsToKill().isEmpty()) { + for (final EntityType ignored : quest.getStage(stage).getMobsToKill()) { + data.mobNumKilled.add(0); + } + } + data.setCowsMilked(0); + data.setFishCaught(0); + data.setPlayersKilled(0); + if (!quest.getStage(stage).getLocationsToReach().isEmpty()) { + for (final Location ignored : quest.getStage(stage).getLocationsToReach()) { + data.locationsReached.add(false); + } + } + if (!quest.getStage(stage).getMobsToTame().isEmpty()) { + for (final EntityType ignored : quest.getStage(stage).getMobsToTame()) { + data.mobsTamed.add(0); + } + } + if (!quest.getStage(stage).getSheepToShear().isEmpty()) { + for (final DyeColor ignored : quest.getStage(stage).getSheepToShear()) { + data.sheepSheared.add(0); + } + } + if (!quest.getStage(stage).getPasswordDisplays().isEmpty()) { + for (final String ignored : quest.getStage(stage).getPasswordDisplays()) { + data.passwordsSaid.add(false); + } + } + if (!quest.getStage(stage).getCustomObjectives().isEmpty()) { + for (final CustomObjective ignored : quest.getStage(stage).getCustomObjectives()) { + data.customObjectiveCounts.add(0); + } + } + data.setDoJournalUpdate(true); + hardDataPut(quest, data); + } + + + /** + * Save data of the Quester to file + * + * @return true if successful + */ + public boolean saveData() { + try { + final Storage storage = plugin.getStorage(); + storage.saveQuester(this); + } catch (final Exception e) { + return false; + } + return true; + } + + /** + * Get the difference between System.currentTimeMillis() and the last completed time for a quest + * + * @param quest The quest to get the last completed time of + * @return Difference between now and then in milliseconds + */ + public long getCompletionDifference(final BukkitQuest quest) { + final long currentTime = System.currentTimeMillis(); + final long lastTime; + if (!completedTimes.containsKey(quest)) { + lastTime = System.currentTimeMillis(); + completedTimes.put(quest, System.currentTimeMillis()); + } else { + lastTime = completedTimes.get(quest); + } + return currentTime - lastTime; + } + + /** + * Get the difference between player cooldown and time since last completion of a quest + * + * @deprecated Use {@link #getRemainingCooldown(BukkitQuest)} + * @param quest The quest to get the last completed time of + * @return Difference between now and then in milliseconds + */ + @Deprecated + public long getCooldownDifference(final BukkitQuest quest) { + return quest.getPlanner().getCooldown() - getCompletionDifference(quest); + } + + /** + * Get the amount of time left before Quester may take a completed quest again + * + * @param quest The quest to calculate the cooldown for + * @return Length of time in milliseconds + */ + public long getRemainingCooldown(final BukkitQuest quest) { + return quest.getPlanner().getCooldown() - getCompletionDifference(quest); + } + + public FileConfiguration getBaseData() { + final FileConfiguration data = new YamlConfiguration(); + if (!currentQuests.isEmpty()) { + final ArrayList questIds = new ArrayList<>(); + final ArrayList questStages = new ArrayList<>(); + for (final BukkitQuest quest : currentQuests.keySet()) { + questIds.add(quest.getId()); + questStages.add(currentQuests.get(quest)); + } + data.set("currentQuests", questIds); + data.set("currentStages", questStages); + data.set("quest-points", questPoints); + final ConfigurationSection dataSec = data.createSection("questData"); + for (final BukkitQuest quest : currentQuests.keySet()) { + if (quest.getName() == null || quest.getName().isEmpty()) { + plugin.getLogger().severe("Quest name was null or empty while loading data"); + return null; + } + final ConfigurationSection questSec = dataSec.createSection(quest.getId()); + final QuestData questData = getQuestData(quest); + if (questData == null) { + continue; + } + if (!questData.blocksBroken.isEmpty()) { + final LinkedList blockAmounts = new LinkedList<>(); + for (final ItemStack m : questData.blocksBroken) { + blockAmounts.add(m.getAmount()); + } + questSec.set("blocks-broken-amounts", blockAmounts); + } + if (!questData.blocksDamaged.isEmpty()) { + final LinkedList blockAmounts = new LinkedList<>(); + for (final ItemStack m : questData.blocksDamaged) { + blockAmounts.add(m.getAmount()); + } + questSec.set("blocks-damaged-amounts", blockAmounts); + } + if (!questData.blocksPlaced.isEmpty()) { + final LinkedList blockAmounts = new LinkedList<>(); + for (final ItemStack m : questData.blocksPlaced) { + blockAmounts.add(m.getAmount()); + } + questSec.set("blocks-placed-amounts", blockAmounts); + } + if (!questData.blocksUsed.isEmpty()) { + final LinkedList blockAmounts = new LinkedList<>(); + for (final ItemStack m : questData.blocksUsed) { + blockAmounts.add(m.getAmount()); + } + questSec.set("blocks-used-amounts", blockAmounts); + } + if (!questData.blocksCut.isEmpty()) { + final LinkedList blockAmounts = new LinkedList<>(); + for (final ItemStack m : questData.blocksCut) { + blockAmounts.add(m.getAmount()); + } + questSec.set("blocks-cut-amounts", blockAmounts); + } + if (!questData.itemsCrafted.isEmpty()) { + final LinkedList craftAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsCrafted) { + craftAmounts.add(m.getAmount()); + } + questSec.set("item-craft-amounts", craftAmounts); + } + if (!questData.itemsSmelted.isEmpty()) { + final LinkedList smeltAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsSmelted) { + smeltAmounts.add(m.getAmount()); + } + questSec.set("item-smelt-amounts", smeltAmounts); + } + if (!questData.itemsEnchanted.isEmpty()) { + final LinkedList enchantAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsEnchanted) { + enchantAmounts.add(m.getAmount()); + } + questSec.set("item-enchant-amounts", enchantAmounts); + } + if (!questData.itemsBrewed.isEmpty()) { + final LinkedList brewAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsBrewed) { + brewAmounts.add(m.getAmount()); + } + questSec.set("item-brew-amounts", brewAmounts); + } + if (!questData.itemsConsumed.isEmpty()) { + final LinkedList consumeAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsConsumed) { + consumeAmounts.add(m.getAmount()); + } + questSec.set("item-consume-amounts", consumeAmounts); + } + if (!questData.itemsDelivered.isEmpty()) { + final LinkedList deliveryAmounts = new LinkedList<>(); + for (final ItemStack m : questData.itemsDelivered) { + deliveryAmounts.add(m.getAmount()); + } + questSec.set("item-delivery-amounts", deliveryAmounts); + } + if (!questData.citizensInteracted.isEmpty()) { + questSec.set("has-talked-to", questData.citizensInteracted); + } + if (!questData.citizensNumKilled.isEmpty()) { + questSec.set("citizen-amounts-killed", questData.citizensNumKilled); + } + if (!questData.mobNumKilled.isEmpty()) { + questSec.set("mobs-killed-amounts", questData.mobNumKilled); + } + if (!questData.mobsTamed.isEmpty()) { + questSec.set("mob-tame-amounts", questData.mobsTamed); + } + final BukkitStage stage = getCurrentStage(quest); + if (stage != null) { + if (stage.getFishToCatch() != null) { + questSec.set("fish-caught", questData.getFishCaught()); + } + if (stage.getCowsToMilk() != null) { + questSec.set("cows-milked", questData.getCowsMilked()); + } + if (stage.getPlayersToKill() != null) { + questSec.set("players-killed", questData.getPlayersKilled()); + } + } + if (!questData.sheepSheared.isEmpty()) { + questSec.set("sheep-sheared", questData.sheepSheared); + } + if (!questData.locationsReached.isEmpty()) { + questSec.set("has-reached-location", questData.locationsReached); + } + if (!questData.passwordsSaid.isEmpty()) { + questSec.set("passwords-said", questData.passwordsSaid); + } + if (!questData.customObjectiveCounts.isEmpty()) { + questSec.set("custom-objective-counts", questData.customObjectiveCounts); + } + if (questData.getDelayTimeLeft() > 0) { + questSec.set("stage-delay", questData.getDelayTimeLeft()); + } + } + } else { + data.set("currentQuests", "none"); + data.set("currentStages", "none"); + data.set("quest-points", questPoints); + } + if (completedQuests.isEmpty()) { + data.set("completed-Quests", "none"); + } else { + final List questIds = new LinkedList<>(); + for (final Quest quest : completedQuests) { + questIds.add(quest.getId()); + } + data.set("completed-Quests", questIds); + } + if (!completedTimes.isEmpty()) { + final List questIds = new LinkedList<>(); + final List questTimes = new LinkedList<>(); + for (final Entry entry : completedTimes.entrySet()) { + questIds.add(entry.getKey().getId()); + questTimes.add(entry.getValue()); + } + data.set("completedRedoableQuests", questIds); + data.set("completedQuestTimes", questTimes); + } + if (!amountsCompleted.isEmpty()) { + final List questIds = new LinkedList<>(); + final List questAmounts = new LinkedList<>(); + for (final Entry entry : amountsCompleted.entrySet()) { + questIds.add(entry.getKey().getId()); + questAmounts.add(entry.getValue()); + } + data.set("amountsCompletedQuests", questIds); + data.set("amountsCompleted", questAmounts); + } + // #getPlayer is faster + OfflinePlayer representedPlayer = getPlayer(); + if (representedPlayer == null) { + representedPlayer = getOfflinePlayer(); + } + data.set("lastKnownName", representedPlayer.getName()); + return data; + } + + /** + * Load data of the Quester from storage + * + * @deprecated Use {@link #hasData()} + * @return true if successful + */ + @Deprecated + public boolean loadData() { + return plugin.getStorage().loadQuester(id) != null; + } + + /** + * Check whether the Quester has data saved to hard storage + * + * @return true if successful + */ + public boolean hasData() { + return plugin.getStorage().loadQuester(id) != null; + } + + /** + * Check whether the Quester has base data in memory, indicating they have participated in quests + * + * @return false if empty + */ + public boolean hasBaseData() { + return !currentQuests.isEmpty() || !questData.isEmpty() || !completedQuests.isEmpty(); + } + + /** + * Initiate the stage timer + * @param quest The quest of which the timer is for + */ + public void startStageTimer(final BukkitQuest quest) { + if (getQuestData(quest).getDelayTimeLeft() > -1) { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new StageTimer(plugin, this, quest), + (long) (getQuestData(quest).getDelayTimeLeft() * 0.02)); + } else { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new StageTimer(plugin, this, quest), + (long) (getCurrentStage(quest).getDelay() * 0.02)); + if (getCurrentStage(quest).getDelayMessage() != null) { + final Player p = plugin.getServer().getPlayer(id); + if (p != null) { + p.sendMessage(ConfigUtil.parseStringWithPossibleLineBreaks((getCurrentStage(quest) + .getDelayMessage()), quest, p)); + } + } + } + getQuestData(quest).setDelayStartTime(System.currentTimeMillis()); + } + + /** + * Pause the stage timer. Useful when a player quits + * @param quest The quest of which the timer is for + */ + public void stopStageTimer(final BukkitQuest quest) { + if (getQuestData(quest).getDelayTimeLeft() > -1) { + getQuestData(quest).setDelayTimeLeft(getQuestData(quest).getDelayTimeLeft() - (System.currentTimeMillis() + - getQuestData(quest).getDelayStartTime())); + } else { + getQuestData(quest).setDelayTimeLeft(getCurrentStage(quest).getDelay() - (System.currentTimeMillis() + - getQuestData(quest).getDelayStartTime())); + } + } + + /** + * Get remaining stage delay time + * @param quest The quest of which the timer is for + * @return Remaining time in milliseconds + */ + public long getStageTime(final BukkitQuest quest) { + if (getQuestData(quest).getDelayTimeLeft() > -1) { + return getQuestData(quest).getDelayTimeLeft() - (System.currentTimeMillis() + - getQuestData(quest).getDelayStartTime()); + } else { + return getCurrentStage(quest).getDelay() - (System.currentTimeMillis() + - getQuestData(quest).getDelayStartTime()); + } + } + + /** + * Check whether the provided quest is valid and, if not, inform the Quester + * + * @param quest The quest to check + */ + public void checkQuest(final BukkitQuest quest) { + if (quest != null) { + boolean exists = false; + for (final BukkitQuest q : plugin.getLoadedQuests()) { + if (q.getId().equalsIgnoreCase(quest.getId())) { + final BukkitStage stage = getCurrentStage(quest); + if (stage != null) { + quest.updateCompass(this, stage); + // TODO - decide whether or not to handle this + /*if (q.equals(quest) == false) { + if (getPlayer() != null && getPlayer().isOnline()) { + quitQuest(quest, ChatColor.GOLD + Lang.get("questModified") + .replace("", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.GOLD)); + } + }*/ + } + exists = true; + break; + } + } + if (!exists) { + sendMessage(ChatColor.RED + Lang.get("questNotExist").replace("", ChatColor.DARK_PURPLE + + quest.getName() + ChatColor.RED)); + } + } + } + + /** + * Show an inventory GUI with quest items to the specified player + * + * @param npc The NPC from which the GUI is bound + * @param quests List of quests to use for displaying items + */ + public void showGUIDisplay(final NPC npc, final LinkedList quests) { + if (npc == null || quests == null) { + return; + } + final QuesterPreOpenGUIEvent preEvent = new QuesterPreOpenGUIEvent(this, npc, quests); + plugin.getServer().getPluginManager().callEvent(preEvent); + if (preEvent.isCancelled()) { + return; + } + final Player player = getPlayer(); + final Inventory inv = plugin.getServer().createInventory(player, ((quests.size() / 9) + 1) * 9, + Lang.get(player, "quests") + " | " + npc.getName()); + int i = 0; + for (final Quest quest : quests) { + if (quest.getGUIDisplay() != null) { + if (i > 53) { + // Protocol-enforced size limit has been exceeded + break; + } + final ItemStack display = quest.getGUIDisplay(); + final ItemMeta meta = display.getItemMeta(); + if (meta != null) { + if (completedQuests.contains(quest)) { + meta.setDisplayName(ChatColor.DARK_PURPLE + ConfigUtil.parseString(quest.getName() + + " " + ChatColor.GREEN + Lang.get(player, "redoCompleted"), npc)); + } else { + meta.setDisplayName(ChatColor.DARK_PURPLE + ConfigUtil.parseString(quest.getName(), npc)); + } + if (!meta.hasLore()) { + final LinkedList lines; + String desc = quest.getDescription(); + if (plugin.getDependencies().getPlaceholderApi() != null) { + desc = PlaceholderAPI.setPlaceholders(player, desc); + } + if (desc.equals(ChatColor.stripColor(desc))) { + lines = MiscUtil.makeLines(desc, " ", 40, ChatColor.DARK_GREEN); + } else { + lines = MiscUtil.makeLines(desc, " ", 40, null); + } + meta.setLore(lines); + } + meta.addItemFlags(ItemFlag.values()); + display.setItemMeta(meta); + } + inv.setItem(i, display); + i++; + } + } + player.openInventory(inv); + } + + /** + * Force Quester to quit the specified quest (canceling any timers), then update Quest Journal

+ * + * Does not save changes to disk. Consider {@link #quitQuest(BukkitQuest, String)} or {@link #quitQuest(BukkitQuest, String[])} + * + * @param quest The quest to quit + */ + public void hardQuit(final BukkitQuest quest) { + try { + currentQuests.remove(quest); + questData.remove(quest); + if (!timers.isEmpty()) { + for (final Map.Entry entry : timers.entrySet()) { + if (entry.getValue().getName().equals(quest.getName())) { + plugin.getServer().getScheduler().cancelTask(entry.getKey()); + timers.remove(entry.getKey()); + } + } + } + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Forcibly remove quest from Quester's list of completed quests, then update Quest Journal

+ * + * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} + * + * @param quest The quest to remove + */ + public void hardRemove(final BukkitQuest quest) { + try { + completedQuests.remove(quest); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Forcibly clear Quester's list of current quests and data, then update Quest Journal

+ * + * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} + */ + public void hardClear() { + try { + currentQuests.clear(); + questData.clear(); + amountsCompleted.clear(); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Forcibly set Quester's current stage, then update Quest Journal + * + * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} + * + * @param key The quest to set stage of + * @param val The stage number to set + */ + public void hardStagePut(final BukkitQuest key, final Integer val) { + try { + currentQuests.put(key, val); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + /** + * Forcibly set Quester's quest data, then update Quest Journal

+ * + * Does not save changes to disk. Consider calling {@link #saveData()} followed by {@link #loadData()} + * + * @param key The quest to set stage of + * @param val The data to set + */ + public void hardDataPut(final BukkitQuest key, final QuestData val) { + try { + questData.put(key, val); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + public boolean canUseCompass() { + if (getPlayer() != null) { + if (!getPlayer().hasPermission("worldedit.navigation.jumpto")) { + return getPlayer().hasPermission("quests.compass"); + } + } + return false; + } + + /** + * Reset compass target to Quester's bed spawn location

+ * + * Will set to Quester's spawn location if bed spawn does not exist + */ + public void resetCompass() { + final Player player = getPlayer(); + if (player == null) { + return; + } + if (!canUseCompass()) { + return; + } + + Location defaultLocation = player.getBedSpawnLocation(); + if (defaultLocation == null) { + defaultLocation = player.getWorld().getSpawnLocation(); + } + compassTargetQuestId = null; + player.setCompassTarget(defaultLocation); + } + + /** + * Update compass target to current stage of first available current quest, if possible + */ + public void findCompassTarget() { + if (!canUseCompass()) { + return; + } + for (final BukkitQuest quest : currentQuests.keySet()) { + final BukkitStage stage = getCurrentStage(quest); + if (stage != null && quest.updateCompass(this, stage)) { + break; + } + } + } + + /** + * Update compass target to current stage of next available current quest, if possible + * + * @param notify Whether to notify this quester of result + */ + public void findNextCompassTarget(final boolean notify) { + if (!canUseCompass()) { + return; + } + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + final LinkedList list = currentQuests.keySet().stream() + .sorted(Comparator.comparing(BukkitQuest::getName)).map(BukkitQuest::getId) + .collect(Collectors.toCollection(LinkedList::new)); + int index = 0; + if (compassTargetQuestId != null) { + if (!list.contains(compassTargetQuestId) && notify) { + return; + } + index = list.indexOf(compassTargetQuestId) + 1; + if (index >= list.size()) { + index = 0; + } + } + if (list.size() > 0) { + final BukkitQuest quest = plugin.getQuestById(list.get(index)); + compassTargetQuestId = quest.getId(); + final BukkitStage stage = getCurrentStage(quest); + if (stage != null) { + quest.updateCompass(BukkitQuester.this, stage); + if (notify) { + sendMessage(ChatColor.YELLOW + Lang.get(getPlayer(), "compassSet") + .replace("", ChatColor.GOLD + quest.getName() + ChatColor.YELLOW)); + } + } + } else { + sendMessage(ChatColor.RED + Lang.get(getPlayer(), "journalNoQuests") + .replace("", Lang.get(getPlayer(), "journalTitle"))); + } + }); + } + + /** + * Check whether the Quester's inventory contains the specified item + * + * @param is The item with a specified amount to check + * @return true if the inventory contains at least the amount of the specified stack + */ + public boolean hasItem(final ItemStack is) { + final Inventory inv = getPlayer().getInventory(); + int playerAmount = 0; + for (final ItemStack stack : inv.getContents()) { + if (stack != null) { + if (ItemUtil.compareItems(is, stack, false) == 0) { + playerAmount += stack.getAmount(); + } + } + } + return playerAmount >= is.getAmount(); + } + + /** + * Dispatch player event to fellow questers

+ * + * Accepted strings are: breakBlock, damageBlock, placeBlock, useBlock, + * cutBlock, craftItem, smeltItem, enchantItem, brewItem, consumeItem, + * milkCow, catchFish, killMob, deliverItem, killPlayer, talkToNPC, + * killNPC, tameMob, shearSheep, password, reachLocation + * + * @deprecated Use {@link #dispatchMultiplayerEverything(BukkitQuest, ObjectiveType, BiFunction)} + * + * @param objectiveType The type of objective to progress + * @param fun The function to execute, the event call + */ + @Deprecated + public void dispatchMultiplayerEverything(final BukkitQuest quest, final String objectiveType, + final BiFunction fun) { + dispatchMultiplayerEverything(quest, ObjectiveType.fromName(objectiveType), fun); + } + + /** + * Dispatch player event to fellow questers

+ * + * @param type The type of objective to progress + * @param fun The function to execute, the event call + */ + public Set dispatchMultiplayerEverything(final BukkitQuest quest, final ObjectiveType type, + final BiFunction fun) { + final Set appliedQuestIDs = new HashSet<>(); + if (quest != null) { + try { + if (quest.getOptions().getShareProgressLevel() == 1) { + final List mq = getMultiplayerQuesters(quest); + if (mq == null) { + return appliedQuestIDs; + } + for (final BukkitQuester q : mq) { + if (q == null) { + continue; + } + if (quest.getOptions().canShareSameQuestOnly()) { + if (q.getCurrentStage(quest) != null) { + fun.apply(q, quest); + appliedQuestIDs.add(quest.getId()); + } + } + q.getCurrentQuests().forEach((otherQuest, i) -> { + if (otherQuest.getStage(i).containsObjective(type)) { + if (!otherQuest.getOptions().canShareSameQuestOnly()) { + fun.apply(q, otherQuest); + appliedQuestIDs.add(otherQuest.getId()); + } + } + }); + } + } + } catch (final Exception e) { + plugin.getLogger().severe("Error occurred while dispatching " + type.name() + " for quest ID " + + quest.getId()); + e.printStackTrace(); + } + } + return appliedQuestIDs; + } + + /** + * Dispatch finish objective to fellow questers + * + * @param quest The current quest + * @param currentStage The current stage of the quest + * @param fun The function to execute, the event call + */ + public Set dispatchMultiplayerObjectives(final BukkitQuest quest, final BukkitStage currentStage, + final Function fun) { + final Set appliedQuestIDs = new HashSet<>(); + if (quest.getOptions().getShareProgressLevel() == 2) { + final List mq = getMultiplayerQuesters(quest); + if (mq == null) { + return appliedQuestIDs; + } + for (final BukkitQuester q : mq) { + if (q == null) { + continue; + } + // Share only same quest is not necessary here + // The function must be applied to the same quest + if ((q.getCurrentQuests().containsKey(quest) && currentStage.equals(q.getCurrentStage(quest)))) { + fun.apply(q); + } + } + } + return appliedQuestIDs; + } + + /** + * Get a list of fellow Questers in a party or group + * + * @param quest The quest which uses a linked plugin, i.e. Parties or DungeonsXL + * @return Potentially empty list of Questers or null for invalid quest + */ + public List getMultiplayerQuesters(final BukkitQuest quest) { + if (quest == null) { + return null; + } + final List mq = new LinkedList<>(); + if (plugin.getDependencies().getPartyProvider() != null) { + final PartyProvider partyProvider = plugin.getDependencies().getPartyProvider(); + if (partyProvider != null) { + if (quest.getOptions().canUsePartiesPlugin() || quest.getOptions().getExternalPartyPlugin() != null) { + if (getUUID() != null && partyProvider.getPartyId(getUUID()) != null) { + final String partyId = partyProvider.getPartyId(getUUID()); + final double distanceSquared = quest.getOptions().getShareDistance() + * quest.getOptions().getShareDistance(); + final boolean offlinePlayers = quest.getOptions().canHandleOfflinePlayers(); + if (offlinePlayers) { + for (final UUID id : partyProvider.getMembers(partyId)) { + if (!id.equals(getUUID())) { + mq.add(plugin.getQuester(id)); + } + } + } else { + for (final UUID id : partyProvider.getOnlineMembers(partyId)) { + if (!id.equals(getUUID())) { + if (distanceSquared > 0) { + final Player player = Bukkit.getPlayer(id); + if (player != null && distanceSquared >= getPlayer().getLocation() + .distanceSquared(player.getLocation())) { + mq.add(plugin.getQuester(id)); + } + } else { + mq.add(plugin.getQuester(id)); + } + } + } + } + return mq; + } + } + } + } else if (plugin.getDependencies().getPartiesApi() != null) { + if (quest.getOptions().canUsePartiesPlugin()) { + final PartyPlayer partyPlayer = plugin.getDependencies().getPartiesApi().getPartyPlayer(getUUID()); + if (partyPlayer != null && partyPlayer.getPartyId() != null) { + final Party party = plugin.getDependencies().getPartiesApi().getParty(partyPlayer.getPartyId()); + if (party != null) { + final double distanceSquared = quest.getOptions().getShareDistance() + * quest.getOptions().getShareDistance(); + final boolean offlinePlayers = quest.getOptions().canHandleOfflinePlayers(); + if (offlinePlayers) { + for (final UUID id : party.getMembers()) { + if (!id.equals(getUUID())) { + mq.add(plugin.getQuester(id)); + } + } + } else { + for (final PartyPlayer pp : party.getOnlineMembers(true)) { + if (!pp.getPlayerUUID().equals(getUUID())) { + if (distanceSquared > 0) { + final Player player = Bukkit.getPlayer(pp.getPlayerUUID()); + if (player != null) { + final Location locationOne = getPlayer().getLocation(); + final Location locationTwo = player.getLocation(); + if (locationOne.getWorld() != null && locationTwo.getWorld() != null) { + if (locationOne.getWorld().getName().equals(locationTwo.getWorld() + .getName())) { + if (distanceSquared >= getPlayer().getLocation() + .distanceSquared(player.getLocation())) { + mq.add(plugin.getQuester(pp.getPlayerUUID())); + } + } + } + } + } else { + mq.add(plugin.getQuester(pp.getPlayerUUID())); + } + } + } + } + return mq; + } + } + } + } + return mq; + } + + /** + * Check if quest is available and, if so, ask Quester if they would like to start it

+ * + * @param quest The quest to check and then offer + * @param giveReason Whether to inform Quester of unavailability + * @return true if successful + */ + public boolean offerQuest(final BukkitQuest quest, final boolean giveReason) { + if (quest == null) { + return false; + } + final QuestTakeEvent event = new QuestTakeEvent(quest, this); + plugin.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return false; + } + if (canAcceptOffer(quest, giveReason)) { + if (getPlayer() != null) { + if (!getPlayer().isConversing()) { + setQuestIdToTake(quest.getId()); + final String s = ChatColor.GOLD + Lang.get("questObjectivesTitle") + .replace("", quest.getName()) + "\n" + ChatColor.RESET + quest.getDescription(); + for (final String msg : s.split("
")) { + sendMessage(msg); + } + if (!plugin.getSettings().canAskConfirmation()) { + takeQuest(quest, false); + } else { + plugin.getConversationFactory().buildConversation(getPlayer()).begin(); + } + return true; + } else { + sendMessage(ChatColor.YELLOW + Lang.get(getPlayer(), "alreadyConversing")); + } + } + } + return false; + } + + /** + * Check if quest is available to this Quester

+ * + * @param quest The quest to check + * @param giveReason Whether to inform Quester of unavailability + * @return true if available + */ + public boolean canAcceptOffer(final BukkitQuest quest, final boolean giveReason) { + if (quest == null) { + return false; + } + if (getCurrentQuests().size() >= plugin.getSettings().getMaxQuests() && plugin.getSettings().getMaxQuests() + > 0) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "questMaxAllowed").replace("", + String.valueOf(plugin.getSettings().getMaxQuests())); + sendMessage(ChatColor.YELLOW + msg); + } + return false; + } else if (getCurrentQuests().containsKey(quest)) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "questAlreadyOn"); + sendMessage(ChatColor.YELLOW + msg); + } + return false; + } else if (getCompletedQuests().contains(quest) && quest.getPlanner().getCooldown() < 0) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "questAlreadyCompleted") + .replace("", ChatColor.DARK_PURPLE + quest.getName() + ChatColor.YELLOW); + sendMessage(ChatColor.YELLOW + msg); + } + return false; + } else if (plugin.getDependencies().getCitizens() != null + && !plugin.getSettings().canAllowCommandsForNpcQuests() + && quest.getNpcStart() != null && quest.getNpcStart().getEntity() != null + && quest.getNpcStart().getEntity().getLocation().getWorld() != null + && getPlayer().getLocation().getWorld() != null + && quest.getNpcStart().getEntity().getLocation().getWorld().getName().equals( + getPlayer().getLocation().getWorld().getName()) + && quest.getNpcStart().getEntity().getLocation().distance(getPlayer().getLocation()) > 6.0) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "mustSpeakTo").replace("", ChatColor.DARK_PURPLE + + quest.getNpcStart().getName() + ChatColor.YELLOW); + sendMessage(ChatColor.YELLOW + msg); + } + return false; + } else if (quest.getBlockStart() != null) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "noCommandStart").replace("", ChatColor.DARK_PURPLE + + quest.getName() + ChatColor.YELLOW); + sendMessage(ChatColor.YELLOW + msg); + } + return false; + } else if (getCompletedQuests().contains(quest) && getRemainingCooldown(quest) > 0 + && !quest.getPlanner().getOverride()) { + if (giveReason) { + final String msg = Lang.get(getPlayer(), "questTooEarly").replace("", ChatColor.AQUA + + quest.getName()+ ChatColor.YELLOW).replace("

+ * + * Method may be called as often as needed. + * + * @param quester The online quester to have their compass updated + * @param stage The stage to process for targets + * @return true if an attempt was made successfully + */ + public boolean updateCompass(final Quester quester, final Stage stage) { + if (quester == null) { + return false; + } + if (stage == null) { + return false; + } + if (!quester.getOfflinePlayer().isOnline()) { + return false; + } + if (!quester.getPlayer().hasPermission("quests.compass")) { + return false; + } + final Quest quest = this; + Bukkit.getScheduler().runTask(plugin, () -> { + Location targetLocation = null; + if (stage.getCitizensToInteract() != null && stage.getCitizensToInteract().size() > 0) { + targetLocation = plugin.getDependencies().getNPCLocation(stage.getCitizensToInteract().getFirst()); + } else if (stage.citizensToKill != null && stage.citizensToKill.size() > 0) { + targetLocation = plugin.getDependencies().getNPCLocation(stage.citizensToKill.getFirst()); + } else if (stage.locationsToReach != null && stage.locationsToReach.size() > 0) { + targetLocation = stage.locationsToReach.getFirst(); + } else if (stage.itemDeliveryTargets != null && stage.itemDeliveryTargets.size() > 0) { + final NPC npc = plugin.getDependencies().getCitizens().getNPCRegistry().getById(stage.itemDeliveryTargets + .getFirst()); + targetLocation = npc.getStoredLocation(); + } else if (stage.playersToKill != null && stage.playersToKill > 0) { + final Location source = quester.getPlayer().getLocation(); + Location nearest = null; + double old_distance = 30000000; + if (source.getWorld() == null) { + return; + } + for (final Player p : source.getWorld().getPlayers()) { + if (p.getUniqueId().equals(quester.getUUID())) { + continue; + } + final double new_distance = p.getLocation().distanceSquared(source); + if (new_distance < old_distance) { + nearest = p.getLocation(); + old_distance = new_distance; + } + } + if (nearest != null) { + targetLocation = nearest; + } + } else if (stage.mobsToKill != null && stage.mobsToKill.size() > 0) { + final Location source = quester.getPlayer().getLocation(); + Location nearest = null; + double old_distance = 30000000; + final EntityType et = stage.mobsToKill.getFirst(); + if (source.getWorld() == null) { + return; + } + for (final Entity e : source.getWorld().getEntities()) { + if (!e.getType().equals(et)) { + continue; + } + final double new_distance = e.getLocation().distanceSquared(source); + if (new_distance < old_distance) { + nearest = e.getLocation(); + old_distance = new_distance; + } + } + if (nearest != null) { + targetLocation = nearest; + } + } else if (stage.mobsToTame != null && stage.mobsToTame.size() > 0) { + final Location source = quester.getPlayer().getLocation(); + Location nearest = null; + double old_distance = 30000000; + final EntityType et = stage.mobsToTame.getFirst(); + if (source.getWorld() == null) { + return; + } + for (final Entity e : source.getWorld().getEntities()) { + if (!e.getType().equals(et)) { + continue; + } + final double new_distance = e.getLocation().distanceSquared(source); + if (new_distance < old_distance) { + nearest = e.getLocation(); + old_distance = new_distance; + } + } + if (nearest != null) { + targetLocation = nearest; + } + } else if (stage.sheepToShear != null && stage.sheepToShear.size() > 0) { + final Location source = quester.getPlayer().getLocation(); + Location nearest = null; + double old_distance = 30000000; + final DyeColor dc = stage.sheepToShear.getFirst(); + if (source.getWorld() == null) { + return; + } + for (final Entity e : source.getWorld().getEntities()) { + if (!e.getType().equals(EntityType.SHEEP)) { + continue; + } + final Sheep s = (Sheep)e; + if (s.getColor()!= null && s.getColor().equals(dc)) { + continue; + } + final double new_distance = e.getLocation().distanceSquared(source); + if (new_distance < old_distance) { + nearest = e.getLocation(); + old_distance = new_distance; + } + } + if (nearest != null) { + targetLocation = nearest; + } + } + if (targetLocation != null && targetLocation.getWorld() != null) { + if (targetLocation.getWorld().getName().equals(quester.getPlayer().getWorld().getName())) { + final Location lockedTarget = new Location(targetLocation.getWorld(), targetLocation.getX(), + targetLocation.getY(), targetLocation.getZ()); + final QuestUpdateCompassEvent event = new QuestUpdateCompassEvent(quest, quester, lockedTarget); + plugin.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + quester.getPlayer().setCompassTarget(lockedTarget); + } + } + }); + return true; + } + + /** + * Check that a quester has met all Requirements to accept this quest

+ * + * Item, permission and custom Requirements are only checked for online players + * + * @param quester The quester to check + * @return true if all Requirements have been met + */ + public boolean testRequirements(final BukkitQuester quester) { + return testRequirements(quester.getOfflinePlayer()); + } + + /** + * Check that a player has met all Requirements to accept this quest

+ * + * Item, permission and custom Requirements are only checked for online players + * + * @param player The player to check + * @return true if all Requirements have been met + */ + protected boolean testRequirements(final OfflinePlayer player) { + final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); + if (requirements.getMoney() != 0 && plugin.getDependencies().getVaultEconomy() != null) { + if (plugin.getDependencies().getVaultEconomy().getBalance(player) < requirements.getMoney()) { + return false; + } + } + if (quester.getQuestPoints() < requirements.getQuestPoints()) { + return false; + } + if (!quester.getCompletedQuests().containsAll(requirements.getNeededQuests())) { + return false; + } + for (final BukkitQuest q : requirements.getBlockQuests()) { + if (quester.getCompletedQuests().contains(q) || quester.getCurrentQuests().containsKey(q)) { + return false; + } + } + for (final String s : requirements.getMcmmoSkills()) { + final SkillType st = Quests.getMcMMOSkill(s); + final int lvl = requirements.getMcmmoAmounts().get(requirements.getMcmmoSkills().indexOf(s)); + if (UserManager.getOfflinePlayer(player).getProfile().getSkillLevel(st) < lvl) { + return false; + } + } + if (requirements.getHeroesPrimaryClass() != null) { + if (!plugin.getDependencies().testPrimaryHeroesClass(requirements.getHeroesPrimaryClass(), player.getUniqueId())) { + return false; + } + } + if (requirements.getHeroesSecondaryClass() != null) { + if (!plugin.getDependencies().testSecondaryHeroesClass(requirements.getHeroesSecondaryClass(), + player.getUniqueId())) { + return false; + } + } + if (player.isOnline()) { + final Player p = (Player)player; + final Inventory fakeInv = Bukkit.createInventory(null, InventoryType.PLAYER); + fakeInv.setContents(p.getInventory().getContents().clone()); + for (final ItemStack is : requirements.getItems()) { + if (InventoryUtil.canRemoveItem(fakeInv, is)) { + InventoryUtil.removeItem(fakeInv, is); + } else { + return false; + } + } + for (final String s : requirements.getPermissions()) { + if (!p.hasPermission(s)) { + return false; + } + } + for (final String s : requirements.getCustomRequirements().keySet()) { + CustomRequirement found = null; + for (final CustomRequirement cr : plugin.getCustomRequirements()) { + if (cr.getName().equalsIgnoreCase(s)) { + found = cr; + break; + } + } + if (found != null) { + if (!found.testRequirement(p, requirements.getCustomRequirements().get(s))) { + return false; + } + } else { + plugin.getLogger().warning("Quester \"" + p.getName() + "\" attempted to take Quest \"" + name + + "\", but the Custom Requirement \"" + s + "\" could not be found. Does it still exist?"); + } + } + } + return true; + } + + /** + * Proceed to finish this quest, issuing applicable rewards + * + * @param quester The quester finishing this quest + */ + public void completeQuest(final BukkitQuester quester) { + completeQuest(quester, true); + } + + /** + * Proceed to finish this quest, issuing applicable rewards + * + * @param quester The quester finishing this quest + * @param allowMultiplayer Allow multiplayer sharing + */ + @SuppressWarnings("deprecation") + public void completeQuest(final BukkitQuester quester, final boolean allowMultiplayer) { + final OfflinePlayer player = quester.getOfflinePlayer(); + boolean cancelled = false; + if (player.isOnline()) { + if (Bukkit.isPrimaryThread()) { + final QuesterPreCompleteQuestEvent preEvent + = new QuesterPreCompleteQuestEvent(quester, this, false); + plugin.getServer().getPluginManager().callEvent(preEvent); + if (preEvent.isCancelled()) { + return; + } + } else { + final CompletableFuture future = CompletableFuture.supplyAsync(() -> { + final QuesterPreCompleteQuestEvent preEvent + = new QuesterPreCompleteQuestEvent(quester, BukkitQuest.this, true); + plugin.getServer().getPluginManager().callEvent(preEvent); + return preEvent.isCancelled(); + }); + + try { + cancelled = future.get(); + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + if (cancelled) { + return; + } + quester.hardQuit(this); + quester.getCompletedQuests().add(this); + for (final Map.Entry entry : quester.getTimers().entrySet()) { + if (entry.getValue().getName().equals(getName())) { + plugin.getServer().getScheduler().cancelTask(entry.getKey()); + quester.getTimers().remove(entry.getKey()); + } + } + if (player.isOnline()) { + final Player p = (Player)player; + final String[] ps = ConfigUtil.parseStringWithPossibleLineBreaks(ChatColor.AQUA + + finished, this, p); + Bukkit.getScheduler().runTaskLater(plugin, () -> p.sendMessage(ps), 40); + } + if (planner.getCooldown() > -1) { + quester.getCompletedTimes().put(this, System.currentTimeMillis()); + if (quester.getAmountsCompleted().containsKey(this)) { + quester.getAmountsCompleted().put(this, quester.getAmountsCompleted().get(this) + 1); + } else { + quester.getAmountsCompleted().put(this, 1); + } + } + + // Issue rewards + final Dependencies depends = plugin.getDependencies(); + boolean issuedReward = false; + if (rewards.getMoney() > 0 && depends.getVaultEconomy() != null) { + depends.getVaultEconomy().depositPlayer(player, rewards.getMoney()); + issuedReward = true; + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + + depends.getVaultEconomy().format(rewards.getMoney())); + } + } + if (player.isOnline()) { + for (final ItemStack i : rewards.getItems()) { + try { + InventoryUtil.addItem(player.getPlayer(), i); + } catch (final Exception e) { + plugin.getLogger().severe("Unable to add null reward item to inventory of " + + player.getName() + " upon completion of quest " + name); + quester.sendMessage(ChatColor.RED + "Quests encountered a problem with an item. " + + "Please contact an administrator."); + } + issuedReward = true; + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + i.getType().name() + " x " + + i.getAmount()); + } + } + } + for (final String s : rewards.getCommands()) { + if (player.getName() == null) { + continue; + } + String temp = s.replace("", player.getName()); + if (depends.getPlaceholderApi() != null && player.isOnline()) { + temp = PlaceholderAPI.setPlaceholders((Player)player, temp); + } + final String command = temp; + if (Bukkit.isPrimaryThread()) { + Bukkit.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command); + } else { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> + Bukkit.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command)); + } + issuedReward = true; + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded command " + s); + } + } + for (int i = 0; i < rewards.getPermissions().size(); i++) { + if (depends.getVaultPermission() != null) { + final String perm = rewards.getPermissions().get(i); + String world = null; + if (i < rewards.getPermissionWorlds().size()) { + world = rewards.getPermissionWorlds().get(i); + } + if (world == null || world.equals("null")) { + depends.getVaultPermission().playerAdd(null, player, perm); + } else { + depends.getVaultPermission().playerAdd(world, player, perm); + } + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded permission " + perm); + } + issuedReward = true; + } + } + for (final String s : rewards.getMcmmoSkills()) { + final int levels = rewards.getMcmmoAmounts().get(rewards.getMcmmoSkills().indexOf(s)); + UserManager.getOfflinePlayer(player).getProfile().addLevels(Quests.getMcMMOSkill(s), levels); + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + s + " x " + levels); + } + issuedReward = true; + } + if (player.isOnline()) { + for (final String s : rewards.getHeroesClasses()) { + final Hero hero = plugin.getDependencies().getHero(player.getUniqueId()); + final double expChange = rewards.getHeroesAmounts().get(rewards.getHeroesClasses().indexOf(s)); + hero.addExp(expChange, plugin.getDependencies().getHeroes().getClassManager().getClass(s), + ((Player)player).getLocation()); + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + s + " x " + expChange); + } + issuedReward = true; + } + } + if (rewards.getPartiesExperience() > 0 && depends.getPartiesApi() != null) { + final PartyPlayer partyPlayer = depends.getPartiesApi().getPartyPlayer(player.getUniqueId()); + if (partyPlayer != null && partyPlayer.getPartyId() != null) { + final Party party = depends.getPartiesApi().getParty(partyPlayer.getPartyId()); + if (party != null) { + party.giveExperience(rewards.getPartiesExperience()); + issuedReward = true; + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + + rewards.getPartiesExperience() + " party experience"); + } + } + } + } + final LinkedList phatLootItems = new LinkedList<>(); + int phatLootExp = 0; + final LinkedList phatLootMessages = new LinkedList<>(); + for (final String s : rewards.getPhatLoots()) { + final LootBundle lb = PhatLootsAPI.getPhatLoot(s).rollForLoot(); + if (lb.getExp() > 0) { + phatLootExp += lb.getExp(); + if (player.isOnline()) { + ((Player)player).giveExp(lb.getExp()); + } + } + if (lb.getMoney() > 0) { + if (depends.getVaultEconomy() != null) { + depends.getVaultEconomy().depositPlayer(player, lb.getMoney()); + } + } + if (!lb.getItemList().isEmpty()) { + phatLootItems.addAll(lb.getItemList()); + if (player.isOnline()) { + for (final ItemStack is : lb.getItemList()) { + try { + InventoryUtil.addItem(player.getPlayer(), is); + } catch (final Exception e) { + plugin.getLogger().severe("Unable to add PhatLoots item to inventory of " + + player.getName() + " upon completion of quest " + name); + quester.sendMessage(ChatColor.RED + "Quests encountered a problem with an item. " + + "Please contact an administrator."); + } + } + } + } + if (!lb.getCommandList().isEmpty() && player.isOnline()) { + for (final CommandLoot cl : lb.getCommandList()) { + cl.execute((Player)player); + } + } + if (!lb.getMessageList().isEmpty()) { + phatLootMessages.addAll(lb.getMessageList()); + } + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded loot " + s); + } + issuedReward = true; + } + if (rewards.getExp() > 0 && player.isOnline()) { + ((Player)player).giveExp(rewards.getExp()); + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded exp " + rewards.getExp()); + } + issuedReward = true; + } + if (rewards.getQuestPoints() > 0) { + quester.setQuestPoints(quester.getQuestPoints() + rewards.getQuestPoints()); + if (plugin.getSettings().getConsoleLogging() > 2) { + plugin.getLogger().info(player.getUniqueId() + " was rewarded " + rewards.getQuestPoints() + " " + + Lang.get("questPoints")); + } + issuedReward = true; + } + if (!rewards.getCustomRewards().isEmpty()) { + issuedReward = true; + if (plugin.getSettings().getConsoleLogging() > 2) { + for (final String s : rewards.getCustomRewards().keySet()) { + plugin.getLogger().info(player.getUniqueId() + " was custom rewarded " + s); + } + } + } + + // Inform player + if (player.isOnline()) { + final Player p = (Player)player; + Lang.send(p, ChatColor.GOLD + Lang.get(p, "questCompleteTitle").replace("", + ChatColor.YELLOW + name + ChatColor.GOLD)); + if (plugin.getSettings().canShowQuestTitles()) { + p.sendTitle(ChatColor.GOLD + Lang.get(p, "quest") + " " + Lang.get(p, "complete"), + ChatColor.YELLOW + name); + } + Lang.send(p, ChatColor.GREEN + Lang.get(p, "questRewardsTitle")); + if (!issuedReward) { + p.sendMessage(ChatColor.GRAY + "- (" + Lang.get("none") + ")"); + } else if (!rewards.getDetailsOverride().isEmpty()) { + for (final String s: rewards.getDetailsOverride()) { + String message = ChatColor.DARK_GREEN + ConfigUtil.parseString( + ChatColor.translateAlternateColorCodes('&', s)); + if (plugin.getDependencies().getPlaceholderApi() != null) { + message = PlaceholderAPI.setPlaceholders(p, message); + } + quester.sendMessage("- " + message); + } + } else { + if (rewards.getQuestPoints() > 0) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + rewards.getQuestPoints() + " " + + Lang.get(p, "questPoints")); + } + for (final ItemStack i : rewards.getItems()) { + StringBuilder text; + if (i.getItemMeta() != null && i.getItemMeta().hasDisplayName()) { + if (i.getEnchantments().isEmpty()) { + text = new StringBuilder("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + i.getItemMeta().getDisplayName() + + ChatColor.RESET + ChatColor.GRAY + " x " + i.getAmount()); + } else { + text = new StringBuilder("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + i.getItemMeta().getDisplayName() + + ChatColor.RESET); + try { + if (!i.getItemMeta().hasItemFlag(ItemFlag.HIDE_ENCHANTS)) { + text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")).append(ChatColor.DARK_PURPLE); + for (final Entry e : i.getEnchantments().entrySet()) { + text.append(" ").append(ItemUtil.getPrettyEnchantmentName(e.getKey())).append(":").append(e.getValue()); + } + } + } catch (final Throwable tr) { + // Do nothing, hasItemFlag() not introduced until 1.8.6 + } + text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); + } + } else if (i.getDurability() != 0) { + text = new StringBuilder("- " + ChatColor.DARK_GREEN + ":" + i.getDurability()); + if (!i.getEnchantments().isEmpty()) { + text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")); + for (int iz = 0; iz < i.getEnchantments().size(); iz++) { + text.append(" "); + } + } + text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); + } else { + text = new StringBuilder("- " + ChatColor.DARK_GREEN + ""); + if (!i.getEnchantments().isEmpty()) { + try { + if (!i.getItemMeta().hasItemFlag(ItemFlag.HIDE_ENCHANTS)) { + text.append(ChatColor.GRAY).append(" ").append(Lang.get(p, "with")); + for (int iz = 0; iz < i.getEnchantments().size(); iz++) { + text.append(" "); + } + } + } catch (final Throwable tr) { + // Do nothing, hasItemFlag() not introduced until 1.8.6 + } + } + text.append(ChatColor.GRAY).append(" x ").append(i.getAmount()); + } + if (plugin.getSettings().canTranslateNames() && text.toString().contains("")) { + if (!plugin.getLocaleManager().sendMessage(p, text.toString(), i.getType(), i.getDurability(), + i.getEnchantments())) { + for (final Entry e : i.getEnchantments().entrySet()) { + text = new StringBuilder(text.toString().replaceFirst("", ItemUtil.getPrettyEnchantmentName( + e.getKey()))); + text = new StringBuilder(text.toString().replaceFirst("", RomanNumeral.getNumeral(e.getValue()))); + } + quester.sendMessage(text.toString().replace("", ItemUtil.getName(i))); + } + } else { + for (final Entry e : i.getEnchantments().entrySet()) { + text = new StringBuilder(text.toString().replaceFirst("", ItemUtil.getPrettyEnchantmentName( + e.getKey()))); + text = new StringBuilder(text.toString().replaceFirst("", RomanNumeral.getNumeral(e.getValue()))); + } + quester.sendMessage(text.toString().replace("", ItemUtil.getName(i))); + } + } + for (final ItemStack i : phatLootItems) { + if (i.getItemMeta() != null && i.getItemMeta().hasDisplayName()) { + if (i.getEnchantments().isEmpty()) { + quester.sendMessage("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + + i.getItemMeta().getDisplayName() + ChatColor.RESET + ChatColor.GRAY + " x " + + i.getAmount()); + } else { + quester.sendMessage("- " + ChatColor.DARK_AQUA + ChatColor.ITALIC + + i.getItemMeta().getDisplayName() + ChatColor.RESET + ChatColor.GRAY + " x " + + i.getAmount() + ChatColor.DARK_PURPLE + " " + Lang.get(p, "enchantedItem")); + } + } else if (i.getDurability() != 0) { + if (i.getEnchantments().isEmpty()) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ":" + + i.getDurability() + ChatColor.GRAY + " x " + i.getAmount()); + } else { + quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ":" + + i.getDurability() + ChatColor.GRAY + " x " + i.getAmount() + + ChatColor.DARK_PURPLE + " " + Lang.get(p, "enchantedItem")); + } + } else { + if (i.getEnchantments().isEmpty()) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ChatColor.GRAY + + " x " + i.getAmount()); + } else { + quester.sendMessage("- " + ChatColor.DARK_GREEN + ItemUtil.getName(i) + ChatColor.GRAY + + " x " + i.getAmount() + ChatColor.DARK_PURPLE + " " + + Lang.get(p, "enchantedItem")); + } + } + } + if (rewards.getMoney() > 0 && depends.getVaultEconomy() != null) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + + depends.getVaultEconomy().format(rewards.getMoney())); + } + if (rewards.getExp() > 0 || phatLootExp > 0) { + final int tot = rewards.getExp() + phatLootExp; + quester.sendMessage("- " + ChatColor.DARK_GREEN + tot + ChatColor.DARK_PURPLE + " " + + Lang.get(p, "experience")); + } + if (!rewards.getCommands().isEmpty()) { + int index = 0; + for (final String s : rewards.getCommands()) { + if (!rewards.getCommandsOverrideDisplay().isEmpty() + && rewards.getCommandsOverrideDisplay().size() > index) { + if (!rewards.getCommandsOverrideDisplay().get(index).trim().equals("")) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + + rewards.getCommandsOverrideDisplay().get(index)); + } + } else { + quester.sendMessage("- " + ChatColor.DARK_GREEN + s); + } + index++; + } + } + if (!rewards.getPermissions().isEmpty()) { + int index = 0; + for (final String s : rewards.getPermissions()) { + if (rewards.getPermissionWorlds() != null && rewards.getPermissionWorlds().size() > index) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + s + " (" + + rewards.getPermissionWorlds().get(index) + ")"); + } else { + quester.sendMessage("- " + ChatColor.DARK_GREEN + s); + + } + index++; + } + } + if (!rewards.getMcmmoSkills().isEmpty()) { + for (final String s : rewards.getMcmmoSkills()) { + quester.sendMessage("- " + ChatColor.DARK_GREEN + + rewards.getMcmmoAmounts().get(rewards.getMcmmoSkills().indexOf(s)) + " " + + ChatColor.DARK_PURPLE + s + " " + Lang.get(p, "experience")); + } + } + if (!rewards.getHeroesClasses().isEmpty()) { + for (final String s : rewards.getHeroesClasses()) { + quester.sendMessage("- " + ChatColor.AQUA + + rewards.getHeroesAmounts().get(rewards.getHeroesClasses().indexOf(s)) + " " + ChatColor.BLUE + + s + " " + Lang.get(p, "experience")); + } + } + if (rewards.getPartiesExperience() > 0) { + p.sendMessage("- " + ChatColor.DARK_GREEN + rewards.getPartiesExperience() + ChatColor.DARK_PURPLE + + " " + Lang.get(p, "partiesExperience")); + } + if (!phatLootMessages.isEmpty()) { + for (final String s : phatLootMessages) { + quester.sendMessage("- " + s); + } + } + for (final String s : rewards.getCustomRewards().keySet()) { + CustomReward found = null; + for (final CustomReward cr : plugin.getCustomRewards()) { + if (cr.getName().equalsIgnoreCase(s)) { + found = cr; + break; + } + } + if (found != null) { + final Map dataMap = rewards.getCustomRewards().get(found.getName()); + String message = found.getDisplay(); + if (message != null) { + for (final String key : dataMap.keySet()) { + message = message.replace("%" + key + "%", dataMap.get(key).toString()); + } + quester.sendMessage("- " + ChatColor.GOLD + message); + } else { + plugin.getLogger().warning("Failed to notify player: " + + "Custom Reward does not have an assigned name"); + } + found.giveReward(p, rewards.getCustomRewards().get(s)); + } else { + plugin.getLogger().warning("Quester \"" + player.getName() + "\" completed the Quest \"" + + name + "\", but the Custom Reward \"" + s + + "\" could not be found. Does it still exist?"); + } + } + } + } + quester.saveData(); + if (player.isOnline()) { + if (player.getPlayer() != null) { + player.getPlayer().updateInventory(); + } + } + quester.updateJournal(); + quester.findCompassTarget(); + if (player.isOnline()) { + final QuesterPostCompleteQuestEvent postEvent = new QuesterPostCompleteQuestEvent(quester, this); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + // Multiplayer + if (allowMultiplayer && options.getShareProgressLevel() == 4) { + final List mq = quester.getMultiplayerQuesters(this); + for (final BukkitQuester qq : mq) { + if (qq.getQuestData(this) != null) { + completeQuest(qq, false); + } + } + } + } + + /** + * Force player to quit quest and inform them of their failure + * + * @param quester The quester to be ejected + */ + public void failQuest(final BukkitQuester quester) { + failQuest(quester, false); + } + + /** + * Force player to quit quest and inform them of their failure + * + * @param quester The quester to be ejected + * @param ignoreFailAction Whether to ignore quest fail Action + */ + @SuppressWarnings("deprecation") + public void failQuest(final BukkitQuester quester, final boolean ignoreFailAction) { + final QuesterPreFailQuestEvent preEvent = new QuesterPreFailQuestEvent(quester, this); + plugin.getServer().getPluginManager().callEvent(preEvent); + if (preEvent.isCancelled()) { + return; + } + final Player player = quester.getPlayer(); + if (!ignoreFailAction) { + final Stage stage = quester.getCurrentStage(this); + if (stage != null && stage.getFailAction() != null) { + quester.getCurrentStage(this).getFailAction().fire(quester, this); + } + } + final String[] messages = { + ChatColor.GOLD + Lang.get(player, "questCommandTitle").replace("", name), + ChatColor.RED + Lang.get(player, "questFailed") + }; + quester.quitQuest(this, messages); + if (player.isOnline()) { + player.updateInventory(); + } + final QuesterPostFailQuestEvent postEvent = new QuesterPostFailQuestEvent(quester, this); + plugin.getServer().getPluginManager().callEvent(postEvent); + } + + /** + * Checks if quester is in WorldGuard region start + * + * @deprecated Use {@link #isInRegionStart(BukkitQuester)} + * @param quester The quester to check + * @return true if quester is in region + */ + @Deprecated + public boolean isInRegion(final BukkitQuester quester) { + return isInRegionStart(quester); + } + + /** + * Checks if player is in WorldGuard region start + * + * @deprecated Use {@link #isInRegionStart(Player)} + * @param player The player to check + * @return true if player is in region + */ + @Deprecated + @SuppressWarnings("unused") + private boolean isInRegion(final Player player) { + return isInRegionStart(player); + } + + /** + * Checks if quester is in WorldGuard region start + * + * @param quester The quester to check + * @return true if quester is in region + */ + public boolean isInRegionStart(final BukkitQuester quester) { + return isInRegionStart(quester.getPlayer()); + } + + /** + * Checks if player is in WorldGuard region start + * + * @param player The player to check + * @return true if player is in region + */ + private boolean isInRegionStart(final Player player) { + if (regionStart == null) { + return false; + } + return plugin.getDependencies().getWorldGuardApi() + .getApplicableRegionsIDs(player.getWorld(), player.getLocation()).contains(regionStart); + } +} diff --git a/core/src/main/java/me/blackvein/quests/quests/BukkitRequirements.java b/core/src/main/java/me/blackvein/quests/quests/BukkitRequirements.java new file mode 100644 index 000000000..82290731a --- /dev/null +++ b/core/src/main/java/me/blackvein/quests/quests/BukkitRequirements.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 PikaMug and contributors. All rights reserved. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package me.blackvein.quests.quests; + +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class BukkitRequirements { + private int money = 0; + private int questPoints = 0; + private List items = new LinkedList<>(); + private List removeItems = new LinkedList<>(); + private List neededQuests = new LinkedList<>(); + private List blockQuests = new LinkedList<>(); + private List permissions = new LinkedList<>(); + private List mcmmoSkills = new LinkedList<>(); + private List mcmmoAmounts = new LinkedList<>(); + private String heroesPrimaryClass = null; + private String heroesSecondaryClass = null; + private Map> customRequirements = new HashMap<>(); + private List detailsOverride = new LinkedList<>(); + + public int getMoney() { + return money; + } + public void setMoney(final int money) { + this.money = money; + } + public int getQuestPoints() { + return questPoints; + } + public void setQuestPoints(final int questPoints) { + this.questPoints = questPoints; + } + public List getItems() { + return items; + } + public void setItems(final List items) { + this.items = items; + } + public List getRemoveItems() { + return removeItems; + } + public void setRemoveItems(final List removeItems) { + this.removeItems = removeItems; + } + public List getNeededQuests() { + return neededQuests; + } + public void setNeededQuests(final List neededQuests) { + this.neededQuests = neededQuests; + } + public List getBlockQuests() { + return blockQuests; + } + public void setBlockQuests(final List blockQuests) { + this.blockQuests = blockQuests; + } + public List getPermissions() { + return permissions; + } + public void setPermissions(final List permissions) { + this.permissions = permissions; + } + public List getMcmmoSkills() { + return mcmmoSkills; + } + public void setMcmmoSkills(final List mcmmoSkills) { + this.mcmmoSkills = mcmmoSkills; + } + public List getMcmmoAmounts() { + return mcmmoAmounts; + } + public void setMcmmoAmounts(final List mcmmoAmounts) { + this.mcmmoAmounts = mcmmoAmounts; + } + public String getHeroesPrimaryClass() { + return heroesPrimaryClass; + } + public void setHeroesPrimaryClass(final String heroesPrimaryClass) { + this.heroesPrimaryClass = heroesPrimaryClass; + } + public String getHeroesSecondaryClass() { + return heroesSecondaryClass; + } + public void setHeroesSecondaryClass(final String heroesSecondaryClass) { + this.heroesSecondaryClass = heroesSecondaryClass; + } + public Map> getCustomRequirements() { + return customRequirements; + } + protected void setCustomRequirements(final Map> customRequirements) { + this.customRequirements = customRequirements; + } + public List getDetailsOverride() { + return detailsOverride; + } + public void setDetailsOverride(final List detailsOverride) { + this.detailsOverride = detailsOverride; + } +} diff --git a/core/src/main/java/me/blackvein/quests/quests/BukkitRewards.java b/core/src/main/java/me/blackvein/quests/quests/BukkitRewards.java new file mode 100644 index 000000000..aa7786369 --- /dev/null +++ b/core/src/main/java/me/blackvein/quests/quests/BukkitRewards.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014 PikaMug and contributors. All rights reserved. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package me.blackvein.quests.quests; + +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class BukkitRewards { + private int money = 0; + private int questPoints = 0; + private int exp = 0; + private List commands = new LinkedList<>(); + private List commandsOverrideDisplay = new LinkedList<>(); + private List permissions = new LinkedList<>(); + private List permissionWorlds = new LinkedList<>(); + private List items = new LinkedList<>(); + private List mcmmoSkills = new LinkedList<>(); + private List mcmmoAmounts = new LinkedList<>(); + private List heroesClasses = new LinkedList<>(); + private List heroesAmounts = new LinkedList<>(); + private int partiesExperience = 0; + private List phatLoots = new LinkedList<>(); + private Map> customRewards = new HashMap<>(); + private List detailsOverride = new LinkedList<>(); + + public int getMoney() { + return money; + } + public void setMoney(final int money) { + this.money = money; + } + public int getQuestPoints() { + return questPoints; + } + public void setQuestPoints(final int questPoints) { + this.questPoints = questPoints; + } + public int getExp() { + return exp; + } + public void setExp(final int exp) { + this.exp = exp; + } + public List getCommands() { + return commands; + } + public void setCommands(final List commands) { + this.commands = commands; + } + public List getCommandsOverrideDisplay() { + return commandsOverrideDisplay; + } + public void setCommandsOverrideDisplay(final List commandsOverrideDisplay) { + this.commandsOverrideDisplay = commandsOverrideDisplay; + } + public List getPermissions() { + return permissions; + } + public void setPermissions(final List permissions) { + this.permissions = permissions; + } + public List getPermissionWorlds() { + return permissionWorlds; + } + public void setPermissionWorlds(final List worldNames) { + this.permissionWorlds = worldNames; + } + public List getItems() { + return items; + } + public void setItems(final List items) { + this.items = items; + } + public List getMcmmoSkills() { + return mcmmoSkills; + } + public void setMcmmoSkills(final List mcmmoSkills) { + this.mcmmoSkills = mcmmoSkills; + } + public List getMcmmoAmounts() { + return mcmmoAmounts; + } + public void setMcmmoAmounts(final List mcmmoAmounts) { + this.mcmmoAmounts = mcmmoAmounts; + } + public List getHeroesClasses() { + return heroesClasses; + } + public void setHeroesClasses(final List heroesClasses) { + this.heroesClasses = heroesClasses; + } + public List getHeroesAmounts() { + return heroesAmounts; + } + public void setHeroesAmounts(final List heroesAmounts) { + this.heroesAmounts = heroesAmounts; + } + public int getPartiesExperience() { + return partiesExperience; + } + public void setPartiesExperience(final int partiesExperience) { + this.partiesExperience = partiesExperience; + } + public List getPhatLoots() { + return phatLoots; + } + public void setPhatLoots(final List phatLoots) { + this.phatLoots = phatLoots; + } + public Map> getCustomRewards() { + return customRewards; + } + protected void setCustomRewards(final Map> customRewards) { + this.customRewards = customRewards; + } + public List getDetailsOverride() { + return detailsOverride; + } + public void setDetailsOverride(final List detailsOverride) { + this.detailsOverride = detailsOverride; + } +} diff --git a/core/src/main/java/me/blackvein/quests/quests/BukkitStage.java b/core/src/main/java/me/blackvein/quests/quests/BukkitStage.java new file mode 100644 index 000000000..443e3555b --- /dev/null +++ b/core/src/main/java/me/blackvein/quests/quests/BukkitStage.java @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2014 PikaMug and contributors. All rights reserved. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package me.blackvein.quests.quests; + +import me.blackvein.quests.CustomObjective; +import me.blackvein.quests.Stage; +import me.blackvein.quests.actions.Action; +import me.blackvein.quests.actions.Action; +import me.blackvein.quests.conditions.Condition; +import me.blackvein.quests.enums.ObjectiveType; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Map.Entry; + +public class BukkitStage implements Stage { + + private LinkedList blocksToBreak = new LinkedList<>(); + private LinkedList blocksToDamage = new LinkedList<>(); + private LinkedList blocksToPlace = new LinkedList<>(); + private LinkedList blocksToUse = new LinkedList<>(); + private LinkedList blocksToCut = new LinkedList<>(); + private LinkedList itemsToCraft = new LinkedList<>(); + private LinkedList itemsToSmelt = new LinkedList<>(); + private LinkedList itemsToEnchant = new LinkedList<>(); + private LinkedList itemsToBrew = new LinkedList<>(); + private LinkedList itemsToConsume = new LinkedList<>(); + private LinkedList itemsToDeliver = new LinkedList<>(); + private LinkedList itemDeliveryTargets = new LinkedList() { + + private static final long serialVersionUID = -2774443496142382127L; + + @Override + public boolean equals(final Object o) { + if (o instanceof LinkedList) { + @SuppressWarnings("unchecked") + final + LinkedList otherList = (LinkedList) o; + for (final Integer i : this) { + final Integer other = otherList.get(this.indexOf(i)); + if (!other.equals(i)) { + return false; + } + } + } + return true; + } + }; + private LinkedList deliverMessages = new LinkedList<>(); + private LinkedList citizensToInteract = new LinkedList() { + + private static final long serialVersionUID = -4086855121042524435L; + + @Override + public boolean equals(final Object o) { + if (o instanceof LinkedList) { + @SuppressWarnings("unchecked") + final + LinkedList otherList = (LinkedList) o; + for (final Integer i : this) { + final Integer other = otherList.get(this.indexOf(i)); + if (!other.equals(i)) { + return false; + } + } + } + return true; + } + }; + private LinkedList citizensToKill = new LinkedList() { + + private static final long serialVersionUID = 7705964814014176415L; + + @Override + public boolean equals(final Object o) { + if (o instanceof LinkedList) { + @SuppressWarnings("unchecked") + final + LinkedList otherList = (LinkedList) o; + for (final Integer i : this) { + final Integer other = otherList.get(this.indexOf(i)); + if (!other.equals(i)) { + return false; + } + } + } + return true; + } + }; + private LinkedList citizenNumToKill = new LinkedList<>(); + private LinkedList mobsToKill = new LinkedList<>(); + private LinkedList mobNumToKill = new LinkedList<>(); + private LinkedList locationsToKillWithin = new LinkedList<>(); + private LinkedList radiiToKillWithin = new LinkedList<>(); + private LinkedList killNames = new LinkedList<>(); + private LinkedList mobsToTame = new LinkedList<>(); + private LinkedList mobNumToTame = new LinkedList<>(); + private Integer fishToCatch; + private Integer cowsToMilk; + private LinkedList sheepToShear = new LinkedList<>(); + private LinkedList sheepNumToShear = new LinkedList<>(); + private Integer playersToKill; + private LinkedList locationsToReach = new LinkedList<>(); + private LinkedList radiiToReachWithin = new LinkedList<>(); + private LinkedList worldsToReachWithin = new LinkedList<>(); + private LinkedList locationNames = new LinkedList<>(); + private LinkedList passwordDisplays = new LinkedList<>(); + private LinkedList passwordPhrases = new LinkedList<>(); + private String script; + private Action startAction = null; + private Action finishAction = null; + private Action failAction = null; + private Action deathAction = null; + private Map chatActions = new HashMap<>(); + private Map commandActions = new HashMap<>(); + private Action disconnectAction = null; + private Condition condition = null; + private long delay = -1; + private String delayMessage = null; + private String completeMessage = null; + private String startMessage = null; + private LinkedList objectiveOverrides = new LinkedList<>(); + private LinkedList customObjectives = new LinkedList<>(); + private LinkedList customObjectiveCounts = new LinkedList<>(); + private LinkedList customObjectiveDisplays = new LinkedList<>(); + private LinkedList> customObjectiveData = new LinkedList<>(); + + public LinkedList getBlocksToBreak() { + return blocksToBreak; + } + + public void setBlocksToBreak(final LinkedList blocksToBreak) { + this.blocksToBreak = blocksToBreak; + } + + public LinkedList getBlocksToDamage() { + return blocksToDamage; + } + + public void setBlocksToDamage(final LinkedList blocksToDamage) { + this.blocksToDamage = blocksToDamage; + } + + public LinkedList getBlocksToPlace() { + return blocksToPlace; + } + + public void setBlocksToPlace(final LinkedList blocksToPlace) { + this.blocksToPlace = blocksToPlace; + } + + public LinkedList getBlocksToUse() { + return blocksToUse; + } + + public void setBlocksToUse(final LinkedList blocksToUse) { + this.blocksToUse = blocksToUse; + } + + public LinkedList getBlocksToCut() { + return blocksToCut; + } + + public void setBlocksToCut(final LinkedList blocksToCut) { + this.blocksToCut = blocksToCut; + } + + public LinkedList getItemsToCraft() { + return itemsToCraft; + } + + public void setItemsToCraft(final LinkedList itemsToCraft) { + this.itemsToCraft = itemsToCraft; + } + + public LinkedList getItemsToSmelt() { + return itemsToSmelt; + } + + public void setItemsToSmelt(final LinkedList itemsToSmelt) { + this.itemsToSmelt = itemsToSmelt; + } + + public LinkedList getItemsToEnchant() { + return itemsToEnchant; + } + + public void setItemsToEnchant(final LinkedList itemsToEnchant) { + this.itemsToEnchant = itemsToEnchant; + } + + public LinkedList getItemsToBrew() { + return itemsToBrew; + } + + public void setItemsToBrew(final LinkedList itemsToBrew) { + this.itemsToBrew = itemsToBrew; + } + + public LinkedList getItemsToConsume() { + return itemsToConsume; + } + + public void setItemsToConsume(final LinkedList itemsToConsume) { + this.itemsToBrew = itemsToConsume; + } + + public LinkedList getItemsToDeliver() { + return itemsToDeliver; + } + + public void setItemsToDeliver(final LinkedList itemsToDeliver) { + this.itemsToDeliver = itemsToDeliver; + } + + public LinkedList getItemDeliveryTargets() { + return itemDeliveryTargets; + } + + public void setItemDeliveryTargets(final LinkedList itemDeliveryTargets) { + this.itemDeliveryTargets = itemDeliveryTargets; + } + + public LinkedList getDeliverMessages() { + return deliverMessages; + } + + public void setDeliverMessages(final LinkedList deliverMessages) { + this.deliverMessages = deliverMessages; + } + + public LinkedList getCitizensToInteract() { + return citizensToInteract; + } + + public void setCitizensToInteract(final LinkedList citizensToInteract) { + this.citizensToInteract = citizensToInteract; + } + + public LinkedList getCitizensToKill() { + return citizensToKill; + } + + public void setCitizensToKill(final LinkedList citizensToKill) { + this.citizensToKill = citizensToKill; + } + + public LinkedList getCitizenNumToKill() { + return citizenNumToKill; + } + + public void setCitizenNumToKill(final LinkedList citizenNumToKill) { + this.citizenNumToKill = citizenNumToKill; + } + + public LinkedList getMobsToKill() { + return mobsToKill; + } + + public void setMobsToKill(final LinkedList mobsToKill) { + this.mobsToKill = mobsToKill; + } + + public LinkedList getMobNumToKill() { + return mobNumToKill; + } + + public void setMobNumToKill(final LinkedList mobNumToKill) { + this.mobNumToKill = mobNumToKill; + } + + public LinkedList getLocationsToKillWithin() { + return locationsToKillWithin; + } + + public void setLocationsToKillWithin(final LinkedList locationsToKillWithin) { + this.locationsToKillWithin = locationsToKillWithin; + } + + public LinkedList getRadiiToKillWithin() { + return radiiToKillWithin; + } + + public void setRadiiToKillWithin(final LinkedList radiiToKillWithin) { + this.radiiToKillWithin = radiiToKillWithin; + } + + public LinkedList getKillNames() { + return killNames; + } + + public void setKillNames(final LinkedList killNames) { + this.killNames = killNames; + } + + public LinkedList getLocationsToReach() { + return locationsToReach; + } + + public void setLocationsToReach(final LinkedList locationsToReach) { + this.locationsToReach = locationsToReach; + } + + public LinkedList getRadiiToReachWithin() { + return radiiToReachWithin; + } + + public void setRadiiToReachWithin(final LinkedList radiiToReachWithin) { + this.radiiToReachWithin = radiiToReachWithin; + } + + public LinkedList getWorldsToReachWithin() { + return worldsToReachWithin; + } + + public void setWorldsToReachWithin(final LinkedList worldsToReachWithin) { + this.worldsToReachWithin = worldsToReachWithin; + } + + public LinkedList getLocationNames() { + return locationNames; + } + + public void setLocationNames(final LinkedList locationNames) { + this.locationNames = locationNames; + } + + public LinkedList getMobsToTame() { + return mobsToTame; + } + + public void setMobsToTame(final LinkedList mobsToTame) { + this.mobsToTame = mobsToTame; + } + + public LinkedList getMobNumToTame() { + return mobNumToTame; + } + + public void setMobNumToTame(final LinkedList mobNumToTame) { + this.mobNumToTame = mobNumToTame; + } + + public Integer getFishToCatch() { + return fishToCatch; + } + + public void setFishToCatch(final Integer fishToCatch) { + this.fishToCatch = fishToCatch; + } + + public Integer getCowsToMilk() { + return cowsToMilk; + } + + public void setCowsToMilk(final Integer cowsToMilk) { + this.cowsToMilk = cowsToMilk; + } + + public Integer getPlayersToKill() { + return playersToKill; + } + + public void setPlayersToKill(final Integer playersToKill) { + this.playersToKill = playersToKill; + } + + public LinkedList getSheepToShear() { + return sheepToShear; + } + + public void setSheepToShear(final LinkedList sheepToShear) { + this.sheepToShear = sheepToShear; + } + + public LinkedList getSheepNumToShear() { + return sheepNumToShear; + } + + public void setSheepNumToShear(final LinkedList sheepNumToShear) { + this.sheepNumToShear = sheepNumToShear; + } + + public LinkedList getPasswordDisplays() { + return passwordDisplays; + } + + public void setPasswordDisplays(final LinkedList passwordDisplays) { + this.passwordDisplays = passwordDisplays; + } + + public LinkedList getPasswordPhrases() { + return passwordPhrases; + } + + public void setPasswordPhrases(final LinkedList passwordPhrases) { + this.passwordPhrases = passwordPhrases; + } + + public String getScript() { + return script; + } + + public void setScript(final String script) { + this.script = script; + } + + public Action getStartAction() { + return startAction; + } + + public void setStartAction(final Action startAction) { + this.startAction = startAction; + } + + public Action getFinishAction() { + return finishAction; + } + + public void setFinishAction(final Action finishAction) { + this.finishAction = finishAction; + } + + public Action getFailAction() { + return failAction; + } + + public void setFailAction(final Action failAction) { + this.failAction = failAction; + } + + public Action getDeathAction() { + return deathAction; + } + + public void setDeathAction(final Action deathAction) { + this.deathAction = deathAction; + } + + public Map getChatActions() { + return chatActions; + } + + public void setChatActions(final Map chatActions) { + this.chatActions = chatActions; + } + + public Map getCommandActions() { + return commandActions; + } + + public void setCommandActions(final Map commandActions) { + this.commandActions = commandActions; + } + + public Action getDisconnectAction() { + return disconnectAction; + } + + public void setDisconnectAction(final Action disconnectAction) { + this.disconnectAction = disconnectAction; + } + + public Condition getCondition() { + return condition; + } + + public void setCondition(final Condition condition) { + this.condition = condition; + } + + public long getDelay() { + return delay; + } + + public void setDelay(final long delay) { + this.delay = delay; + } + + public String getDelayMessage() { + return delayMessage; + } + + public void setDelayMessage(final String delayMessage) { + this.delayMessage = delayMessage; + } + + public String getCompleteMessage() { + return completeMessage; + } + + public void setCompleteMessage(final String completeMessage) { + this.completeMessage = completeMessage; + } + + public String getStartMessage() { + return startMessage; + } + + public void setStartMessage(final String startMessage) { + this.startMessage = startMessage; + } + + public LinkedList getObjectiveOverrides() { + return objectiveOverrides; + } + + public void setObjectiveOverrides(final LinkedList objectiveOverrides) { + this.objectiveOverrides = objectiveOverrides; + } + + public LinkedList getCustomObjectives() { + return customObjectives; + } + + public LinkedList getCustomObjectiveCounts() { + return customObjectiveCounts; + } + + public LinkedList getCustomObjectiveDisplays() { + return customObjectiveDisplays; + } + + public LinkedList> getCustomObjectiveData() { + return customObjectiveData; + } + + /** + * Check if stage has at least one objective

+ * + * Excludes start/complete message, delay, and objective-override + * + * @return true if stage contains an objective + */ + public boolean hasObjective() { + if (!blocksToBreak.isEmpty()) { return true; } + if (!blocksToDamage.isEmpty()) { return true; } + if (!blocksToPlace.isEmpty()) { return true; } + if (!blocksToUse.isEmpty()) { return true; } + if (!blocksToCut.isEmpty()) { return true; } + if (cowsToMilk != null) { return true; } + if (fishToCatch != null) { return true; } + if (playersToKill != null) { return true; } + if (!itemsToCraft.isEmpty()) { return true; } + if (!itemsToSmelt.isEmpty()) { return true; } + if (!itemsToEnchant.isEmpty()) { return true; } + if (!itemsToBrew.isEmpty()) { return true; } + if (!itemsToConsume.isEmpty()) { return true; } + if (!itemsToDeliver.isEmpty()) { return true; } + if (!citizensToInteract.isEmpty()) { return true; } + if (!citizensToKill.isEmpty()) { return true; } + if (!locationsToReach.isEmpty()) { return true; } + if (!mobsToTame.isEmpty()) { return true; } + if (!sheepToShear.isEmpty()) { return true; } + if (!passwordDisplays.isEmpty()) { return true; } + return !customObjectives.isEmpty(); + } + + /** + * Check if stage has the specified type of objective

+ * + * @param type The type of objective to check for + * @return true if stage contains specified objective + */ + public boolean containsObjective(final ObjectiveType type) { + if (type.equals(ObjectiveType.BREAK_BLOCK)) { + return !blocksToBreak.isEmpty(); + } else if (type.equals(ObjectiveType.DAMAGE_BLOCK)) { + return !blocksToDamage.isEmpty(); + } else if (type.equals(ObjectiveType.PLACE_BLOCK)) { + return !blocksToPlace.isEmpty(); + } else if (type.equals(ObjectiveType.USE_BLOCK)) { + return !blocksToUse.isEmpty(); + } else if (type.equals(ObjectiveType.CUT_BLOCK)) { + return !blocksToCut.isEmpty(); + } else if (type.equals(ObjectiveType.CRAFT_ITEM)) { + return !itemsToCraft.isEmpty(); + } else if (type.equals(ObjectiveType.SMELT_ITEM)) { + return !itemsToSmelt.isEmpty(); + } else if (type.equals(ObjectiveType.ENCHANT_ITEM)) { + return !itemsToEnchant.isEmpty(); + } else if (type.equals(ObjectiveType.BREW_ITEM)) { + return !itemsToBrew.isEmpty(); + } else if (type.equals(ObjectiveType.CONSUME_ITEM)) { + return !itemsToConsume.isEmpty(); + } else if (type.equals(ObjectiveType.DELIVER_ITEM)) { + return !itemsToDeliver.isEmpty(); + } else if (type.equals(ObjectiveType.MILK_COW)) { + return cowsToMilk != null; + } else if (type.equals(ObjectiveType.CATCH_FISH)) { + return fishToCatch != null; + } else if (type.equals(ObjectiveType.KILL_MOB)) { + return !mobsToKill.isEmpty(); + } else if (type.equals(ObjectiveType.KILL_PLAYER)) { + return playersToKill != null; + } else if (type.equals(ObjectiveType.TALK_TO_NPC)) { + return !citizensToInteract.isEmpty(); + } else if (type.equals(ObjectiveType.KILL_NPC)) { + return !citizensToKill.isEmpty(); + } else if (type.equals(ObjectiveType.TAME_MOB)) { + return !mobsToTame.isEmpty(); + } else if (type.equals(ObjectiveType.SHEAR_SHEEP)) { + return !sheepToShear.isEmpty(); + } else if (type.equals(ObjectiveType.REACH_LOCATION)) { + return !locationsToReach.isEmpty(); + } else if (type.equals(ObjectiveType.PASSWORD)) { + return !passwordPhrases.isEmpty(); + } else { + return false; + } + } +} diff --git a/api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI.java b/core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI.java rename to core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI.java diff --git a/api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_0_9.java b/core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_0_9.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_0_9.java rename to core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_0_9.java diff --git a/api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_0.java b/core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_0.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_0.java rename to core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_0.java diff --git a/api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_1.java b/core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_1.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_1.java rename to core/src/main/java/me/blackvein/quests/reflect/denizen/DenizenAPI_1_1_1.java diff --git a/api/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI.java b/core/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI.java rename to core/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI.java diff --git a/api/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI_7_0_0.java b/core/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI_7_0_0.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI_7_0_0.java rename to core/src/main/java/me/blackvein/quests/reflect/worldguard/WorldGuardAPI_7_0_0.java diff --git a/api/src/main/java/me/blackvein/quests/statistics/Metrics.java b/core/src/main/java/me/blackvein/quests/statistics/Metrics.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/statistics/Metrics.java rename to core/src/main/java/me/blackvein/quests/statistics/Metrics.java diff --git a/api/src/main/java/me/blackvein/quests/storage/Storage.java b/core/src/main/java/me/blackvein/quests/storage/Storage.java similarity index 93% rename from api/src/main/java/me/blackvein/quests/storage/Storage.java rename to core/src/main/java/me/blackvein/quests/storage/Storage.java index afba415ed..b5b051555 100644 --- a/api/src/main/java/me/blackvein/quests/storage/Storage.java +++ b/core/src/main/java/me/blackvein/quests/storage/Storage.java @@ -12,7 +12,7 @@ package me.blackvein.quests.storage; -import me.blackvein.quests.Quester; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; import me.blackvein.quests.storage.implementation.StorageImplementation; @@ -85,11 +85,11 @@ public class Storage { } } - public CompletableFuture loadQuester(final UUID uniqueId) { + public CompletableFuture loadQuester(final UUID uniqueId) { return makeFuture(() -> implementation.loadQuester(uniqueId)); } - public CompletableFuture saveQuester(final Quester quester) { + public CompletableFuture saveQuester(final BukkitQuester quester) { return makeFuture(() -> { try { implementation.saveQuester(quester); @@ -102,7 +102,7 @@ public class Storage { public CompletableFuture saveOfflineQuesters() { return makeFuture(() -> { try { - for (Quester quester : plugin.getOfflineQuesters()) { + for (BukkitQuester quester : plugin.getOfflineQuesters()) { implementation.saveQuester(quester); } } catch (final Exception e) { diff --git a/api/src/main/java/me/blackvein/quests/storage/StorageFactory.java b/core/src/main/java/me/blackvein/quests/storage/StorageFactory.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/StorageFactory.java rename to core/src/main/java/me/blackvein/quests/storage/StorageFactory.java diff --git a/api/src/main/java/me/blackvein/quests/storage/StorageType.java b/core/src/main/java/me/blackvein/quests/storage/StorageType.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/StorageType.java rename to core/src/main/java/me/blackvein/quests/storage/StorageType.java diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java b/core/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java similarity index 88% rename from api/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java index 46f3e12d4..01ae514d6 100644 --- a/api/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java +++ b/core/src/main/java/me/blackvein/quests/storage/implementation/StorageImplementation.java @@ -12,7 +12,7 @@ package me.blackvein.quests.storage.implementation; -import me.blackvein.quests.Quester; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; import java.util.Collection; @@ -27,9 +27,9 @@ public interface StorageImplementation { void close(); - Quester loadQuester(UUID uniqueId) throws Exception; + BukkitQuester loadQuester(UUID uniqueId) throws Exception; - void saveQuester(Quester quester) throws Exception; + void saveQuester(BukkitQuester quester) throws Exception; void deleteQuester(UUID uniqueId) throws Exception; diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProvider.java b/core/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProvider.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProvider.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProvider.java diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProviders.java b/core/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProviders.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProviders.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/custom/CustomStorageProviders.java diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java b/core/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java similarity index 94% rename from api/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java index 971da40db..a56ee2116 100644 --- a/api/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java +++ b/core/src/main/java/me/blackvein/quests/storage/implementation/file/SeparatedYamlStorage.java @@ -12,18 +12,16 @@ package me.blackvein.quests.storage.implementation.file; -import me.blackvein.quests.Quest; -import me.blackvein.quests.Quester; +import me.blackvein.quests.quests.BukkitQuest; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; -import me.blackvein.quests.Stage; +import me.blackvein.quests.quests.BukkitStage; import me.blackvein.quests.storage.implementation.StorageImplementation; -import me.blackvein.quests.util.MiscUtil; import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.io.File; @@ -67,13 +65,13 @@ public class SeparatedYamlStorage implements StorageImplementation { @SuppressWarnings("deprecation") @Override - public Quester loadQuester(final UUID uniqueId) throws Exception { + public BukkitQuester loadQuester(final UUID uniqueId) throws Exception { final FileConfiguration data = new YamlConfiguration(); - Quester quester = plugin.getQuester(uniqueId); + BukkitQuester quester = plugin.getQuester(uniqueId); if (quester != null) { quester.hardClear(); } else { - quester = new Quester(plugin, uniqueId); + quester = new BukkitQuester(plugin, uniqueId); } try { final File dataFile = getDataFile(quester); @@ -89,7 +87,7 @@ public class SeparatedYamlStorage implements StorageImplementation { if (data.contains("completedRedoableQuests")) { final List questIds = data.getStringList("completedRedoableQuests"); final List questTimes = data.getLongList("completedQuestTimes"); - final ConcurrentHashMap completedTimes = quester.getCompletedTimes(); + final ConcurrentHashMap completedTimes = quester.getCompletedTimes(); for (int i = 0; i < questIds.size(); i++) { if (plugin.getQuestById(questIds.get(i)) != null) { completedTimes.put(plugin.getQuestById(questIds.get(i)), questTimes.get(i)); @@ -103,7 +101,7 @@ public class SeparatedYamlStorage implements StorageImplementation { if (data.contains("amountsCompletedQuests")) { final List questIds = data.getStringList("amountsCompletedQuests"); final List questAmounts = data.getIntegerList("amountsCompleted"); - final ConcurrentHashMap amountsCompleted = quester.getAmountsCompleted(); + final ConcurrentHashMap amountsCompleted = quester.getAmountsCompleted(); for (int i = 0; i < questIds.size(); i++) { if (plugin.getQuestById(questIds.get(i)) != null) { amountsCompleted.put(plugin.getQuestById(questIds.get(i)), questAmounts.get(i)); @@ -116,10 +114,10 @@ public class SeparatedYamlStorage implements StorageImplementation { } quester.setLastKnownName(data.getString("lastKnownName")); quester.setQuestPoints(data.getInt("quest-points")); - final ConcurrentSkipListSet completedQuests = quester.getCompletedQuests(); + final ConcurrentSkipListSet completedQuests = quester.getCompletedQuests(); if (data.isList("completed-Quests")) { for (final String s : data.getStringList("completed-Quests")) { - for (final Quest q : plugin.getLoadedQuests()) { + for (final BukkitQuest q : plugin.getLoadedQuests()) { if (q.getId().equals(s)) { if (!quester.getCompletedQuests().contains(q)) { completedQuests.add(q); @@ -140,7 +138,7 @@ public class SeparatedYamlStorage implements StorageImplementation { final List questIds = data.getStringList("currentQuests"); final List questStages = data.getIntegerList("currentStages"); final int maxSize = Math.min(questIds.size(), questStages.size()); - final ConcurrentHashMap currentQuests = quester.getCurrentQuests(); + final ConcurrentHashMap currentQuests = quester.getCurrentQuests(); for (int i = 0; i < maxSize; i++) { if (plugin.getQuestById(questIds.get(i)) != null) { currentQuests.put(plugin.getQuestById(questIds.get(i)), questStages.get(i)); @@ -156,11 +154,11 @@ public class SeparatedYamlStorage implements StorageImplementation { } for (final String key : dataSec.getKeys(false)) { final ConfigurationSection questSec = dataSec.getConfigurationSection(key); - final Quest quest = plugin.getQuestById(key) != null ? plugin.getQuestById(key) : plugin.getQuest(key); + final BukkitQuest quest = plugin.getQuestById(key) != null ? plugin.getQuestById(key) : plugin.getQuest(key); if (quest == null || !quester.getCurrentQuests().containsKey(quest)) { continue; } - final Stage stage = quester.getCurrentStage(quest); + final BukkitStage stage = quester.getCurrentStage(quest); if (stage == null) { quest.completeQuest(quester); plugin.getLogger().severe("[Quests] Invalid stage number for player: \"" + uniqueId + "\" on Quest \"" @@ -378,7 +376,7 @@ public class SeparatedYamlStorage implements StorageImplementation { } @Override - public void saveQuester(final Quester quester) throws Exception { + public void saveQuester(final BukkitQuester quester) throws Exception { final FileConfiguration data = quester.getBaseData(); try { data.save(new File(directoryPath + File.separator + quester.getUUID() + ".yml")); @@ -395,11 +393,11 @@ public class SeparatedYamlStorage implements StorageImplementation { @Override public String getQuesterLastKnownName(final UUID uniqueId) throws Exception { - Quester quester = plugin.getQuester(uniqueId); + BukkitQuester quester = plugin.getQuester(uniqueId); if (quester != null) { quester.hardClear(); } else { - quester = new Quester(plugin, uniqueId); + quester = new BukkitQuester(plugin, uniqueId); } return quester.getLastKnownName(); } @@ -436,7 +434,7 @@ public class SeparatedYamlStorage implements StorageImplementation { * * @return file if exists, otherwise null */ - public File getDataFile(final Quester quester) { + public File getDataFile(final BukkitQuester quester) { File dataFile = new File(plugin.getDataFolder(), "data" + File.separator + quester.getUUID().toString() + ".yml"); if (!dataFile.exists()) { final OfflinePlayer p = quester.getOfflinePlayer(); diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java b/core/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java similarity index 91% rename from api/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java index ebc87ac56..8a0db535b 100644 --- a/api/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java +++ b/core/src/main/java/me/blackvein/quests/storage/implementation/sql/SqlStorage.java @@ -12,9 +12,9 @@ package me.blackvein.quests.storage.implementation.sql; -import me.blackvein.quests.Quest; +import me.blackvein.quests.quests.BukkitQuest; import me.blackvein.quests.QuestData; -import me.blackvein.quests.Quester; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; import me.blackvein.quests.storage.implementation.StorageImplementation; import me.blackvein.quests.storage.implementation.sql.connection.ConnectionFactory; @@ -221,8 +221,8 @@ public class SqlStorage implements StorageImplementation { } @Override - public Quester loadQuester(final UUID uniqueId) throws Exception { - final Quester quester = plugin.getQuester(uniqueId); + public BukkitQuester loadQuester(final UUID uniqueId) throws Exception { + final BukkitQuester quester = plugin.getQuester(uniqueId); if (quester == null) { return null; } @@ -248,21 +248,21 @@ public class SqlStorage implements StorageImplementation { } @Override - public void saveQuester(final Quester quester) throws Exception { + public void saveQuester(final BukkitQuester quester) throws Exception { final UUID uniqueId = quester.getUUID(); final String lastKnownName = quester.getLastKnownName(); final String oldLastKnownName = getQuesterLastKnownName(uniqueId); - final Set currentQuests = quester.getCurrentQuests().keySet().stream().map(Quest::getId).collect(Collectors.toSet()); - final Set oldCurrentQuests = getQuesterCurrentQuests(uniqueId).keySet().stream().map(Quest::getId).collect(Collectors.toSet()); + final Set currentQuests = quester.getCurrentQuests().keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); + final Set oldCurrentQuests = getQuesterCurrentQuests(uniqueId).keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); oldCurrentQuests.removeAll(currentQuests); - final Set completedQuests = quester.getCompletedQuests().stream().map(Quest::getId).collect(Collectors.toSet()); - final Set oldCompletedQuests = getQuesterCompletedQuests(uniqueId).stream().map(Quest::getId).collect(Collectors.toSet()); + final Set completedQuests = quester.getCompletedQuests().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); + final Set oldCompletedQuests = getQuesterCompletedQuests(uniqueId).stream().map(BukkitQuest::getId).collect(Collectors.toSet()); oldCompletedQuests.removeAll(completedQuests); - final Set redoableQuests = quester.getCompletedTimes().keySet().stream().map(Quest::getId).collect(Collectors.toSet()); - final Set oldRedoableQuests = getQuesterCompletedTimes(uniqueId).keySet().stream().map(Quest::getId).collect(Collectors.toSet()); + final Set redoableQuests = quester.getCompletedTimes().keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); + final Set oldRedoableQuests = getQuesterCompletedTimes(uniqueId).keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); oldRedoableQuests.removeAll(redoableQuests); - final Set questData = quester.getQuestData().keySet().stream().map(Quest::getId).collect(Collectors.toSet()); - final Set oldQuestData = getQuesterQuestData(uniqueId).keySet().stream().map(Quest::getId).collect(Collectors.toSet()); + final Set questData = quester.getQuestData().keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); + final Set oldQuestData = getQuesterQuestData(uniqueId).keySet().stream().map(BukkitQuest::getId).collect(Collectors.toSet()); oldQuestData.removeAll(questData); try (final Connection c = connectionFactory.getConnection()) { @@ -290,7 +290,7 @@ public class SqlStorage implements StorageImplementation { } } } else { - for (final Entry entry : quester.getCurrentQuests().entrySet()) { + for (final Entry entry : quester.getCurrentQuests().entrySet()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_CURRENT_QUESTS_INSERT))) { ps.setString(1, uniqueId.toString()); ps.setString(2, entry.getKey().getId()); @@ -309,7 +309,7 @@ public class SqlStorage implements StorageImplementation { } } } else { - for (final Quest quest : quester.getCompletedQuests()) { + for (final BukkitQuest quest : quester.getCompletedQuests()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_COMPLETED_QUESTS_INSERT))) { ps.setString(1, uniqueId.toString()); ps.setString(2, quest.getId()); @@ -327,7 +327,7 @@ public class SqlStorage implements StorageImplementation { } } } else { - for (final Entry entry : quester.getCompletedTimes().entrySet()) { + for (final Entry entry : quester.getCompletedTimes().entrySet()) { final int amount = quester.getAmountsCompleted().get(entry.getKey()); try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_REDOABLE_QUESTS_INSERT))) { ps.setString(1, uniqueId.toString()); @@ -348,7 +348,7 @@ public class SqlStorage implements StorageImplementation { } } } else { - for (final Entry entry : quester.getQuestData().entrySet()) { + for (final Entry entry : quester.getQuestData().entrySet()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_QUEST_DATA_INSERT))) { ps.setString(1, uniqueId.toString()); ps.setString(2, entry.getKey().getId()); @@ -424,14 +424,14 @@ public class SqlStorage implements StorageImplementation { return null; } - public ConcurrentHashMap getQuesterCurrentQuests(final UUID uniqueId) throws Exception { - final ConcurrentHashMap currentQuests = new ConcurrentHashMap<>(); + public ConcurrentHashMap getQuesterCurrentQuests(final UUID uniqueId) throws Exception { + final ConcurrentHashMap currentQuests = new ConcurrentHashMap<>(); try (final Connection c = connectionFactory.getConnection()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_CURRENT_QUESTS_SELECT_BY_UUID))) { ps.setString(1, uniqueId.toString()); try (final ResultSet rs = ps.executeQuery()) { while (rs.next()) { - final Quest quest = plugin.getQuestById(rs.getString("questid")); + final BukkitQuest quest = plugin.getQuestById(rs.getString("questid")); if (quest != null) { currentQuests.put(quest, rs.getInt("stageNum")); } @@ -442,15 +442,15 @@ public class SqlStorage implements StorageImplementation { return currentQuests; } - public ConcurrentHashMap getQuesterQuestData(final UUID uniqueId) throws Exception { - final Quester quester = plugin.getQuester(uniqueId); - final ConcurrentHashMap questData = new ConcurrentHashMap<>(); + public ConcurrentHashMap getQuesterQuestData(final UUID uniqueId) throws Exception { + final BukkitQuester quester = plugin.getQuester(uniqueId); + final ConcurrentHashMap questData = new ConcurrentHashMap<>(); try (final Connection c = connectionFactory.getConnection()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_QUEST_DATA_SELECT_BY_UUID))) { ps.setString(1, uniqueId.toString()); try (final ResultSet rs = ps.executeQuery()) { while (rs.next()) { - final Quest quest = plugin.getQuestById(rs.getString("quest_id")); + final BukkitQuest quest = plugin.getQuestById(rs.getString("quest_id")); final QuestData data = new QuestData(quester); if (quest != null && quester.getCurrentStage(quest) != null) { data.blocksBroken.addAll(deserializeItemStackProgress(rs.getString("blocks_broken"), @@ -497,14 +497,14 @@ public class SqlStorage implements StorageImplementation { return questData; } - public ConcurrentSkipListSet getQuesterCompletedQuests(final UUID uniqueId) throws Exception { - final ConcurrentSkipListSet completedQuests = new ConcurrentSkipListSet<>(); + public ConcurrentSkipListSet getQuesterCompletedQuests(final UUID uniqueId) throws Exception { + final ConcurrentSkipListSet completedQuests = new ConcurrentSkipListSet<>(); try (final Connection c = connectionFactory.getConnection()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_COMPLETED_QUESTS_SELECT_BY_UUID))) { ps.setString(1, uniqueId.toString()); try (final ResultSet rs = ps.executeQuery()) { while (rs.next()) { - final Quest quest = plugin.getQuestById(rs.getString("questid")); + final BukkitQuest quest = plugin.getQuestById(rs.getString("questid")); if (quest != null) { completedQuests.add(quest); } @@ -515,14 +515,14 @@ public class SqlStorage implements StorageImplementation { return completedQuests; } - public ConcurrentHashMap getQuesterCompletedTimes(final UUID uniqueId) throws Exception { - final ConcurrentHashMap completedTimes = new ConcurrentHashMap<>(); + public ConcurrentHashMap getQuesterCompletedTimes(final UUID uniqueId) throws Exception { + final ConcurrentHashMap completedTimes = new ConcurrentHashMap<>(); try (final Connection c = connectionFactory.getConnection()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_REDOABLE_QUESTS_SELECT_BY_UUID))) { ps.setString(1, uniqueId.toString()); try (final ResultSet rs = ps.executeQuery()) { while (rs.next()) { - final Quest quest = plugin.getQuestById(rs.getString("questid")); + final BukkitQuest quest = plugin.getQuestById(rs.getString("questid")); if (quest != null) { completedTimes.put(quest, rs.getLong("lasttime")); } @@ -533,14 +533,14 @@ public class SqlStorage implements StorageImplementation { return completedTimes; } - public ConcurrentHashMap getQuesterAmountsCompleted(final UUID uniqueId) throws Exception { - final ConcurrentHashMap amountsCompleted = new ConcurrentHashMap<>(); + public ConcurrentHashMap getQuesterAmountsCompleted(final UUID uniqueId) throws Exception { + final ConcurrentHashMap amountsCompleted = new ConcurrentHashMap<>(); try (final Connection c = connectionFactory.getConnection()) { try (final PreparedStatement ps = c.prepareStatement(statementProcessor.apply(PLAYER_REDOABLE_QUESTS_SELECT_BY_UUID))) { ps.setString(1, uniqueId.toString()); try (final ResultSet rs = ps.executeQuery()) { while (rs.next()) { - final Quest quest = plugin.getQuestById(rs.getString("questid")); + final BukkitQuest quest = plugin.getQuestById(rs.getString("questid")); if (quest != null) { amountsCompleted.put(quest, rs.getInt("amount")); } diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/ConnectionFactory.java b/core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/ConnectionFactory.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/ConnectionFactory.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/ConnectionFactory.java diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/HikariConnectionFactory.java b/core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/HikariConnectionFactory.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/HikariConnectionFactory.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/HikariConnectionFactory.java diff --git a/api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/MySqlConnectionFactory.java b/core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/MySqlConnectionFactory.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/MySqlConnectionFactory.java rename to core/src/main/java/me/blackvein/quests/storage/implementation/sql/connection/hikari/MySqlConnectionFactory.java diff --git a/api/src/main/java/me/blackvein/quests/storage/misc/StorageCredentials.java b/core/src/main/java/me/blackvein/quests/storage/misc/StorageCredentials.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/storage/misc/StorageCredentials.java rename to core/src/main/java/me/blackvein/quests/storage/misc/StorageCredentials.java diff --git a/api/src/main/java/me/blackvein/quests/tasks/ActionTimer.java b/core/src/main/java/me/blackvein/quests/tasks/ActionTimer.java similarity index 84% rename from api/src/main/java/me/blackvein/quests/tasks/ActionTimer.java rename to core/src/main/java/me/blackvein/quests/tasks/ActionTimer.java index c9636b822..d04a16a96 100644 --- a/api/src/main/java/me/blackvein/quests/tasks/ActionTimer.java +++ b/core/src/main/java/me/blackvein/quests/tasks/ActionTimer.java @@ -15,18 +15,18 @@ package me.blackvein.quests.tasks; import org.bukkit.ChatColor; import org.bukkit.scheduler.BukkitRunnable; -import me.blackvein.quests.Quest; -import me.blackvein.quests.Quester; +import me.blackvein.quests.quests.BukkitQuest; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.util.Lang; public class ActionTimer extends BukkitRunnable { - private final Quester quester; - private final Quest quest; + private final BukkitQuester quester; + private final BukkitQuest quest; private final int time; private final boolean last; - public ActionTimer(final Quester quester, final Quest quest, final int time, final boolean last) { + public ActionTimer(final BukkitQuester quester, final BukkitQuest quest, final int time, final boolean last) { this.quester = quester; this.quest = quest; this.time = time; diff --git a/api/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java b/core/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java similarity index 96% rename from api/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java rename to core/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java index 54f853315..a6291a6db 100644 --- a/api/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java +++ b/core/src/main/java/me/blackvein/quests/tasks/NpcEffectThread.java @@ -12,7 +12,7 @@ package me.blackvein.quests.tasks; -import me.blackvein.quests.Quester; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; import me.blackvein.quests.particle.ParticleProvider; import net.citizensnpcs.api.npc.NPC; @@ -33,7 +33,7 @@ public class NpcEffectThread implements Runnable { @Override public void run() { for (final Player player : plugin.getServer().getOnlinePlayers()) { - final Quester quester = plugin.getQuester(player.getUniqueId()); + final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); final List nearby = player.getNearbyEntities(32.0, 32.0, 32.0); if (!nearby.isEmpty()) { for (final Entity e : nearby) { diff --git a/api/src/main/java/me/blackvein/quests/tasks/PlayerMoveThread.java b/core/src/main/java/me/blackvein/quests/tasks/PlayerMoveThread.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/tasks/PlayerMoveThread.java rename to core/src/main/java/me/blackvein/quests/tasks/PlayerMoveThread.java diff --git a/api/src/main/java/me/blackvein/quests/tasks/StageTimer.java b/core/src/main/java/me/blackvein/quests/tasks/StageTimer.java similarity index 89% rename from api/src/main/java/me/blackvein/quests/tasks/StageTimer.java rename to core/src/main/java/me/blackvein/quests/tasks/StageTimer.java index 391049c8e..3295f99ab 100644 --- a/api/src/main/java/me/blackvein/quests/tasks/StageTimer.java +++ b/core/src/main/java/me/blackvein/quests/tasks/StageTimer.java @@ -12,17 +12,17 @@ package me.blackvein.quests.tasks; -import me.blackvein.quests.Quest; -import me.blackvein.quests.Quester; +import me.blackvein.quests.quests.BukkitQuest; +import me.blackvein.quests.player.BukkitQuester; import me.blackvein.quests.Quests; public class StageTimer implements Runnable { - private final Quester quester; + private final BukkitQuester quester; private final Quests plugin; - private final Quest quest; + private final BukkitQuest quest; - public StageTimer(final Quests plugin, final Quester quester, final Quest quest) { + public StageTimer(final Quests plugin, final BukkitQuester quester, final BukkitQuest quest) { this.quester = quester; this.quest = quest; this.plugin = plugin; diff --git a/api/src/main/java/me/blackvein/quests/util/CK.java b/core/src/main/java/me/blackvein/quests/util/CK.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/CK.java rename to core/src/main/java/me/blackvein/quests/util/CK.java diff --git a/api/src/main/java/me/blackvein/quests/util/ConfigUtil.java b/core/src/main/java/me/blackvein/quests/util/ConfigUtil.java similarity index 96% rename from api/src/main/java/me/blackvein/quests/util/ConfigUtil.java rename to core/src/main/java/me/blackvein/quests/util/ConfigUtil.java index 1326327e2..f27e8905a 100644 --- a/api/src/main/java/me/blackvein/quests/util/ConfigUtil.java +++ b/core/src/main/java/me/blackvein/quests/util/ConfigUtil.java @@ -13,7 +13,7 @@ package me.blackvein.quests.util; import me.blackvein.quests.Dependencies; -import me.blackvein.quests.Quest; +import me.blackvein.quests.quests.BukkitQuest; import me.clip.placeholderapi.PlaceholderAPI; import net.citizensnpcs.api.npc.NPC; import org.bukkit.Bukkit; @@ -100,7 +100,7 @@ public class ConfigUtil { + loc.getZ(); } - public static String[] parseStringWithPossibleLineBreaks(final String s, final Quest quest, final Player player) { + public static String[] parseStringWithPossibleLineBreaks(final String s, final BukkitQuest quest, final Player player) { String parsed = parseString(s); if (parsed.contains("")) { if (quest.getNpcStart() != null) { @@ -115,7 +115,7 @@ public class ConfigUtil { return parsed.split("\n"); } - public static String[] parseStringWithPossibleLineBreaks(final String s, final Quest quest) { + public static String[] parseStringWithPossibleLineBreaks(final String s, final BukkitQuest quest) { String parsed = parseString(s); if (parsed.contains("")) { if (quest.getNpcStart() != null) { @@ -135,7 +135,7 @@ public class ConfigUtil { return parsed.split("\n"); } - public static String parseString(final String s, final Quest quest) { + public static String parseString(final String s, final BukkitQuest quest) { String parsed = parseString(s); if (parsed.contains("")) { if (quest.getNpcStart() != null) { @@ -147,7 +147,7 @@ public class ConfigUtil { return parsed; } - public static String parseString(final String s, final Quest quest, final Player player) { + public static String parseString(final String s, final BukkitQuest quest, final Player player) { String parsed = parseString(s, quest); if (Dependencies.placeholder != null && player != null) { parsed = PlaceholderAPI.setPlaceholders(player, parsed); diff --git a/api/src/main/java/me/blackvein/quests/util/FakeConversable.java b/core/src/main/java/me/blackvein/quests/util/FakeConversable.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/FakeConversable.java rename to core/src/main/java/me/blackvein/quests/util/FakeConversable.java diff --git a/api/src/main/java/me/blackvein/quests/util/InventoryUtil.java b/core/src/main/java/me/blackvein/quests/util/InventoryUtil.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/InventoryUtil.java rename to core/src/main/java/me/blackvein/quests/util/InventoryUtil.java diff --git a/api/src/main/java/me/blackvein/quests/util/ItemUtil.java b/core/src/main/java/me/blackvein/quests/util/ItemUtil.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/ItemUtil.java rename to core/src/main/java/me/blackvein/quests/util/ItemUtil.java diff --git a/api/src/main/java/me/blackvein/quests/util/Lang.java b/core/src/main/java/me/blackvein/quests/util/Lang.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/Lang.java rename to core/src/main/java/me/blackvein/quests/util/Lang.java diff --git a/api/src/main/java/me/blackvein/quests/util/MiscUtil.java b/core/src/main/java/me/blackvein/quests/util/MiscUtil.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/MiscUtil.java rename to core/src/main/java/me/blackvein/quests/util/MiscUtil.java diff --git a/api/src/main/java/me/blackvein/quests/util/RomanNumeral.java b/core/src/main/java/me/blackvein/quests/util/RomanNumeral.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/RomanNumeral.java rename to core/src/main/java/me/blackvein/quests/util/RomanNumeral.java diff --git a/api/src/main/java/me/blackvein/quests/util/UpdateChecker.java b/core/src/main/java/me/blackvein/quests/util/UpdateChecker.java similarity index 100% rename from api/src/main/java/me/blackvein/quests/util/UpdateChecker.java rename to core/src/main/java/me/blackvein/quests/util/UpdateChecker.java diff --git a/api/src/main/resources/actions.yml b/core/src/main/resources/actions.yml similarity index 100% rename from api/src/main/resources/actions.yml rename to core/src/main/resources/actions.yml diff --git a/api/src/main/resources/conditions.yml b/core/src/main/resources/conditions.yml similarity index 100% rename from api/src/main/resources/conditions.yml rename to core/src/main/resources/conditions.yml diff --git a/api/src/main/resources/config.yml b/core/src/main/resources/config.yml similarity index 100% rename from api/src/main/resources/config.yml rename to core/src/main/resources/config.yml diff --git a/api/src/main/resources/lang/af-ZA/strings.yml b/core/src/main/resources/lang/af-ZA/strings.yml similarity index 100% rename from api/src/main/resources/lang/af-ZA/strings.yml rename to core/src/main/resources/lang/af-ZA/strings.yml diff --git a/api/src/main/resources/lang/ar-SA/strings.yml b/core/src/main/resources/lang/ar-SA/strings.yml similarity index 100% rename from api/src/main/resources/lang/ar-SA/strings.yml rename to core/src/main/resources/lang/ar-SA/strings.yml diff --git a/api/src/main/resources/lang/ca-ES/strings.yml b/core/src/main/resources/lang/ca-ES/strings.yml similarity index 100% rename from api/src/main/resources/lang/ca-ES/strings.yml rename to core/src/main/resources/lang/ca-ES/strings.yml diff --git a/api/src/main/resources/lang/cs-CZ/strings.yml b/core/src/main/resources/lang/cs-CZ/strings.yml similarity index 100% rename from api/src/main/resources/lang/cs-CZ/strings.yml rename to core/src/main/resources/lang/cs-CZ/strings.yml diff --git a/api/src/main/resources/lang/da-DK/strings.yml b/core/src/main/resources/lang/da-DK/strings.yml similarity index 100% rename from api/src/main/resources/lang/da-DK/strings.yml rename to core/src/main/resources/lang/da-DK/strings.yml diff --git a/api/src/main/resources/lang/de-DE/strings.yml b/core/src/main/resources/lang/de-DE/strings.yml similarity index 100% rename from api/src/main/resources/lang/de-DE/strings.yml rename to core/src/main/resources/lang/de-DE/strings.yml diff --git a/api/src/main/resources/lang/el-GR/strings.yml b/core/src/main/resources/lang/el-GR/strings.yml similarity index 100% rename from api/src/main/resources/lang/el-GR/strings.yml rename to core/src/main/resources/lang/el-GR/strings.yml diff --git a/api/src/main/resources/lang/en-PT/strings.yml b/core/src/main/resources/lang/en-PT/strings.yml similarity index 100% rename from api/src/main/resources/lang/en-PT/strings.yml rename to core/src/main/resources/lang/en-PT/strings.yml diff --git a/api/src/main/resources/lang/en-US/strings.yml b/core/src/main/resources/lang/en-US/strings.yml similarity index 100% rename from api/src/main/resources/lang/en-US/strings.yml rename to core/src/main/resources/lang/en-US/strings.yml diff --git a/api/src/main/resources/lang/es-ES/strings.yml b/core/src/main/resources/lang/es-ES/strings.yml similarity index 100% rename from api/src/main/resources/lang/es-ES/strings.yml rename to core/src/main/resources/lang/es-ES/strings.yml diff --git a/api/src/main/resources/lang/es-MX/strings.yml b/core/src/main/resources/lang/es-MX/strings.yml similarity index 100% rename from api/src/main/resources/lang/es-MX/strings.yml rename to core/src/main/resources/lang/es-MX/strings.yml diff --git a/api/src/main/resources/lang/et-EE/strings.yml b/core/src/main/resources/lang/et-EE/strings.yml similarity index 100% rename from api/src/main/resources/lang/et-EE/strings.yml rename to core/src/main/resources/lang/et-EE/strings.yml diff --git a/api/src/main/resources/lang/fi-FI/strings.yml b/core/src/main/resources/lang/fi-FI/strings.yml similarity index 100% rename from api/src/main/resources/lang/fi-FI/strings.yml rename to core/src/main/resources/lang/fi-FI/strings.yml diff --git a/api/src/main/resources/lang/fil-PH/strings.yml b/core/src/main/resources/lang/fil-PH/strings.yml similarity index 100% rename from api/src/main/resources/lang/fil-PH/strings.yml rename to core/src/main/resources/lang/fil-PH/strings.yml diff --git a/api/src/main/resources/lang/fr-FR/strings.yml b/core/src/main/resources/lang/fr-FR/strings.yml similarity index 100% rename from api/src/main/resources/lang/fr-FR/strings.yml rename to core/src/main/resources/lang/fr-FR/strings.yml diff --git a/api/src/main/resources/lang/he-IL/strings.yml b/core/src/main/resources/lang/he-IL/strings.yml similarity index 100% rename from api/src/main/resources/lang/he-IL/strings.yml rename to core/src/main/resources/lang/he-IL/strings.yml diff --git a/api/src/main/resources/lang/hi-IN/strings.yml b/core/src/main/resources/lang/hi-IN/strings.yml similarity index 100% rename from api/src/main/resources/lang/hi-IN/strings.yml rename to core/src/main/resources/lang/hi-IN/strings.yml diff --git a/api/src/main/resources/lang/hr-HR/strings.yml b/core/src/main/resources/lang/hr-HR/strings.yml similarity index 100% rename from api/src/main/resources/lang/hr-HR/strings.yml rename to core/src/main/resources/lang/hr-HR/strings.yml diff --git a/api/src/main/resources/lang/hu-HU/strings.yml b/core/src/main/resources/lang/hu-HU/strings.yml similarity index 100% rename from api/src/main/resources/lang/hu-HU/strings.yml rename to core/src/main/resources/lang/hu-HU/strings.yml diff --git a/api/src/main/resources/lang/id-ID/strings.yml b/core/src/main/resources/lang/id-ID/strings.yml similarity index 100% rename from api/src/main/resources/lang/id-ID/strings.yml rename to core/src/main/resources/lang/id-ID/strings.yml diff --git a/api/src/main/resources/lang/it-IT/strings.yml b/core/src/main/resources/lang/it-IT/strings.yml similarity index 100% rename from api/src/main/resources/lang/it-IT/strings.yml rename to core/src/main/resources/lang/it-IT/strings.yml diff --git a/api/src/main/resources/lang/ja-JP/strings.yml b/core/src/main/resources/lang/ja-JP/strings.yml similarity index 100% rename from api/src/main/resources/lang/ja-JP/strings.yml rename to core/src/main/resources/lang/ja-JP/strings.yml diff --git a/api/src/main/resources/lang/ko-KR/strings.yml b/core/src/main/resources/lang/ko-KR/strings.yml similarity index 100% rename from api/src/main/resources/lang/ko-KR/strings.yml rename to core/src/main/resources/lang/ko-KR/strings.yml diff --git a/api/src/main/resources/lang/lol-US/strings.yml b/core/src/main/resources/lang/lol-US/strings.yml similarity index 100% rename from api/src/main/resources/lang/lol-US/strings.yml rename to core/src/main/resources/lang/lol-US/strings.yml diff --git a/api/src/main/resources/lang/nb-NO/strings.yml b/core/src/main/resources/lang/nb-NO/strings.yml similarity index 100% rename from api/src/main/resources/lang/nb-NO/strings.yml rename to core/src/main/resources/lang/nb-NO/strings.yml diff --git a/api/src/main/resources/lang/nl-NL/strings.yml b/core/src/main/resources/lang/nl-NL/strings.yml similarity index 100% rename from api/src/main/resources/lang/nl-NL/strings.yml rename to core/src/main/resources/lang/nl-NL/strings.yml diff --git a/api/src/main/resources/lang/no-NO/strings.yml b/core/src/main/resources/lang/no-NO/strings.yml similarity index 100% rename from api/src/main/resources/lang/no-NO/strings.yml rename to core/src/main/resources/lang/no-NO/strings.yml diff --git a/api/src/main/resources/lang/pl-PL/strings.yml b/core/src/main/resources/lang/pl-PL/strings.yml similarity index 100% rename from api/src/main/resources/lang/pl-PL/strings.yml rename to core/src/main/resources/lang/pl-PL/strings.yml diff --git a/api/src/main/resources/lang/pt-BR/strings.yml b/core/src/main/resources/lang/pt-BR/strings.yml similarity index 100% rename from api/src/main/resources/lang/pt-BR/strings.yml rename to core/src/main/resources/lang/pt-BR/strings.yml diff --git a/api/src/main/resources/lang/pt-PT/strings.yml b/core/src/main/resources/lang/pt-PT/strings.yml similarity index 100% rename from api/src/main/resources/lang/pt-PT/strings.yml rename to core/src/main/resources/lang/pt-PT/strings.yml diff --git a/api/src/main/resources/lang/ro-RO/strings.yml b/core/src/main/resources/lang/ro-RO/strings.yml similarity index 100% rename from api/src/main/resources/lang/ro-RO/strings.yml rename to core/src/main/resources/lang/ro-RO/strings.yml diff --git a/api/src/main/resources/lang/ru-RU/strings.yml b/core/src/main/resources/lang/ru-RU/strings.yml similarity index 100% rename from api/src/main/resources/lang/ru-RU/strings.yml rename to core/src/main/resources/lang/ru-RU/strings.yml diff --git a/api/src/main/resources/lang/si-LK/strings.yml b/core/src/main/resources/lang/si-LK/strings.yml similarity index 100% rename from api/src/main/resources/lang/si-LK/strings.yml rename to core/src/main/resources/lang/si-LK/strings.yml diff --git a/api/src/main/resources/lang/sr-CS/strings.yml b/core/src/main/resources/lang/sr-CS/strings.yml similarity index 100% rename from api/src/main/resources/lang/sr-CS/strings.yml rename to core/src/main/resources/lang/sr-CS/strings.yml diff --git a/api/src/main/resources/lang/sr-SP/strings.yml b/core/src/main/resources/lang/sr-SP/strings.yml similarity index 100% rename from api/src/main/resources/lang/sr-SP/strings.yml rename to core/src/main/resources/lang/sr-SP/strings.yml diff --git a/api/src/main/resources/lang/sv-SE/strings.yml b/core/src/main/resources/lang/sv-SE/strings.yml similarity index 100% rename from api/src/main/resources/lang/sv-SE/strings.yml rename to core/src/main/resources/lang/sv-SE/strings.yml diff --git a/api/src/main/resources/lang/th-TH/strings.yml b/core/src/main/resources/lang/th-TH/strings.yml similarity index 100% rename from api/src/main/resources/lang/th-TH/strings.yml rename to core/src/main/resources/lang/th-TH/strings.yml diff --git a/api/src/main/resources/lang/tr-TR/strings.yml b/core/src/main/resources/lang/tr-TR/strings.yml similarity index 100% rename from api/src/main/resources/lang/tr-TR/strings.yml rename to core/src/main/resources/lang/tr-TR/strings.yml diff --git a/api/src/main/resources/lang/uk-UA/strings.yml b/core/src/main/resources/lang/uk-UA/strings.yml similarity index 100% rename from api/src/main/resources/lang/uk-UA/strings.yml rename to core/src/main/resources/lang/uk-UA/strings.yml diff --git a/api/src/main/resources/lang/vi-VN/strings.yml b/core/src/main/resources/lang/vi-VN/strings.yml similarity index 100% rename from api/src/main/resources/lang/vi-VN/strings.yml rename to core/src/main/resources/lang/vi-VN/strings.yml diff --git a/api/src/main/resources/lang/zh-CN/strings.yml b/core/src/main/resources/lang/zh-CN/strings.yml similarity index 100% rename from api/src/main/resources/lang/zh-CN/strings.yml rename to core/src/main/resources/lang/zh-CN/strings.yml diff --git a/api/src/main/resources/lang/zh-TW/strings.yml b/core/src/main/resources/lang/zh-TW/strings.yml similarity index 100% rename from api/src/main/resources/lang/zh-TW/strings.yml rename to core/src/main/resources/lang/zh-TW/strings.yml diff --git a/api/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml similarity index 100% rename from api/src/main/resources/plugin.yml rename to core/src/main/resources/plugin.yml diff --git a/api/src/main/resources/quests.yml b/core/src/main/resources/quests.yml similarity index 100% rename from api/src/main/resources/quests.yml rename to core/src/main/resources/quests.yml diff --git a/api/src/main/resources/strings.yml b/core/src/main/resources/strings.yml similarity index 100% rename from api/src/main/resources/strings.yml rename to core/src/main/resources/strings.yml diff --git a/dist/pom.xml b/dist/pom.xml index 34945e8a6..2c03e2449 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -5,7 +5,7 @@ me.blackvein.quests quests-parent - 4.1.3 + 4.2.0 quests-dist pom @@ -65,5 +65,10 @@ quests-v1_8_R1 ${revision} + + me.blackvein.quests + quests-core + ${revision} + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 950869423..857257522 100644 --- a/pom.xml +++ b/pom.xml @@ -6,12 +6,12 @@ me.blackvein.quests quests-parent - 4.1.3 + 4.2.0 quests https://github.com/PikaMug/Quests/ - 4.1.3 + 4.2.0 UTF-8 1.8 1.8 @@ -25,6 +25,7 @@ v1_8_R1 v1_8_R2 v1_8_R3 + core dist diff --git a/v1_8_R1/pom.xml b/v1_8_R1/pom.xml index 980ab8123..75b9cecac 100644 --- a/v1_8_R1/pom.xml +++ b/v1_8_R1/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -5,7 +6,7 @@ me.blackvein.quests quests-parent - 4.1.3 + 4.2.0 diff --git a/v1_8_R2/pom.xml b/v1_8_R2/pom.xml index a761f1793..31c622086 100644 --- a/v1_8_R2/pom.xml +++ b/v1_8_R2/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -5,7 +6,7 @@ me.blackvein.quests quests-parent - 4.1.3 + 4.2.0 diff --git a/v1_8_R3/pom.xml b/v1_8_R3/pom.xml index e28b71928..73cb11b4a 100644 --- a/v1_8_R3/pom.xml +++ b/v1_8_R3/pom.xml @@ -1,3 +1,4 @@ + 4.0.0 @@ -5,7 +6,7 @@ me.blackvein.quests quests-parent - 4.1.3 + 4.2.0