diff --git a/pom.xml b/pom.xml index f88cadbb4..c62c118e3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ me.blackvein.quests quests - 2.9.6 + 2.10.0 quests https://github.com/FlyingPikachu/Quests/ jar diff --git a/src/main/java/me/blackvein/quests/Event.java b/src/main/java/me/blackvein/quests/Event.java index 584d7f085..7185f27d9 100644 --- a/src/main/java/me/blackvein/quests/Event.java +++ b/src/main/java/me/blackvein/quests/Event.java @@ -21,6 +21,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import me.blackvein.quests.util.ItemUtil; +import me.blackvein.quests.util.Lang; import me.blackvein.quests.util.QuestMob; public class Event { @@ -37,6 +38,8 @@ public class Event { int stormDuration = 0; World thunderWorld = null; int thunderDuration = 0; + Integer timer = 0; + Boolean cancelTimer = false; public LinkedList mobSpawns = new LinkedList() { private static final long serialVersionUID = -761974607799449780L; @@ -66,6 +69,10 @@ public class Event { float health = -1; Location teleport; + public Event(final Quests plugin) { + this.plugin = plugin; + } + public int hashCode() { assert false : "hashCode not designed"; return 42; // any arbitrary constant will do @@ -232,13 +239,58 @@ public class Event { if (failQuest == true) { quest.failQuest(quester); } + if (timer > 0) { + player.sendMessage(Quests.parseString(String.format(Lang.get("timerStart"), timer), quest)); + if (timer > 60) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 60, false) + .runTaskLaterAsynchronously(plugin, (timer-60)*20).getTaskId(), quest); + } + if (timer > 30) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 30, false) + .runTaskLaterAsynchronously(plugin, (timer-30)*20).getTaskId(), quest); + } + if (timer > 10) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 10, false) + .runTaskLaterAsynchronously(plugin, (timer-10)*20).getTaskId(), quest); + } + if (timer > 5) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 5, false) + .runTaskLaterAsynchronously(plugin, (timer-5)*20).getTaskId(), quest); + } + if (timer > 4) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 4, false) + .runTaskLaterAsynchronously(plugin, (timer-4)*20).getTaskId(), quest); + } + if (timer > 3) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 3, false) + .runTaskLaterAsynchronously(plugin, (timer-3)*20).getTaskId(), quest); + } + if (timer > 2) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 2, false) + .runTaskLaterAsynchronously(plugin, (timer-2)*20).getTaskId(), quest); + } + if (timer > 1) { + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 1, false) + .runTaskLaterAsynchronously(plugin, (timer-1)*20).getTaskId(), quest); + } + quester.timers.put(new ObjectiveTimer(plugin, quester, quest, 0, true) + .runTaskLaterAsynchronously(plugin, timer*20).getTaskId(), quest); + } + if (cancelTimer) { + for (Map.Entry entry : quester.timers.entrySet()) { + if (entry.getValue().getName().equals(quest.getName())) { + plugin.getServer().getScheduler().cancelTask(entry.getKey()); + quester.timers.remove(entry.getKey()); + } + } + } } public static Event loadEvent(String name, Quests plugin) { if (name == null || plugin == null) { return null; } - Event event = new Event(); + Event event = new Event(plugin); FileConfiguration data = new YamlConfiguration(); try { data.load(new File(plugin.getDataFolder(), "events.yml")); @@ -513,6 +565,22 @@ public class Event { return null; } } + if (data.contains(eventKey + "timer")) { + if (data.isInt(eventKey + "timer")) { + event.timer = data.getInt(eventKey + "timer"); + } else { + plugin.getLogger().severe(ChatColor.GOLD + "[Quests] " + ChatColor.RED + "timer: " + ChatColor.GOLD + "inside Event " + ChatColor.DARK_PURPLE + name + ChatColor.GOLD + " is not a number!"); + return null; + } + } + if (data.contains(eventKey + "cancel-timer")) { + if (data.isBoolean(eventKey + "cancel-timer")) { + event.cancelTimer = data.getBoolean(eventKey + "cancel-timer"); + } else { + plugin.getLogger().severe(ChatColor.GOLD + "[Quests] " + ChatColor.RED + "cancel-timer: " + ChatColor.GOLD + "inside Event " + ChatColor.DARK_PURPLE + name + ChatColor.GOLD + " is not a boolean!"); + return null; + } + } return event; } } diff --git a/src/main/java/me/blackvein/quests/EventFactory.java b/src/main/java/me/blackvein/quests/EventFactory.java index 7b89f2f35..68f121b3e 100644 --- a/src/main/java/me/blackvein/quests/EventFactory.java +++ b/src/main/java/me/blackvein/quests/EventFactory.java @@ -163,6 +163,8 @@ public class EventFactory implements ConversationAbandonedListener { context.setSessionData(CK.E_HEALTH, null); context.setSessionData(CK.E_TELEPORT, null); context.setSessionData(CK.E_COMMANDS, null); + context.setSessionData(CK.E_TIMER, null); + context.setSessionData(CK.E_CANCEL_TIMER, null); } public static void loadData(Event event, ConversationContext context) { @@ -251,6 +253,12 @@ public class EventFactory implements ConversationAbandonedListener { if (event.commands != null) { context.setSessionData(CK.E_COMMANDS, event.commands); } + if (event.timer > 0) { + context.setSessionData(CK.E_TIMER, event.timer); + } + if (event.cancelTimer) { + context.setSessionData(CK.E_CANCEL_TIMER, true); + } } private class SelectEditPrompt extends StringPrompt { @@ -358,7 +366,7 @@ public class EventFactory implements ConversationAbandonedListener { private class CreateMenuPrompt extends FixedSetPrompt { public CreateMenuPrompt() { - super("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"); + super("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21"); } @SuppressWarnings("unchecked") @@ -477,8 +485,17 @@ public class EventFactory implements ConversationAbandonedListener { text += ChatColor.GRAY + " - " + ChatColor.AQUA + s + "\n"; } } - text += ChatColor.GREEN + "" + ChatColor.BOLD + "18" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("done") + "\n"; - text += ChatColor.RED + "" + ChatColor.BOLD + "19" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("quit"); + if (context.getSessionData(CK.E_TIMER) == null) { + text += ChatColor.BLUE + "" + ChatColor.BOLD + "18" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("eventEditorSetTimer") + ChatColor.GRAY + " (" + Lang.get("noneSet") + ")\n"; + } else { + text += ChatColor.BLUE + "" + ChatColor.BOLD + "18" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("eventEditorSetTimer") + "(" + ChatColor.AQUA + "\"" + context.getSessionData(CK.E_TIMER) + "\"" + ChatColor.YELLOW + ")\n"; + } + if (context.getSessionData(CK.E_CANCEL_TIMER) == null) { + context.setSessionData(CK.E_CANCEL_TIMER, "No"); + } + text += ChatColor.BLUE + "" + ChatColor.BOLD + "19" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("eventEditorCancelTimer") + ": " + ChatColor.AQUA + context.getSessionData(CK.E_CANCEL_TIMER) + "\n"; + text += ChatColor.GREEN + "" + ChatColor.BOLD + "20" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("done") + "\n"; + text += ChatColor.RED + "" + ChatColor.BOLD + "21" + ChatColor.RESET + ChatColor.YELLOW + " - " + Lang.get("quit"); return text; } @@ -534,18 +551,42 @@ public class EventFactory implements ConversationAbandonedListener { } else if (input.equalsIgnoreCase("17")) { return new CommandsPrompt(); } else if (input.equalsIgnoreCase("18")) { + return new TimerPrompt(); + } else if (input.equalsIgnoreCase("19")) { + String s = (String) context.getSessionData(CK.E_CANCEL_TIMER); + if (s.equalsIgnoreCase(Lang.get("yesWord"))) { + context.setSessionData(CK.E_CANCEL_TIMER, Lang.get("noWord")); + } else { + context.setSessionData(CK.E_CANCEL_TIMER, Lang.get("yesWord")); + } + return new CreateMenuPrompt(); + } else if (input.equalsIgnoreCase("20")) { if (context.getSessionData(CK.E_OLD_EVENT) != null) { return new FinishPrompt((String) context.getSessionData(CK.E_OLD_EVENT)); } else { return new FinishPrompt(null); } - } else if (input.equalsIgnoreCase("19")) { + } else if (input.equalsIgnoreCase("21")) { return new QuitPrompt(); } return null; } } + private class TimerPrompt extends NumericPrompt { + + @Override + protected Prompt acceptValidatedInput(final ConversationContext context, final Number number) { + context.setSessionData(CK.E_TIMER, number); + return new CreateMenuPrompt(); + } + + @Override + public String getPromptText(final ConversationContext conversationContext) { + return ChatColor.YELLOW + Lang.get("eventEditorEnterTimerSeconds"); + } + } + private class QuitPrompt extends StringPrompt { @Override @@ -821,6 +862,15 @@ public class EventFactory implements ConversationAbandonedListener { if (context.getSessionData(CK.E_TELEPORT) != null) { section.set("teleport-location", getCString(context, CK.E_TELEPORT)); } + if (context.getSessionData(CK.E_TIMER) != null && (int) context.getSessionData(CK.E_TIMER) > 0) { + section.set("timer", getCInt(context, CK.E_TIMER)); + } + if (context.getSessionData(CK.E_CANCEL_TIMER) != null) { + String s = getCString(context, CK.E_CANCEL_TIMER); + if (s.equalsIgnoreCase(Lang.get("yesWord"))) { + section.set("cancel-timer", true); + } + } try { data.save(eventsFile); } catch (IOException e) { diff --git a/src/main/java/me/blackvein/quests/ObjectiveTimer.java b/src/main/java/me/blackvein/quests/ObjectiveTimer.java new file mode 100644 index 000000000..b4c86b6e1 --- /dev/null +++ b/src/main/java/me/blackvein/quests/ObjectiveTimer.java @@ -0,0 +1,33 @@ +package me.blackvein.quests; + +import org.bukkit.scheduler.BukkitRunnable; + +import me.blackvein.quests.util.Lang; + +public class ObjectiveTimer extends BukkitRunnable { + + Quester quester; + Quests plugin; + Quest quest; + private int time; + private boolean last; + + ObjectiveTimer(Quests plugin, Quester quester, Quest quest, int time, boolean last) { + this.quester = quester; + this.quest = quest; + this.plugin = plugin; + this.time = time; + this.last = last; + } + + @Override + public void run() { + quester.timers.remove(getTaskId()); + if (last) { + quest.failQuest(quester); + quester.updateJournal(); + } else { + quester.getPlayer().sendMessage(Quests.parseString(String.format(Lang.get("timerMessage"), time), quest)); + } + } +} diff --git a/src/main/java/me/blackvein/quests/PlayerListener.java b/src/main/java/me/blackvein/quests/PlayerListener.java index e91c11196..661b75418 100644 --- a/src/main/java/me/blackvein/quests/PlayerListener.java +++ b/src/main/java/me/blackvein/quests/PlayerListener.java @@ -48,7 +48,6 @@ import org.bukkit.projectiles.ProjectileSource; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; - import me.blackvein.quests.util.ItemUtil; import me.blackvein.quests.util.Lang; import net.citizensnpcs.api.CitizensAPI; @@ -650,6 +649,12 @@ public class PlayerListener implements Listener { currentStage.disconnectEvent.fire(quester, quest); } } + quester.timers.keySet().forEach(timerId -> { + plugin.getServer().getScheduler().cancelTask(timerId); + quester.timers.get(timerId).failQuest(quester); + quester.timers.remove(timerId); + }); + if (quester.hasData()) { quester.saveData(); } diff --git a/src/main/java/me/blackvein/quests/Quest.java b/src/main/java/me/blackvein/quests/Quest.java index 3b28dae6c..66c62c587 100644 --- a/src/main/java/me/blackvein/quests/Quest.java +++ b/src/main/java/me/blackvein/quests/Quest.java @@ -100,6 +100,9 @@ public class Quest { completeQuest(q); } else { try { + if (q.getCurrentStage(this).finishEvent != null) { + q.getCurrentStage(this).finishEvent.fire(q, this); + } setStage(q, q.currentQuests.get(this) + 1); } catch (InvalidStageException e) { e.printStackTrace(); @@ -257,6 +260,12 @@ public class Quest { q.completedQuests.add(name); String none = ChatColor.GRAY + "- (" + Lang.get("none") + ")"; final String ps = Quests.parseString(finished, this); + for (Map.Entry entry : q.timers.entrySet()) { + if (entry.getValue().getName().equals(getName())) { + plugin.getServer().getScheduler().cancelTask(entry.getKey()); + q.timers.remove(entry.getKey()); + } + } org.bukkit.Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override diff --git a/src/main/java/me/blackvein/quests/Quester.java b/src/main/java/me/blackvein/quests/Quester.java index 75668fb2f..534afe92d 100644 --- a/src/main/java/me/blackvein/quests/Quester.java +++ b/src/main/java/me/blackvein/quests/Quester.java @@ -46,6 +46,7 @@ public class Quester { boolean editorMode = false; boolean hasJournal = false; public String questToTake; + public ConcurrentHashMap timers = new ConcurrentHashMap<>(); public Map currentQuests = new ConcurrentHashMap() { private static final long serialVersionUID = 6361484975823846780L; diff --git a/src/main/java/me/blackvein/quests/util/CK.java b/src/main/java/me/blackvein/quests/util/CK.java index 520883569..e1b510f1e 100644 --- a/src/main/java/me/blackvein/quests/util/CK.java +++ b/src/main/java/me/blackvein/quests/util/CK.java @@ -132,6 +132,8 @@ public class CK { public static final String E_HEALTH = "evtHealth"; public static final String E_TELEPORT = "evtTeleportLocation"; public static final String E_COMMANDS = "evtCommands"; + public static final String E_TIMER = "evtTimer"; + public static final String E_CANCEL_TIMER = "evtCancelTimer"; // Party public static final String P_INVITER = "inviter"; } \ No newline at end of file diff --git a/src/main/java/me/blackvein/quests/util/Lang.java b/src/main/java/me/blackvein/quests/util/Lang.java index ce7554706..ddf2969ee 100644 --- a/src/main/java/me/blackvein/quests/util/Lang.java +++ b/src/main/java/me/blackvein/quests/util/Lang.java @@ -433,6 +433,9 @@ public class Lang { langMap.put("eventEditorSetHunger", "Set player hunger level"); langMap.put("eventEditorSetSaturation", "Set player saturation level"); langMap.put("eventEditorSetHealth", "Set player health level"); + langMap.put("eventEditorEnterTimerSeconds", "Set number of seconds left before the quest fails (use cancel-timer event to cancel timers)"); + langMap.put("eventEditorSetTimer", "Set time to fail quest"); + langMap.put("eventEditorCancelTimer", "Cancel the quest timer"); langMap.put("eventEditorSetTeleport", "Set player teleport location"); langMap.put("eventEditorSetCommands", "Set commands to execute"); langMap.put("eventEditorItems", "Event Items"); @@ -944,6 +947,9 @@ public class Lang { langMap.put("valRequired", "Value required"); langMap.put("enchantedItem", "*Enchanted*"); langMap.put("experience", "Experience"); + // Timers + langMap.put("timerMessage", "Time left to finish the quest/stage: %s seconds"); + langMap.put("timerStart", "You have %s seconds to finish this quest/stage"); // // Error Messages langMap.put("questErrorReadingFile", "Error reading Quests file."); diff --git a/src/main/resources/events.yml b/src/main/resources/events.yml index 01b7fdfbe..319a2dafd 100644 --- a/src/main/resources/events.yml +++ b/src/main/resources/events.yml @@ -19,4 +19,8 @@ events: RodEvent: message: "Here you go!" items: - - name-fishing_rod:amount-1 \ No newline at end of file + - name-fishing_rod:amount-1 + TimerEvent: + timer: 40 + CancelTimer: + cancel-timer: true \ No newline at end of file diff --git a/src/main/resources/quests.yml b/src/main/resources/quests.yml index 29f9e6f91..e3dd39009 100644 --- a/src/main/resources/quests.yml +++ b/src/main/resources/quests.yml @@ -76,4 +76,65 @@ quests: - "rod" fish-to-catch: 5 rewards: - exp: 250 \ No newline at end of file + exp: 250 + + TimedQuest: + name: 'Timed Quest' + ask-message: 'This is timed quest, mine dirt before time runs out!' + finish-message: 'You did it in time!' + stages: + ordered: + '1': + break-block-names: + - DIRT + break-block-amounts: + - 10 + break-block-durability: + - 0 + start-event: TimerEvent + + TimedQuest2: + name: 'Timed Quest 2' + ask-message: 'This is timed quest 2, mine dirt and then grass before time runs out!' + finish-message: 'You did it in time!' + stages: + ordered: + '1': + break-block-names: + - DIRT + break-block-amounts: + - 10 + break-block-durability: + - 0 + start-event: TimerEvent + finish-event: CancelTimer + '2': + break-block-names: + - GRASS + break-block-amounts: + - 10 + break-block-durability: + - 0 + start-event: TimerEvent + + TimedQuest3: + name: 'Timed Quest 3' + ask-message: 'This is timed quest 3, mine dirt and then grass before time runs out!' + finish-message: 'You did it in time!' + stages: + ordered: + '1': + break-block-names: + - DIRT + break-block-amounts: + - 10 + break-block-durability: + - 0 + start-event: TimerEvent + '2': + break-block-names: + - GRASS + break-block-amounts: + - 10 + break-block-durability: + - 0 \ No newline at end of file