9
0
mirror of https://github.com/Auxilor/EcoQuests.git synced 2025-12-21 07:59:14 +00:00

Compare commits

...

118 Commits

Author SHA1 Message Date
Will FP
c86651df9b libreforge-updater 2024-09-22 17:00:59 +01:00
Will FP
26ccae38b1 Merge pull request #4 from Exanthiax/improved_sorting
improved sorting and multi-line descriptions
2024-09-22 15:47:35 +01:00
Exanthiax
c1c985d638 improved sorting and multi-line descriptions 2024-09-22 15:12:11 +01:00
Auxilor
5e51c369bb libreforge-updater 2024-09-02 11:30:14 +01:00
Auxilor
67a2e2fb4f libreforge-updater 2024-08-30 17:25:13 +01:00
Auxilor
f94e79bc92 libreforge-updater 2024-08-29 12:09:23 +01:00
Auxilor
9cf8d465b9 libreforge-updater 2024-08-23 15:35:29 +01:00
Auxilor
237ebda870 libreforge-updater 2024-08-21 18:58:25 +01:00
Auxilor
ed6bcaab04 libreforge-updater 2024-08-15 15:07:42 +01:00
Auxilor
40a0f99716 libreforge-updater 2024-08-03 13:41:32 +01:00
Auxilor
a59bce65ab libreforge-updater 2024-07-25 10:04:39 +01:00
Auxilor
0212076fad libreforge-updater 2024-07-21 12:19:23 +01:00
Auxilor
c4b0429ad5 libreforge-updater 2024-07-19 20:28:44 +01:00
Auxilor
c5e0611a20 libreforge-updater 2024-07-18 13:24:18 +01:00
Auxilor
cb2e8a181f libreforge-updater 2024-07-16 17:13:48 +01:00
Auxilor
c40a304c8a libreforge-updater 2024-07-13 20:45:24 +01:00
Auxilor
9e7a8a7581 libreforge-updater 2024-07-08 15:58:33 +01:00
Auxilor
2e5fbda6c2 libreforge-updater 2024-07-05 13:02:51 +01:00
Auxilor
908a4c5a14 libreforge-updater 2024-07-03 17:44:03 +01:00
Auxilor
ee38c05518 libreforge-updater 2024-06-29 16:44:07 +01:00
Auxilor
98d5431ba7 libreforge-updater 2024-06-28 15:56:30 +01:00
Auxilor
ff13678d33 libreforge-updater 2024-06-27 18:54:34 +01:00
Auxilor
8b955f3481 libreforge-updater 2024-06-26 16:52:26 +01:00
Auxilor
b6d8b4154b libreforge-updater 2024-06-25 15:14:05 +01:00
Auxilor
f71078f956 libreforge-updater 2024-06-24 15:06:40 +01:00
Auxilor
4e4f9c637b Updated to Java 21 2024-06-24 14:04:43 +01:00
Auxilor
2433c34a1c libreforge-updater 2024-06-23 17:26:37 +01:00
Auxilor
607da38533 libreforge-updater 2024-06-23 13:19:10 +01:00
Will FP
17d0af8ab9 libreforge-updater 2024-05-31 20:37:52 +01:00
Will FP
8332c5aa2a libreforge-updater 2024-05-11 18:21:18 +01:00
Will FP
863e741ac6 libreforge-updater 2024-04-17 20:35:00 +01:00
Auxilor
aab1a5bf44 libreforge-updater 2024-04-15 18:19:50 +01:00
Auxilor
93f243871f libreforge-updater 2024-04-11 13:17:45 +01:00
Auxilor
78e2b6bfff libreforge-updater 2024-03-29 16:08:51 +00:00
Will FP
4bf97077b7 libreforge-updater 2024-03-11 17:38:06 +00:00
Will FP
6eead2f420 libreforge-updater 2024-03-10 20:09:37 +00:00
Will FP
c574d78992 libreforge-updater 2024-03-02 15:20:52 +00:00
Will FP
399101a487 libreforge-updater 2024-02-22 13:18:23 +00:00
Will FP
95a013fbf1 Merge pull request #1 from MCCasper/master
t
2024-02-17 19:57:48 +00:00
Nikolai Connolly
b0fa4bad8b t 2024-02-16 20:52:30 -06:00
Will FP
d55635c590 libreforge-updater 2024-02-15 13:02:37 +00:00
Will FP
bd6b919f86 libreforge-updater 2024-02-08 19:49:56 +00:00
Will FP
d390a2102a libreforge-updater 2024-01-30 11:27:42 +00:00
Will FP
89e2232618 libreforge-updater 2024-01-18 17:03:23 +00:00
Will FP
db34794aa0 libreforge-updater 2024-01-16 13:29:19 +00:00
Will FP
b8a8076b23 libreforge-updater 2024-01-13 14:24:05 +00:00
Will FP
b999e381a1 libreforge-updater 2024-01-07 13:52:00 +00:00
Will FP
e726af326f libreforge-updater 2024-01-06 09:20:18 +00:00
Auxilor
9654b2c78b libreforge-updater 2024-01-04 17:25:37 +00:00
Auxilor
2645d679f5 libreforge-updater 2024-01-01 20:02:39 +00:00
Will FP
3851943ee4 libreforge-updater 2023-12-27 14:17:46 +01:00
Will FP
ee39a180e1 libreforge-updater 2023-12-24 14:54:57 +01:00
Auxilor
da5cb60399 libreforge-updater 2023-12-20 15:57:20 +00:00
Will FP
d25ba604c3 libreforge-updater 2023-12-14 16:13:50 +00:00
Will FP
5810b4a7a9 libreforge-updater 2023-12-11 12:13:05 +00:00
Will FP
2ab6a42b37 libreforge-updater 2023-12-07 17:26:01 +00:00
Will FP
b496848143 libreforge-updater 2023-12-03 15:59:50 +00:00
Will FP
274102ac06 libreforge-updater 2023-11-30 14:27:46 +00:00
Will FP
08ef85f6d0 libreforge-updater 2023-11-26 23:24:49 +00:00
Will FP
29d0f8200e libreforge-updater 2023-11-23 13:21:45 +00:00
Auxilor
6496d5c7d1 libreforge-updater 2023-11-21 22:41:42 +00:00
Auxilor
35c89d7aa5 libreforge-updater 2023-11-19 14:14:25 +00:00
Auxilor
ab99f74626 libreforge-updater 2023-11-17 19:02:33 +00:00
Auxilor
ecfa40920f libreforge-updater 2023-11-11 17:58:59 +00:00
Auxilor
202528681a libreforge-updater 2023-11-10 13:59:29 +00:00
Auxilor
7aa02b3a91 libreforge-updater 2023-11-05 13:42:08 +00:00
Auxilor
070d25de67 libreforge-updater 2023-10-30 13:31:07 +00:00
Auxilor
3ab99c9237 libreforge-updater 2023-10-28 14:15:35 +01:00
Auxilor
3ee10633fb libreforge-updater 2023-10-24 15:39:35 +01:00
Auxilor
49c77396ea libreforge-updater 2023-10-19 12:52:36 +01:00
Auxilor
09fb8d2109 libreforge-updater 2023-10-14 14:20:33 +01:00
Auxilor
9623f1c427 libreforge-updater 2023-10-14 14:19:14 +01:00
Auxilor
39eaef3856 libreforge-updater 2023-10-02 11:54:25 +01:00
Auxilor
bf085b4ea5 libreforge-updater 2023-09-26 14:46:03 +01:00
Auxilor
1a1433f84f libreforge-updater 2023-09-20 15:33:56 +01:00
Auxilor
571b4c05e2 Fixed a small amount of stupidity 2023-09-17 11:29:16 +01:00
Auxilor
58aa2fd81d graddel 2023-09-17 11:28:35 +01:00
Auxilor
335524a2da libreforge-updater 2023-09-17 11:20:21 +01:00
Auxilor
73d748d445 libreforge-updater 2023-09-13 15:08:56 +01:00
Auxilor
e0e0804cce libreforge-updater 2023-09-07 16:01:57 +01:00
Auxilor
c00d5eb7d2 libreforge-updater 2023-09-02 17:34:44 +01:00
Will FP
f7fab37555 Fixed page changers 2023-09-01 12:32:17 +01:00
Auxilor
a93aac6b6f libreforge-updater 2023-08-31 16:59:46 +01:00
Auxilor
025a74048a Added on-complete 2023-08-31 16:57:13 +01:00
Auxilor
9db9f542c9 libreforge-updater 2023-08-30 11:31:41 +01:00
Auxilor
75a091624c Dynamic experience requirements now lock in when a task starts 2023-08-30 11:09:09 +01:00
Auxilor
17c81ea5b8 Added use-local-storage 2023-08-30 09:50:00 +01:00
Auxilor
81d4faaf0c libreforge-updater 2023-08-26 18:11:44 +01:00
Auxilor
03110e36b1 libreforge-updater 2023-08-23 15:31:59 +01:00
Auxilor
4b687e2c00 libreforge-updater 2023-08-19 15:32:52 +01:00
Auxilor
c01c86a592 libreforge-updater 2023-08-15 18:52:36 +01:00
Auxilor
438b118846 libreforge-updater 2023-08-13 14:42:52 +01:00
Auxilor
9c6cd8f467 Updated to 1.0.1 2023-08-11 15:01:54 +01:00
Auxilor
1db9b48579 Fixed quests being allowed on lrcdb (tasks only) 2023-08-11 15:01:36 +01:00
Auxilor
6b7380decd Added polymart / bstats IDs 2023-08-10 19:53:34 +01:00
Auxilor
3ecc004a7f Added publishing block 2023-08-10 19:41:05 +01:00
Auxilor
252163ba46 Added .github 2023-08-10 19:39:12 +01:00
Auxilor
2a612e84fc Improved config.yml 2023-08-10 18:24:37 +01:00
Auxilor
c9af764714 Improvements 2023-08-10 18:20:30 +01:00
Auxilor
5455db9fda Updated to 1.0.0 2023-08-10 18:04:35 +01:00
Auxilor
3250d33f8e Clarified not-met-lines 2023-08-10 18:04:26 +01:00
Auxilor
c0528c2c81 Examples 2023-08-10 18:03:26 +01:00
Auxilor
eecbe696a6 Improved GUI 2023-08-10 17:59:41 +01:00
Auxilor
ba3bc524ae Added option to disable auto start 2023-08-10 17:58:22 +01:00
Auxilor
b98dd0c6e6 Fixed bug with GUYI 2023-08-10 17:47:59 +01:00
Auxilor
93cfb2911a Fixed 2023-08-10 17:45:32 +01:00
Auxilor
d89a50b33b Fixed 2023-08-10 17:40:53 +01:00
Auxilor
ebec6b0615 Added %ecoquests_recent_quest_name% and improved lore 2023-08-10 17:38:52 +01:00
Auxilor
3ca42cb6d8 Updated to 0.4.0 2023-08-10 17:01:08 +01:00
Auxilor
cc3e5af684 Added %time_since% placeholder 2023-08-10 17:00:25 +01:00
Auxilor
ddc2659c62 Added permissions for paper 2023-08-10 15:37:54 +01:00
Auxilor
406ff65a6d Cleanup more 2023-08-10 15:36:13 +01:00
Auxilor
e7a16550ac Added %ecoquests_quests_percent_completed% 2023-08-10 15:30:29 +01:00
Auxilor
63b19f130e Added quest_xp_multipleir 2023-08-10 15:27:29 +01:00
Auxilor
215e4556cb Cleanup 2023-08-10 15:23:43 +01:00
Auxilor
5eeb00c083 Improved APi 2023-08-10 15:11:39 +01:00
Auxilor
0a333853d8 Resettable tasks now save properly 2023-08-09 16:07:36 +01:00
Auxilor
dd454bd447 Fixed tasks, added task pool 2023-08-09 14:50:48 +01:00
46 changed files with 647 additions and 133 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @WillFP

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Discord
url: https://discord.gg/ZcwpSsE/
about: Issues have moved to Discord, please join the server to get help!

11
.github/ISSUE_TEMPLATE/report-a-bug.md vendored Normal file
View File

@@ -0,0 +1,11 @@
---
name: Report a Bug
about: Report an issue with the plugin
title: ''
labels: bug
assignees: ''
---
# Please report bugs on the discord!
[Join by clicking here](https://discord.gg/ZcwpSsE/)

33
.github/workflows/publish-release.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Publish Packages
on:
workflow_dispatch:
release:
types: [ created ]
push:
tags:
- '*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
- name: Set up JDK 21
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 21
- name: Change wrapper permissions
run: chmod +x ./gradlew
- name: Publish package
uses: gradle/gradle-build-action@v2
with:
arguments: publish
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}

View File

@@ -2,8 +2,8 @@ plugins {
java
`java-library`
`maven-publish`
kotlin("jvm") version "1.7.10"
id("com.github.johnrengelman.shadow") version "8.0.0"
kotlin("jvm") version "1.9.20"
id("io.github.goooler.shadow") version "8.1.7"
id("com.willfp.libreforge-gradle-plugin") version "1.0.0"
}
@@ -25,7 +25,7 @@ allprojects {
apply(plugin = "java")
apply(plugin = "kotlin")
apply(plugin = "maven-publish")
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "io.github.goooler.shadow")
repositories {
mavenLocal()
@@ -39,7 +39,7 @@ allprojects {
dependencies {
compileOnly("com.willfp:eco:6.65.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.7.10")
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
}
java {

View File

@@ -9,9 +9,23 @@ dependencies {
publishing {
publications {
register("maven", MavenPublication::class) {
from(components["java"])
register<MavenPublication>("maven") {
groupId = project.group.toString()
version = project.version.toString()
artifactId = rootProject.name
artifact(rootProject.tasks.shadowJar.get().archiveFile)
}
}
repositories {
maven {
name = "auxilor"
url = uri("https://repo.auxilor.io/repository/maven-releases/")
credentials {
username = System.getenv("MAVEN_USERNAME")
password = System.getenv("MAVEN_PASSWORD")
}
}
}
}

View File

@@ -1,8 +1,12 @@
package com.willfp.ecoquests
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.data.profile
import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.core.placeholder.templates.SimpleInjectablePlaceholder
import com.willfp.eco.util.toNiceString
import com.willfp.ecoquests.commands.CommandEcoQuests
import com.willfp.ecoquests.commands.CommandQuests
import com.willfp.ecoquests.gui.PreviousQuestsGUI
@@ -12,6 +16,7 @@ import com.willfp.ecoquests.libreforge.ConditionHasCompletedTask
import com.willfp.ecoquests.libreforge.ConditionHasQuestActive
import com.willfp.ecoquests.libreforge.EffectGainTaskXp
import com.willfp.ecoquests.libreforge.EffectGiveTaskXp
import com.willfp.ecoquests.libreforge.EffectQuestXpMultiplier
import com.willfp.ecoquests.libreforge.EffectStartQuest
import com.willfp.ecoquests.libreforge.FilterQuest
import com.willfp.ecoquests.libreforge.FilterTask
@@ -40,6 +45,7 @@ class EcoQuestsPlugin : LibreforgePlugin() {
Conditions.register(ConditionHasQuestActive)
Effects.register(EffectGainTaskXp)
Effects.register(EffectGiveTaskXp)
Effects.register(EffectQuestXpMultiplier)
Effects.register(EffectStartQuest)
Filters.register(FilterQuest)
Filters.register(FilterTask)
@@ -56,9 +62,20 @@ class EcoQuestsPlugin : LibreforgePlugin() {
Quests.getCompletedQuests(it).size.toString()
}.register()
PlayerPlaceholder(this, "quests_percent_completed") {
val completed = Quests.getCompletedQuests(it).size
val total = Quests.values().size
val percent = completed.toDouble() / total.toDouble() * 100.0
percent.toNiceString()
}.register()
PlayerPlaceholder(this, "quests_active") {
Quests.getActiveQuests(it).size.toString()
}.register()
PlayerPlaceholder(this, "recent_quest_name") {
Quests.getActiveQuests(it).minBy { quest -> quest.getTimeSinceStart(it) }.name
}.register()
}
override fun handleReload() {

View File

@@ -13,6 +13,7 @@ class CommandEcoQuests(plugin: EcoPlugin) : PluginCommand(
init {
this.addSubcommand(CommandReload(plugin))
.addSubcommand(CommandStart(plugin))
.addSubcommand(CommandResetPlayer(plugin))
.addSubcommand(CommandReset(plugin))
}

View File

@@ -3,8 +3,6 @@ package com.willfp.ecoquests.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecoquests.gui.QuestsGUI
import com.willfp.libreforge.commands.CommandReload
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
class CommandQuests(plugin: EcoPlugin) : PluginCommand(

View File

@@ -3,11 +3,8 @@ package com.willfp.ecoquests.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.util.StringUtils
import com.willfp.ecoquests.gui.QuestsGUI
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.commands.CommandReload
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandReset(plugin: EcoPlugin) : PluginCommand(
@@ -17,15 +14,21 @@ class CommandReset(plugin: EcoPlugin) : PluginCommand(
false
) {
override fun onExecute(sender: CommandSender, args: List<String>) {
val player = notifyPlayerRequired(args.getOrNull(0), "invalid-player")
val quest = notifyNull(Quests[args.getOrNull(1)], "invalid-quest")
val quest = notifyNull(Quests[args.getOrNull(0)], "invalid-quest")
quest.reset(player)
if (!quest.isResettable) {
sender.sendMessage(
plugin.langYml.getMessage("quest-not-resettable", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%quest%", quest.name)
)
return
}
quest.reset()
sender.sendMessage(
plugin.langYml.getMessage("reset-quest", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%quest%", quest.name)
.replace("%player%", player.name)
)
}
@@ -35,14 +38,6 @@ class CommandReset(plugin: EcoPlugin) : PluginCommand(
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
plugin.server.onlinePlayers.map { it.name },
completions
)
}
if (args.size == 2) {
StringUtil.copyPartialMatches(
args[1],
Quests.values().map { it.id },
completions
)

View File

@@ -0,0 +1,51 @@
package com.willfp.ecoquests.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.util.StringUtils
import com.willfp.ecoquests.quests.Quests
import org.bukkit.command.CommandSender
import org.bukkit.util.StringUtil
class CommandResetPlayer(plugin: EcoPlugin) : PluginCommand(
plugin,
"resetplayer",
"ecoquests.command.resetplayer",
false
) {
override fun onExecute(sender: CommandSender, args: List<String>) {
val player = notifyPlayerRequired(args.getOrNull(0), "invalid-player")
val quest = notifyNull(Quests[args.getOrNull(1)], "invalid-quest")
quest.reset(player)
sender.sendMessage(
plugin.langYml.getMessage("reset-quest-for-player", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%quest%", quest.name)
.replace("%player%", player.name)
)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
plugin.server.onlinePlayers.map { it.name },
completions
)
}
if (args.size == 2) {
StringUtil.copyPartialMatches(
args[1],
Quests.values().map { it.id },
completions
)
}
return completions
}
}

View File

@@ -3,11 +3,8 @@ package com.willfp.ecoquests.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.util.StringUtils
import com.willfp.ecoquests.gui.QuestsGUI
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.commands.CommandReload
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandStart(plugin: EcoPlugin) : PluginCommand(

View File

@@ -12,7 +12,7 @@ class PositionedPageChanger(
direction: PageChanger.Direction
): PositionedComponent {
private val pageChanger = PageChanger(
Items.lookup("item").item,
Items.lookup(config.getString("item")).item,
direction
)

View File

@@ -5,17 +5,21 @@ import com.willfp.eco.core.gui.onLeftClick
import com.willfp.eco.core.gui.slot
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.items.builder.modify
import com.willfp.eco.util.formatEco
import com.willfp.ecoquests.gui.PreviousQuestsGUI
class QuestInfoComponent(
config: Config
) : PositionedComponent {
private val slot = slot(
ItemStackBuilder(Items.lookup(config.getString("item")))
.setDisplayName(config.getFormattedString("name"))
.addLoreLines(config.getFormattedStrings("lore"))
.build()
) {
private val baseItem = Items.lookup(config.getString("item"))
private val slot = slot({ player, _ ->
baseItem.item.clone().modify {
setDisplayName(config.getString("name").formatEco(player, formatPlaceholders = true))
addLoreLines(config.getStrings("lore").formatEco(player, formatPlaceholders = true))
}
}) {
onLeftClick { player, _, _, _ ->
PreviousQuestsGUI.open(player)
}

View File

@@ -2,9 +2,12 @@ package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.get
import org.bukkit.entity.Player
object ConditionHasCompletedQuest : Condition<NoCompileData>("has_completed_quest") {
@@ -12,7 +15,14 @@ object ConditionHasCompletedQuest : Condition<NoCompileData>("has_completed_ques
require("quest", "You must specify the quest ID!")
}
override fun isMet(player: Player, config: Config, compileData: NoCompileData): Boolean {
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val player = dispatcher.get<Player>() ?: return false
val quest = Quests[config.getString("quest")] ?: return false
return quest.hasCompleted(player)

View File

@@ -3,18 +3,31 @@ package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoquests.quests.Quests
import com.willfp.ecoquests.tasks.Tasks
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.get
import org.bukkit.entity.Player
object ConditionHasCompletedTask : Condition<NoCompileData>("has_completed_task") {
override val arguments = arguments {
require("quest", "You must specify the quest ID!")
require("task", "You must specify the task ID!")
}
override fun isMet(player: Player, config: Config, compileData: NoCompileData): Boolean {
val task = Tasks[config.getString("task")] ?: return false
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val player = dispatcher.get<Player>() ?: return false
val quest = Quests[config.getString("quest")] ?: return false
val template = Tasks[config.getString("task")] ?: return false
val task = quest.getTask(template) ?: return false
return task.hasCompleted(player)
}

View File

@@ -2,9 +2,12 @@ package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.get
import org.bukkit.entity.Player
object ConditionHasQuestActive : Condition<NoCompileData>("has_quest_active") {
@@ -12,7 +15,14 @@ object ConditionHasQuestActive : Condition<NoCompileData>("has_quest_active") {
require("quest", "You must specify the quest ID!")
}
override fun isMet(player: Player, config: Config, compileData: NoCompileData): Boolean {
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val player = dispatcher.get<Player>() ?: return false
val quest = Quests[config.getString("quest")] ?: return false
return quest.hasActive(player)

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoquests.quests.Quests
import com.willfp.ecoquests.tasks.Tasks
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.arguments
@@ -17,13 +18,17 @@ object EffectGainTaskXp : Effect<NoCompileData>("gain_task_xp") {
override val arguments = arguments {
require("task", "You must specify the task ID!")
require("quest", "You must specify the quest ID!")
require("xp", "You must specify the amount of xp to gain!")
}
override fun onTrigger(config: Config, data: TriggerData, compileData: NoCompileData): Boolean {
val player = data.player ?: return false
val task = Tasks[config.getString("task")] ?: return false
val quest = Quests[config.getString("quest")] ?: return false
val template = Tasks[config.getString("task")] ?: return false
val task = quest.getTask(template) ?: return false
val xp = config.getDoubleFromExpression("xp", data)
task.gainExperience(player, xp)

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoquests.quests.Quests
import com.willfp.ecoquests.tasks.Tasks
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.arguments
@@ -17,13 +18,17 @@ object EffectGiveTaskXp : Effect<NoCompileData>("give_task_xp") {
override val arguments = arguments {
require("task", "You must specify the task ID!")
require("quest", "You must specify the quest ID!")
require("xp", "You must specify the amount of xp to give!")
}
override fun onTrigger(config: Config, data: TriggerData, compileData: NoCompileData): Boolean {
val player = data.player ?: return false
val task = Tasks[config.getString("task")] ?: return false
val quest = Quests[config.getString("quest")] ?: return false
val template = Tasks[config.getString("task")] ?: return false
val task = quest.getTask(template) ?: return false
val xp = config.getDoubleFromExpression("xp", data)
task.giveExperience(player, xp)

View File

@@ -0,0 +1,25 @@
package com.willfp.ecoquests.libreforge
import com.willfp.ecoquests.api.event.PlayerTaskExpGainEvent
import com.willfp.ecoquests.quests.Quest
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.effects.templates.MultiMultiplierEffect
import com.willfp.libreforge.toDispatcher
import org.bukkit.event.EventHandler
object EffectQuestXpMultiplier : MultiMultiplierEffect<Quest>("quest_xp_multiplier") {
override val key = "quests"
override fun getElement(key: String): Quest? {
return Quests[key]
}
override fun getAllElements(): Collection<Quest> {
return Quests.values()
}
@EventHandler(ignoreCancelled = true)
fun handle(event: PlayerTaskExpGainEvent) {
event.amount *= getMultiplier(event.player.toDispatcher(), event.quest)
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecoquests.api.event.QuestEvent
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.filters.Filter
@@ -14,8 +15,6 @@ object FilterQuest : Filter<NoCompileData, Collection<String>>("quest") {
override fun isMet(data: TriggerData, value: Collection<String>, compileData: NoCompileData): Boolean {
val event = data.event as? QuestEvent ?: return true
return value.any { questID ->
questID.equals(event.quest.id, ignoreCase = true)
}
return value.containsIgnoreCase(event.quest.id)
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecoquests.api.event.QuestEvent
import com.willfp.ecoquests.api.event.TaskEvent
import com.willfp.libreforge.NoCompileData
@@ -15,8 +16,6 @@ object FilterTask : Filter<NoCompileData, Collection<String>>("task") {
override fun isMet(data: TriggerData, value: Collection<String>, compileData: NoCompileData): Boolean {
val event = data.event as? TaskEvent ?: return true
return value.any { taskID ->
taskID.equals(event.task.id, ignoreCase = true)
}
return value.containsIgnoreCase(event.task.id)
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.ecoquests.libreforge
import com.willfp.ecoquests.api.event.PlayerQuestCompleteEvent
import com.willfp.ecoquests.api.event.PlayerQuestStartEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
@@ -18,7 +19,7 @@ object TriggerCompleteQuest : Trigger("complete_quest") {
val player = event.player
this.dispatch(
player,
player.toDispatcher(),
TriggerData(
player = player,
event = event

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.ecoquests.api.event.PlayerTaskCompleteEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
@@ -17,7 +18,7 @@ object TriggerCompleteTask : Trigger("complete_task") {
val player = event.player
this.dispatch(
player,
player.toDispatcher(),
TriggerData(
player = player,
event = event

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.ecoquests.api.event.PlayerTaskExpGainEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
@@ -19,7 +20,7 @@ object TriggerGainTaskXp : Trigger("gain_task_xp") {
val player = event.player
this.dispatch(
player,
player.toDispatcher(),
TriggerData(
player = player,
event = event,

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoquests.libreforge
import com.willfp.ecoquests.api.event.PlayerQuestStartEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
@@ -17,7 +18,7 @@ object TriggerStartQuest : Trigger("start_quest") {
val player = event.player
this.dispatch(
player,
player.toDispatcher(),
TriggerData(
player = player,
event = event

View File

@@ -14,20 +14,28 @@ import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
import com.willfp.eco.core.placeholder.context.placeholderContext
import com.willfp.eco.core.registry.KRegistrable
import com.willfp.eco.util.formatEco
import com.willfp.eco.util.lineWrap
import com.willfp.eco.util.toNiceString
import com.willfp.ecoquests.api.event.PlayerQuestCompleteEvent
import com.willfp.ecoquests.api.event.PlayerQuestStartEvent
import com.willfp.ecoquests.tasks.Task
import com.willfp.ecoquests.tasks.TaskTemplate
import com.willfp.ecoquests.tasks.Tasks
import com.willfp.ecoquests.util.formatDuration
import com.willfp.ecoquests.util.randomlyPick
import com.willfp.libreforge.EmptyProvidedHolder
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.effects.executors.impl.NormalExecutorFactory
import com.willfp.libreforge.toDispatcher
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
val currentTimeMinutes: Int
get() = (System.currentTimeMillis() / 1000 / 60).toInt()
class Quest(
private val plugin: EcoPlugin,
override val id: String,
@@ -37,6 +45,8 @@ class Quest(
val announcesStart = config.getBool("announce-start")
val autoStarts = config.getBool("auto-start")
private val guiItem = Items.lookup(config.getString("gui.item")).item
val slot = slot({ player, _ ->
@@ -49,7 +59,14 @@ class Quest(
)
addLoreLines(
startConditions.getNotMetLines(player, EmptyProvidedHolder)
startConditions.getNotMetLines(player.toDispatcher(), EmptyProvidedHolder)
)
setDisplayName(
addPlaceholdersInto(
listOf(plugin.configYml.getString("quests.icon.name")),
player
).first()
)
}
}) {
@@ -60,22 +77,72 @@ class Quest(
val alwaysInGUI = config.getBool("gui.always")
val tasks = config.getStrings("tasks")
.mapNotNull { Tasks[it] }
.map { Task(plugin, it, this) }
// The pool of available tasks to pick from
private val availableTasks = config.getSubsections("tasks")
.mapNotNull {
Tasks[it.getString("task")]
?.create(this, it.getString("xp"))
}
private val hasStartedKey: PersistentDataKey<Boolean> = PersistentDataKey(
// The amount of tasks to use from the pool
val taskAmount = config.getInt("task-amount").let {
if (it < 0) {
availableTasks.size
} else {
it.coerceAtMost(availableTasks.size)
}
}
private val savedTasksKey = PersistentDataKey(
plugin.createNamespacedKey("quest_${id}_tasks"),
PersistentDataKeyType.STRING_LIST,
emptyList()
)
// The tasks that are actually in use
var tasks = run {
if (taskAmount == availableTasks.size) {
// If taskAmount is equal to availableTasks.size then tasks are ordered as configured
if (isResettable) {
availableTasks.take(taskAmount)
} else {
availableTasks.shuffled().take(taskAmount)
}
} else {
// If taskAmount is less than availableTasks.size then tasks are selected and ordered randomly.
if (isResettable) {
loadTasks() ?: availableTasks.randomlyPick(taskAmount)
} else {
availableTasks.randomlyPick(taskAmount)
}
}
}
private set
private val hasStartedKey = PersistentDataKey(
plugin.createNamespacedKey("quest_${id}_has_started"),
PersistentDataKeyType.BOOLEAN,
false
)
private val hasCompletedKey: PersistentDataKey<Boolean> = PersistentDataKey(
private val startedTimeKey = PersistentDataKey(
plugin.createNamespacedKey("quest_${id}_started_time"),
PersistentDataKeyType.INT,
Int.MAX_VALUE
)
private val hasCompletedKey = PersistentDataKey(
plugin.createNamespacedKey("quest_${id}_has_completed"),
PersistentDataKeyType.BOOLEAN,
false
)
private val completedTimeKey = PersistentDataKey(
plugin.createNamespacedKey("quest_${id}_completed_time"),
PersistentDataKeyType.INT,
Int.MAX_VALUE
)
private val rewardMessages = config.getStrings("reward-messages")
private val rewards = Effects.compileChain(
@@ -103,14 +170,16 @@ class Quest(
private val resetTime = config.getInt("reset-time")
val isResettable: Boolean
get() = resetTime >= 0
val minutesUntilReset: Int
get() = if (resetTime < 0) {
Int.MAX_VALUE
} else {
val currentTime = (System.currentTimeMillis() / 1000 / 60).toInt()
val previousTime = ServerProfile.load().read(lastResetTimeKey)
resetTime - currentTime + previousTime
resetTime - currentTimeMinutes + previousTime
}
init {
@@ -141,33 +210,99 @@ class Quest(
PlayerlessPlaceholder(plugin, "quest_${id}_time_until_reset") {
formatDuration(this.minutesUntilReset)
}.register()
PlayerPlaceholder(plugin, "quest_${id}_time_since_start") {
formatDuration(this.getTimeSinceStart(it))
}.register()
PlayerPlaceholder(plugin, "quest_${id}_time_since_completed") {
formatDuration(this.getTimeSinceCompletion(it))
}.register()
PlayerPlaceholder(plugin, "quest_${id}_time_since") {
if (hasCompleted(it)) {
plugin.langYml.getString("time-since.completed")
.replace("%time%", formatDuration(this.getTimeSinceCompletion(it)))
.formatEco(it)
} else if (hasStarted(it)) {
plugin.langYml.getString("time-since.started")
.replace("%time%", formatDuration(this.getTimeSinceStart(it)))
.formatEco(it)
} else {
plugin.langYml.getString("time-since.never")
.formatEco(it)
}
}.register()
for (i in 1..this.tasks.size+1) {
PlayerPlaceholder(plugin, "quest_${id}_task_${i}_required_xp") {
this.tasks[i-1].getExperienceRequired(it).toNiceString()
}.register()
PlayerPlaceholder(plugin, "quest_${id}_task_${i}_xp") {
this.tasks[i-1].getExperience(it).toNiceString()
}.register()
PlayerPlaceholder(plugin, "quest_${id}_task_${i}_description") {
this.tasks[i-1].getDescription(it)
}.register()
PlayerPlaceholder(plugin, "quest_${id}_task_${i}_completed") {
this.tasks[i-1].hasCompleted(it).toNiceString()
}.register()
PlayerPlaceholder(plugin, "quest_${id}_task_${i}_completed_description") {
this.tasks[i-1].getCompletedDescription(it)
}.register()
}
}
override fun onRegister() {
for (task in tasks) {
task.bind()
}
}
override fun onRemove() {
if (isResettable) {
saveTasks()
}
for (task in tasks) {
task.unbind()
}
}
fun getTask(template: TaskTemplate): Task? {
return tasks.firstOrNull { it.template == template }
}
fun getDescription(player: Player): List<String> {
return addPlaceholdersInto(listOf(config.getString("description")), player)
val descriptions = config.getStrings("description")
return addPlaceholdersInto(descriptions, player)
}
fun hasActive(player: Player): Boolean {
fun hasActive(player: OfflinePlayer): Boolean {
return hasStarted(player) && !hasCompleted(player)
}
fun hasCompleted(player: Player): Boolean {
fun hasCompleted(player: OfflinePlayer): Boolean {
return player.profile.read(hasCompletedKey)
}
fun meetsStartConditions(player: Player): Boolean {
return startConditions.areMet(player, EmptyProvidedHolder)
return startConditions.areMet(player.toDispatcher(), EmptyProvidedHolder)
}
fun shouldStart(player: Player): Boolean {
return meetsStartConditions(player) && !hasStarted(player)
return meetsStartConditions(player) && !hasStarted(player) && autoStarts
}
fun hasStarted(player: Player): Boolean {
fun hasStarted(player: OfflinePlayer): Boolean {
return player.profile.read(hasStartedKey)
}
fun reset(player: Player) {
fun reset(player: OfflinePlayer) {
player.profile.write(hasStartedKey, false)
player.profile.write(hasCompletedKey, false)
@@ -181,12 +316,41 @@ class Quest(
return
}
startEffects?.trigger(player)
startEffects?.trigger(player.toDispatcher())
player.profile.write(hasStartedKey, true)
player.profile.write(startedTimeKey, currentTimeMinutes)
// Reset tasks to generate new xp requirements
for (task in tasks) {
task.reset(player)
}
Bukkit.getPluginManager().callEvent(PlayerQuestStartEvent(player, this))
}
fun getTimeSinceStart(player: OfflinePlayer): Int {
return currentTimeMinutes - player.profile.read(startedTimeKey)
}
fun getTimeSinceCompletion(player: OfflinePlayer): Int {
return currentTimeMinutes - player.profile.read(completedTimeKey)
}
fun getTimeSincePlaceholder(player: Player): String {
return if (hasCompleted(player)) {
plugin.langYml.getString("time-since.completed")
.replace("%time%", formatDuration(this.getTimeSinceCompletion(player)))
.formatEco(player)
} else if (hasStarted(player)) {
plugin.langYml.getString("time-since.started")
.replace("%time%", formatDuration(this.getTimeSinceStart(player)))
.formatEco(player)
} else {
plugin.langYml.getString("time-since.never")
.formatEco(player)
}
}
fun resetIfNeeded() {
if (resetTime < 0) {
return
@@ -196,11 +360,69 @@ class Quest(
return
}
reset()
}
fun reset() {
ServerProfile.load().write(lastResetTimeKey, (System.currentTimeMillis() / 1000 / 60).toInt())
for (player in Bukkit.getOnlinePlayers()) {
reset(player)
}
// Offline players can be reset async
plugin.scheduler.runAsync {
for (player in Bukkit.getOfflinePlayers()) {
if (!player.isOnline) {
reset(player)
}
}
}
// Unbind old tasks
for (task in tasks) {
task.unbind()
}
tasks = availableTasks.randomlyPick(taskAmount)
// Bind new tasks
for (task in tasks) {
task.bind()
}
// Save new tasks
saveTasks()
}
private fun loadTasks(): List<Task>? {
val serialized = ServerProfile.load().read(savedTasksKey)
if (serialized.isEmpty()) {
return null
}
val savedTasks = mutableListOf<Task>()
for (s in serialized) {
val split = s.split(":")
val taskId = split[0]
val xpExpr = split[1]
val template = Tasks[taskId] ?: continue
savedTasks += template.create(this, xpExpr)
}
return savedTasks
}
private fun saveTasks() {
val serialized = tasks.map {
"${it.template.id}:${it.xpExpr}"
}
ServerProfile.load().write(savedTasksKey, serialized)
}
fun checkCompletion(player: Player): Boolean {
@@ -210,17 +432,21 @@ class Quest(
}
if (tasks.all { it.hasCompleted(player) }) {
player.profile.write(hasCompletedKey, true)
rewards?.trigger(player)
Bukkit.getPluginManager().callEvent(PlayerQuestCompleteEvent(player, this))
complete(player)
return true
}
return false
}
private fun complete(player: Player) {
player.profile.write(hasCompletedKey, true)
player.profile.write(completedTimeKey, currentTimeMinutes)
rewards?.trigger(player.toDispatcher())
Bukkit.getPluginManager().callEvent(PlayerQuestCompleteEvent(player, this))
}
private fun List<String>.addMargin(margin: Int): List<String> {
return this.map { s -> " ".repeat(margin) + s }
}
@@ -233,6 +459,7 @@ class Quest(
fun String.addPlaceholders() = this
.replace("%quest%", quest.name)
.replace("%time_until_reset%", formatDuration(quest.minutesUntilReset))
.replace("%time_since%", getTimeSincePlaceholder(player))
// Replace multi-line placeholders.
val processed = strings.flatMap { s ->
@@ -242,7 +469,7 @@ class Quest(
rewardMessages
.addMargin(margin)
} else if (s.contains("%tasks%")) {
tasks.flatMap { task -> task.getCompletedDescription(player) }
tasks.map { task -> task.getCompletedDescription(player) }
.addMargin(margin)
} else if (s.contains("%description%")) {
getDescription(player)
@@ -256,6 +483,6 @@ class Quest(
placeholderContext(
player = player
)
)
).lineWrap(plugin.configYml.getInt("quests.icon.line-wrap"), true)
}
}

View File

@@ -7,6 +7,8 @@ import com.willfp.libreforge.loader.configs.ConfigCategory
import org.bukkit.entity.Player
object Quests : ConfigCategory("quest", "quests") {
override val supportsSharing = false
private val registry = Registry<Quest>()
override fun clear(plugin: LibreforgePlugin) {

View File

@@ -5,7 +5,6 @@ import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder
import com.willfp.eco.core.placeholder.context.placeholderContext
import com.willfp.eco.util.evaluateExpression
import com.willfp.eco.util.formatEco
@@ -16,7 +15,9 @@ import com.willfp.ecoquests.api.event.PlayerTaskExpGainEvent
import com.willfp.ecoquests.quests.Quest
import com.willfp.ecoquests.quests.Quests
import com.willfp.libreforge.counters.Accumulator
import com.willfp.libreforge.toDispatcher
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import kotlin.math.min
@@ -24,7 +25,7 @@ class Task(
private val plugin: EcoPlugin,
val template: TaskTemplate,
val quest: Quest,
private val xpExpr: String
internal val xpExpr: String
) {
private val xpKey = PersistentDataKey(
plugin.createNamespacedKey("${quest.id}_task_${template.id}_xp"),
@@ -32,6 +33,12 @@ class Task(
0.0
)
private val xpRequiredKey = PersistentDataKey(
plugin.createNamespacedKey("${quest.id}_task_${template.id}_xp_required"),
PersistentDataKeyType.DOUBLE,
0.0
)
private val hasCompletedKey = PersistentDataKey(
plugin.createNamespacedKey("${quest.id}_task_${template.id}_has_completed"),
PersistentDataKeyType.BOOLEAN,
@@ -80,16 +87,16 @@ class Task(
}
}
fun reset(player: Player) {
fun reset(player: OfflinePlayer) {
player.profile.write(xpKey, 0.0)
player.profile.write(hasCompletedKey, false)
}
fun hasCompleted(player: Player): Boolean {
fun hasCompleted(player: OfflinePlayer): Boolean {
return player.profile.read(hasCompletedKey)
}
fun getExperienceRequired(player: Player): Double {
private fun generateExperienceRequired(player: Player): Double {
return evaluateExpression(
xpExpr,
placeholderContext(
@@ -98,8 +105,26 @@ class Task(
)
}
fun getExperience(player: Player): Double {
return min(player.profile.read(xpKey), getExperienceRequired(player))
fun getExperienceRequired(player: Player): Double {
val required = player.profile.read(xpRequiredKey)
return if (required <= 0) {
val newRequired = generateExperienceRequired(player)
if (newRequired <= 0) {
throw IllegalStateException("Invalid XP Required for task ${template.id} in quest ${quest.id}" +
"(Requirement was $newRequired, which is less than or equal to 0)")
}
player.profile.write(xpRequiredKey, newRequired)
newRequired
} else {
required
}
}
fun getExperience(player: OfflinePlayer): Double {
return player.profile.read(xpKey)
}
/**
@@ -124,10 +149,11 @@ class Task(
val requiredXp = getExperienceRequired(player)
val newXp = player.profile.read(xpKey) + amount
player.profile.write(xpKey, newXp)
player.profile.write(xpKey, min(newXp, requiredXp))
if (newXp >= requiredXp) {
player.profile.write(hasCompletedKey, true)
template.onComplete?.trigger(player.toDispatcher())
Bukkit.getPluginManager().callEvent(PlayerTaskCompleteEvent(player, template, quest))
@@ -145,15 +171,13 @@ class Task(
.formatEco(player)
}
fun getCompletedDescription(player: Player): List<String> {
fun getCompletedDescription(player: Player): String {
return if (hasCompleted(player)) {
plugin.configYml.getString("tasks.completed")
.replace("%description%", getDescription(player))
.lineWrap(plugin.configYml.getInt("tasks.line-wrap"), true)
} else {
plugin.configYml.getString("tasks.not-completed")
.replace("%description%", getDescription(player))
.lineWrap(plugin.configYml.getInt("tasks.line-wrap"), true)
}
}
}

View File

@@ -3,8 +3,10 @@ package com.willfp.ecoquests.tasks
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.registry.KRegistrable
import com.willfp.ecoquests.quests.Quest
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.counters.Counters
import com.willfp.libreforge.effects.Effects
class TaskTemplate(
private val plugin: EcoPlugin,
@@ -14,4 +16,12 @@ class TaskTemplate(
val xpGainMethods = config.getSubsections("xp-gain-methods").mapNotNull {
Counters.compile(it, ViolationContext(plugin, "task $id tasks"))
}
val onComplete = Effects.compileChain(
config.getSubsections("on-complete"),
ViolationContext(plugin, "task $id on-complete")
)
fun create(quest: Quest, xpExpr: String) =
Task(plugin, this, quest, xpExpr)
}

View File

@@ -0,0 +1,14 @@
package com.willfp.ecoquests.util
fun <T> Collection<T>.randomlyPick(amount: Int): List<T> {
val list = this.toMutableList()
val picked = mutableListOf<T>()
repeat(amount) {
val index = (0 until list.size).random()
picked.add(list[index])
list.removeAt(index)
}
return picked
}

View File

@@ -3,7 +3,12 @@
# by Auxilor
#
scan-interval: 20 # How often to scan for quest starting / completion (in ticks)
# Even if eco is set up to use a database, you can
# force EcoQuests to save to local storage to disable
# cross-server sync.
use-local-storage: false
scan-interval: 20 # How often to scan for quests auto-starting (in ticks)
gui:
title: "Quest Book"
@@ -34,10 +39,13 @@ gui:
quest-info:
item: writable_book
name: "&aQuest Book"
name: "&fQuest Book"
lore:
- "&eClick to view your"
- "&eprevious quests!"
- ""
- "&7Quests Completed: &f%ecoquests_quests_completed%"
- "&7Quests Active: &f%ecoquests_quests_active%"
- ""
- "&eClick to view past quests!"
location:
row: 1
@@ -130,12 +138,15 @@ completed-gui:
custom-slots: [ ]
tasks:
line-wrap: 32
completed: "&a&l &r&f%description%"
not-completed: "&c&l✘ &r&f%description%"
# The line to show when a task is completed
completed: "&a&l &r&f%description%"
# The line to show when a task is not completed
not-completed: "&c&l❌ &r&f%description%"
quests:
icon:
name: "&e%quest%" # The name of the icon
line-wrap: 32 # Lore line-wrapping
lore:
- "%description%"
- ""
@@ -144,6 +155,8 @@ quests:
- ""
- "&fRewards:"
- " %rewards%"
- ""
- "%time_since%"
complete:
message:

View File

@@ -4,6 +4,6 @@ environment:
options:
color: "&#eacda3"
resource-id: 0
bstats-id: 0
resource-id: 4600
bstats-id: 19455
uses-reflective-reload: false

View File

@@ -10,4 +10,11 @@ messages:
already-started: "&cThe player has already started this quest!"
started-quest: "&fStarted the &a%quest% &fquest for &a%player%&f!"
reset-quest: "&fReset the &a%quest% &fquest for &a%player%&f!"
reset-quest-for-player: "&fReset the &a%quest% &fquest for &a%player%&f!"
reset-quest: "&fReset the &a%quest% &fquest!"
quest-not-resettable: "&cThis quest is not resettable!"
time-since:
never: "&cNot started yet!"
started: "&7Started %time% ago"
completed: "&7Completed %time% ago"

View File

@@ -1,17 +0,0 @@
name: ${pluginName}
version: ${version}
main: com.willfp.ecoquests.EcoQuestsPlugin
api-version: 1.19
dependencies:
- name: eco
required: true
bootstrap: false
- name: libreforge
required: false
bootstrap: false
load-after:
- name: eco
bootstrap: false

View File

@@ -32,8 +32,9 @@ permissions:
children:
ecoquests.command.reload: true
ecoquests.command.quests: true
ecoquests.command.start: op
ecoquests.command.reset: op
ecoquests.command.start: true
ecoquests.command.reset: true
ecoquests.command.resetplayer: true
ecoquests.command.reload:
description: Allows reloading the config
@@ -49,4 +50,7 @@ permissions:
default: op
ecoquests.command.reset:
description: Allows using /ecoquests reset.
default: op
ecoquests.command.resetplayer:
description: Allows using /ecoquests resetplayer.
default: op

View File

@@ -1,26 +1,36 @@
name: "Resettable Quest"
# The ID of the quest is the name of the .yml file,
# for example traveller.yml has the ID of traveller
# You can place quests anywhere in this folder,
# including in subfolders if you want to organize your quest configs
# _example.yml is not loaded.
description: "&fThis quest will reset in &a%time_until_reset%"
name: "Traveller"
description: "&7Stretch your legs! Walk around Lumoria and find new places to explore."
# Options for the /quests GUI
gui:
enabled: true # If the quest should be shown in the GUI
always: false # If the quest should always be in the GUI, even if it's not started
# The item to show in the GUI, read https://plugins.auxilor.io/all-plugins/the-item-lookup-system
item: paper name:"&eExample Quest"
item: paper
# How many minutes between this quest being reset (set to -1 to disable)
# 1 Day: 1440
# 1 Week: 10080
# 1 Month: 43200
reset-time: 10
reset-time: -1
# A list of tasks and their XP requirements to complete this quest.
# If the task is one action, set XP to 1.
# XP requirements can use placeholder math, for example %ecoskills_combat% * 100
tasks:
- task: break_stone
xp: 100
- task: move
xp: 1000
# (For resettable tasks) The amount of tasks to select from the list above.
# Set to -1 to use all tasks.
task-amount: -1
# The messages for the %rewards% placeholder in icons, messages, etc.
reward-messages:
@@ -40,4 +50,9 @@ start-effects: [ ]
# A list of conditions required to start the quest.
# The quest will be automatically started when these conditions are met.
# Read https://plugins.auxilor.io/conditions/configuring-a-condition
# If gui.always is true, then not-met-lines will show up on the GUI icon!
start-conditions: [ ]
# If the quest should auto start when all conditions are met
# If this is set to false, the quest can only be started with /ecoquests start
auto-start: true

View File

@@ -1,4 +1,4 @@
name: "Resettable Quest"
name: "Daily Quest I"
description: "&fThis quest will reset in &a%time_until_reset%"
@@ -7,13 +7,13 @@ gui:
enabled: true # If the quest should be shown in the GUI
always: false # If the quest should always be in the GUI, even if it's not started
# The item to show in the GUI, read https://plugins.auxilor.io/all-plugins/the-item-lookup-system
item: paper name:"&eExample Quest"
item: paper
# How many minutes between this quest being reset (set to -1 to disable)
# 1 Day: 1440
# 1 Week: 10080
# 1 Month: 43200
reset-time: 10
reset-time: 1440
# A list of tasks and their XP requirements to complete this quest.
# If the task is one action, set XP to 1.
@@ -22,6 +22,10 @@ tasks:
- task: break_stone
xp: 100
# (For resettable tasks) The amount of tasks to select from the list above.
# Set to -1 to use all tasks.
task-amount: 1
# The messages for the %rewards% placeholder in icons, messages, etc.
reward-messages:
- " &8» &r&f+2 %ecoskills_defense_name%"
@@ -40,4 +44,7 @@ start-effects: [ ]
# A list of conditions required to start the quest.
# The quest will be automatically started when these conditions are met.
# Read https://plugins.auxilor.io/conditions/configuring-a-condition
# If gui.always is true, then not-met-lines will show up on the GUI icon!
start-conditions: [ ]
auto-start: true

View File

@@ -1,7 +1,7 @@
# The ID of the task is the name of the .yml file,
# for example break_100_stone.yml has the ID of break_100_stone
# You can place tasks anywhere in this folder,
# including in subfolders if you want to organize your quest task
# including in subfolders if you want to organize your task configs
# _example.yml is not loaded.
# If multiple quests have the same task, gaining task XP for one quest
@@ -21,3 +21,10 @@ xp-gain-methods:
filters:
blocks:
- stone
# An optional list of effects to run when a player completes the task
# Read here: https://plugins.auxilor.io/effects/configuring-an-effect
on-complete:
- id: send_message
args:
message: "Task Completed!"

View File

@@ -0,0 +1,4 @@
description: "&fMove distance (&a%xp%&8/&a%required-xp%&f)"
xp-gain-methods:
- trigger: move

View File

@@ -1,5 +1,5 @@
#libreforge-updater
#Wed Aug 09 14:37:41 BST 2023
#Sun Sep 22 17:00:59 BST 2024
kotlin.code.style=official
libreforge-version=4.27.0
version=0.3.0
libreforge-version=4.72.0
version=1.43.0

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -1,6 +0,0 @@
jdk: openjdk17
before_install:
- source "$HOME/.sdkman/bin/sdkman-init.sh"
- sdk update
- sdk install java 17.0.1-tem
- sdk use java 17.0.1-tem

View File

@@ -2,11 +2,15 @@ pluginManagement {
repositories {
gradlePluginPortal()
mavenLocal()
maven("https://repo.jpenilla.xyz/snapshots/")
maven("https://repo.auxilor.io/repository/maven-public/")
maven("https://repo.papermc.io/repository/maven-public/")
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
rootProject.name = "EcoQuests"
// Core