diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/EcoScrollsPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/EcoScrollsPlugin.kt index 001e41c..895545c 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/EcoScrollsPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/EcoScrollsPlugin.kt @@ -3,18 +3,26 @@ package com.willfp.ecoscrolls import com.willfp.ecoscrolls.scrolls.Scrolls import com.willfp.ecoscrolls.commands.CommandEcoScrolls import com.willfp.eco.core.command.impl.PluginCommand +import com.willfp.eco.core.display.DisplayModule +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager +import com.willfp.eco.core.placeholder.context.PlaceholderContext +import com.willfp.eco.core.placeholder.templates.DynamicPlaceholder import com.willfp.ecoscrolls.commands.CommandInscribe import com.willfp.ecoscrolls.config.TargetsYml +import com.willfp.ecoscrolls.display.ScrollDisplay import com.willfp.ecoscrolls.gui.updateInscribeMenu +import com.willfp.ecoscrolls.scrolls.ScrollLevel import com.willfp.ecoscrolls.target.ScrollFinder import com.willfp.ecoscrolls.target.Targets import com.willfp.ecoscrolls.util.DiscoverRecipeListener -import com.willfp.libreforge.SimpleProvidedHolder +import com.willfp.libreforge.NamedValue import com.willfp.libreforge.loader.LibreforgePlugin import com.willfp.libreforge.loader.configs.ConfigCategory -import com.willfp.libreforge.registerGenericHolderProvider +import com.willfp.libreforge.registerHolderPlaceholderProvider import com.willfp.libreforge.registerHolderProvider import org.bukkit.event.Listener +import org.checkerframework.checker.units.qual.m +import java.util.regex.Pattern internal lateinit var plugin: EcoScrollsPlugin private set @@ -22,8 +30,39 @@ internal lateinit var plugin: EcoScrollsPlugin class EcoScrollsPlugin : LibreforgePlugin() { val targetsYml = TargetsYml(this) + init { + plugin = this + } + override fun handleEnable() { registerHolderProvider(ScrollFinder.toHolderProvider()) + + registerHolderPlaceholderProvider { it, _ -> + listOf( + NamedValue("level", it.level), + ) + } + + PlaceholderManager.registerPlaceholder( + object : DynamicPlaceholder(plugin, Pattern.compile("scroll_([a-z]+)_([a-zA-Z0-9_]+)")) { + override fun getValue(args: String, context: PlaceholderContext): String? { + val matcher = pattern.matcher(args) + + if (!matcher.matches()) { + return null + } + + // Get the scroll and identifier from the matched groups + val scroll = matcher.group(1) + val identifier = matcher.group(2) + + // Return empty instead of null for optional placeholders, like hot potato books + val scrollInstance = Scrolls[scroll] ?: return "" + + return scrollInstance.getPlaceholder(identifier, context) ?: "" + } + } + ) } override fun handleReload() { @@ -49,4 +88,8 @@ class EcoScrollsPlugin : LibreforgePlugin() { DiscoverRecipeListener(this) ) } + + override fun createDisplayModule(): DisplayModule { + return ScrollDisplay(this) + } } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/commands/CommandGive.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/commands/CommandGive.kt index 1a47e24..1929027 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/commands/CommandGive.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/commands/CommandGive.kt @@ -3,6 +3,8 @@ package com.willfp.ecoscrolls.commands import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.command.impl.Subcommand import com.willfp.eco.core.drops.DropQueue +import com.willfp.eco.core.items.Items.toSNBT +import com.willfp.eco.core.items.toSNBT import com.willfp.ecoscrolls.scrolls.Scrolls import org.bukkit.Bukkit import org.bukkit.command.CommandSender @@ -50,7 +52,7 @@ class CommandGive( val scroll = Scrolls[args[1]] if (scroll == null) { - sender.sendMessage(plugin.langYml.getMessage("invalid-stone")) + sender.sendMessage(plugin.langYml.getMessage("invalid-scroll")) return } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/display/ScrollDisplay.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/display/ScrollDisplay.kt new file mode 100644 index 0000000..3efe2a3 --- /dev/null +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/display/ScrollDisplay.kt @@ -0,0 +1,24 @@ +package com.willfp.ecoscrolls.display + +import com.willfp.eco.core.display.DisplayModule +import com.willfp.eco.core.display.DisplayPriority +import com.willfp.eco.core.fast.fast +import com.willfp.ecoscrolls.EcoScrollsPlugin +import com.willfp.ecoscrolls.scrolls.scroll +import com.willfp.ecoscrolls.scrolls.scrolls +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack + +class ScrollDisplay( + plugin: EcoScrollsPlugin +): DisplayModule(plugin, DisplayPriority.HIGHEST) { + override fun display(itemStack: ItemStack, player: Player?, vararg args: Any) { + val fis = itemStack.fast() + + fis.scroll?.displayScroll(fis, player) + + for (scroll in fis.scrolls) { + fis.lore = fis.lore + scroll.scroll.getLore(itemStack, player) + } + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/gui/InscriptionTable.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/gui/InscriptionTable.kt index 60fbef6..0613294 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/gui/InscriptionTable.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/gui/InscriptionTable.kt @@ -1,6 +1,7 @@ package com.willfp.ecoscrolls.gui import com.willfp.eco.core.drops.DropQueue +import com.willfp.eco.core.fast.fast import com.willfp.eco.core.gui.GUIComponent import com.willfp.eco.core.gui.captiveSlot import com.willfp.eco.core.gui.menu @@ -9,6 +10,7 @@ import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent import com.willfp.eco.core.gui.onEvent import com.willfp.eco.core.gui.onLeftClick import com.willfp.eco.core.gui.slot +import com.willfp.eco.core.gui.slot.ConfigSlot import com.willfp.eco.core.gui.slot.CustomSlot import com.willfp.eco.core.gui.slot.FillerMask import com.willfp.eco.core.gui.slot.MaskItems @@ -45,10 +47,13 @@ private val Menu.status by menuStateVar(InscriptionStatus.EMPTY) private val Menu.scroll by menuStateVar>() -private val capturedItem = CaptiveItem() -private val capturedScrollItem = CaptiveItem() +private lateinit var capturedItem: CaptiveItem +private lateinit var capturedScrollItem: CaptiveItem internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) { + capturedItem = CaptiveItem() + capturedScrollItem = CaptiveItem() + val violationContext = ViolationContext(plugin, "Inscription Table") val openEffects = Effects.compile( @@ -62,6 +67,20 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) { ) inscriptionTable = menu(plugin.configYml.getInt("gui.rows")) { + allowChangingHeldItem() + + title = plugin.configYml.getFormattedString("gui.title") + + val indicatorPattern = plugin.configYml.getStrings("gui.indicator.pattern") + for (i in 1..indicatorPattern.size) { + val row = indicatorPattern[i - 1] + for (j in 1..9) { + if (row[j - 1] != '0') { + setSlot(i, j, IndicatorSlot(plugin)) + } + } + } + setMask( FillerMask( MaskItems.fromItemNames( @@ -98,6 +117,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) { ) onEvent { player, menu, _ -> + menu.scroll[player] = Optional.empty() val item = capturedItem[player] val scrollItem = capturedScrollItem[player] @@ -107,12 +127,11 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) { val scroll = scrollItem.scroll if (scroll == null) { menu.status[player] = InscriptionStatus.DENY + } else if (scroll.canInscribe(item)) { + menu.scroll[player] = Optional.of(scroll) + menu.status[player] = InscriptionStatus.ALLOW } else { - menu.status[player] = if (scroll.canInscribe(item)) { - InscriptionStatus.ALLOW - } else { - InscriptionStatus.DENY - } + menu.status[player] = InscriptionStatus.DENY } } } @@ -132,13 +151,41 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) { .forceTelekinesis() .push() } + + for (config in plugin.configYml.getSubsections("gui.custom-slots")) { + setSlot( + config.getInt("row"), + config.getInt("column"), + ConfigSlot(config) + ) + } + } +} + +private class IndicatorSlot(plugin: EcoScrollsPlugin) : CustomSlot() { + private val allowed = Items.lookup(plugin.configYml.getString("gui.indicator.allow-item")).item + private val denied = Items.lookup(plugin.configYml.getString("gui.indicator.deny-item")).item + + init { + create() + } + + private fun create() { + init(slot { player, menu -> + val status = menu.status[player] + + when (status) { + InscriptionStatus.ALLOW -> allowed + else -> denied + } + }) } } private class CloseSlot(private val plugin: EcoScrollsPlugin) : CustomSlot() { private val item = Items.lookup(plugin.configYml.getString("gui.close.item")).modify { - setDisplayName(plugin.langYml.getFormattedString("gui.close.name")) - addLoreLines(plugin.langYml.getFormattedStrings("gui.close.lore")) + setDisplayName(plugin.configYml.getFormattedString("gui.close.name")) + addLoreLines(plugin.configYml.getFormattedStrings("gui.close.lore")) } init { @@ -201,16 +248,16 @@ private abstract class MenuSlot( } private fun getItem(player: Player, menu: Menu): ItemStack { - val name = plugin.langYml.getString("gui.${status.name.lowercase()}.name") + val name = plugin.configYml.getString("gui.${status.name.lowercase()}.name") .injectPlaceholders(player, menu) - val lore = plugin.langYml.getStrings("gui.${status.name.lowercase()}.lore") + val lore = plugin.configYml.getStrings("gui.${status.name.lowercase()}.lore") .map { it.injectPlaceholders(player, menu) } - return item.modify { - setDisplayName(name) - addLoreLines(lore) - } + return item.fast().apply { + this.displayName = name + this.lore = lore + }.unwrap() } private fun String.injectPlaceholders(player: Player, menu: Menu): String { @@ -250,10 +297,18 @@ private class AllowSlot(plugin: EcoScrollsPlugin, violationContext: ViolationCon val inscribed = scroll.inscribe(item, player) if (inscribed) { + val scrollItem = capturedScrollItem[player] + ?: throw IllegalStateException("Scroll item is null") + + scrollItem.amount -= 1 + applyEffects.trigger(TriggerData(player = player).dispatch(player.toDispatcher())) } else { denyEffects.trigger(TriggerData(player = player).dispatch(player.toDispatcher())) } + + // Cheat to update the menu + menu.callEvent(player, CaptiveItemChangeEvent(0, 0, null, null)) } } diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Items.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Items.kt index f29765b..e3663ff 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Items.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Items.kt @@ -50,6 +50,7 @@ var FastItemStack.scrolls: Set set(value) { this.persistentDataContainer.scrolls = value } + var PersistentDataContainer.scrolls: Set get() { if (!this.has(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY)) { @@ -75,18 +76,18 @@ var PersistentDataContainer.scrolls: Set return } - val tag = mutableListOf() + val tags = mutableListOf() - for (scroll in scrolls) { + for (scroll in value) { val scrollTag = newPersistentDataContainer() scrollTag.set(SCROLL_ID_KEY, PersistentDataType.STRING, scroll.scroll.id) scrollTag.set(SCROLL_LEVEL_KEY, PersistentDataType.INTEGER, scroll.level) - tag += scrollTag + tags += scrollTag } - this.set(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY, tag.toTypedArray()) + this.set(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY, tags.toTypedArray()) } fun ItemStack.getScrollLevel(scroll: Scroll): ScrollLevel? { diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Scroll.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Scroll.kt index 64f92f3..262b29d 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Scroll.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/Scroll.kt @@ -1,10 +1,23 @@ package com.willfp.ecoscrolls.scrolls import com.willfp.eco.core.config.interfaces.Config +import com.willfp.eco.core.display.Display +import com.willfp.eco.core.fast.FastItemStack +import com.willfp.eco.core.fast.fast +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager import com.willfp.eco.core.items.Items +import com.willfp.eco.core.placeholder.InjectablePlaceholder +import com.willfp.eco.core.placeholder.PlaceholderInjectable +import com.willfp.eco.core.placeholder.context.PlaceholderContext +import com.willfp.eco.core.placeholder.context.placeholderContext +import com.willfp.eco.core.placeholder.templates.DynamicInjectablePlaceholder +import com.willfp.eco.core.placeholder.templates.DynamicPlaceholder import com.willfp.eco.core.price.ConfiguredPrice import com.willfp.eco.core.recipe.Recipes import com.willfp.eco.core.registry.KRegistrable +import com.willfp.eco.util.evaluateExpression +import com.willfp.eco.util.evaluateExpressionOrNull +import com.willfp.eco.util.formatEco import com.willfp.ecoscrolls.EcoScrollsPlugin import com.willfp.ecoscrolls.plugin import com.willfp.ecoscrolls.target.Targets @@ -16,6 +29,8 @@ import com.willfp.libreforge.triggers.TriggerData import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack import java.util.Objects +import java.util.regex.Pattern +import kotlin.math.exp class Scroll( plugin: EcoScrollsPlugin, @@ -40,8 +55,16 @@ class Scroll( val maxLevel = config.getInt("max-level") - private val _item = Items.lookup(config.getString("item.item")).item.apply { - this.scroll = this@Scroll + private val itemName = config.getString("item.name") + private val itemLore = config.getStrings("item.lore") + + private val _item = run { + val base = Items.lookup(config.getString("item.item")).item + val fis = base.fast() + fis.scroll = this + fis.displayName = itemName.formatEco() + fis.lore = itemLore.formatEco().map { Display.PREFIX + it } + fis.lore + fis.unwrap() } val item: ItemStack @@ -57,6 +80,8 @@ class Scroll( val targets = config.getStrings("targets") .mapNotNull { Targets[it] } + private val conflicts = config.getStrings("conflicts") + val inscriptionConditions = Conditions.compile( config.getSubsections("inscription.conditions"), context.with("inscription conditions") @@ -71,6 +96,30 @@ class Scroll( config.getSubsection("inscription.price"), ) + private val lore = config.getStrings("lore") + + private val levelPlaceholder = object : DynamicInjectablePlaceholder(Pattern.compile("level")) { + override fun getValue(p0: String, p1: PlaceholderContext): String? { + return p1.itemStack?.getScrollLevel(this@Scroll)?.level?.toString() + } + } + + private val levelInjectable = object : PlaceholderInjectable { + override fun getPlaceholderInjections(): List { + return listOf( + levelPlaceholder + ) + } + + override fun addInjectablePlaceholder(p0: MutableIterable) { + // + } + + override fun clearInjectedPlaceholders() { + // + } + } + fun getLevel(level: Int): ScrollLevel { return levels.getOrPut(level) { createLevel(level) @@ -82,7 +131,11 @@ class Scroll( } fun canInscribe(itemStack: ItemStack): Boolean { - if (!targets.none { it.matches(itemStack) }) { + if (targets.none { it.matches(itemStack) }) { + return false + } + + if (itemStack.scrolls.any { it.scroll.conflictsWith(this) }) { return false } @@ -121,7 +174,8 @@ class Scroll( inscriptionEffects.trigger( TriggerData( - player = player + player = player, + item = itemStack ).dispatch(player.toDispatcher()) ) @@ -136,6 +190,36 @@ class Scroll( itemStack.scrolls = itemStack.scrolls.filter { it.scroll != this }.toSet() + level } + fun getLore(itemStack: ItemStack, player: Player?): List { + return lore.formatEco( + placeholderContext( + player = player, + item = itemStack, + injectable = levelInjectable + ) + ).map { Display.PREFIX + it } + } + + fun displayScroll(fis: FastItemStack, player: Player?) { + fis.displayName = itemName.formatEco(player = player) + fis.lore = itemLore.formatEco(placeholderContext(player = player)) + .map { Display.PREFIX + it } + fis.lore + } + + fun getPlaceholder(identifier: String, context: PlaceholderContext): String? { + if ((levelPlaceholder.getValue(levelPlaceholder.pattern.pattern(), context)?.toIntOrNull() ?: 0) < 1) { + return null + } + + val expression = config.getString("placeholders.$identifier") + return expression.formatEco(context.withInjectableContext(levelInjectable)) + } + + fun conflictsWith(other: Scroll): Boolean { + return this.conflicts.contains(other.id) || + other.conflicts.contains(this.id) + } + override fun equals(other: Any?): Boolean { if (other !is Scroll) { return false diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/ScrollLevel.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/ScrollLevel.kt index 356dbd0..124eb21 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/ScrollLevel.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/ecoscrolls/scrolls/ScrollLevel.kt @@ -23,7 +23,7 @@ class ScrollLevel( } override fun toString(): String { - return id.toString() + return "ScrollLevel(scroll=$scroll, level=$level)" } override fun hashCode(): Int { diff --git a/eco-core/core-plugin/src/main/resources/config.yml b/eco-core/core-plugin/src/main/resources/config.yml index 1bf4631..750ad28 100644 --- a/eco-core/core-plugin/src/main/resources/config.yml +++ b/eco-core/core-plugin/src/main/resources/config.yml @@ -10,6 +10,8 @@ discover-recipes: true gui: rows: 6 + title: "Inscription Table" + mask: # The way the mask works is by having a list of materials # And then a pattern to use those materials. @@ -25,41 +27,41 @@ gui: - black_stained_glass_pane - magenta_stained_glass_pane pattern: - - "011111110" - - "012202210" - - "012111210" - - "010111010" - - "011111110" - - "011101110" + - "111111111" + - "100010001" + - "111000111" + - "211101112" + - "221111122" + - "222101222" - show-allowed: - allow-material: lime_stained_glass_pane - deny-material: red_stained_glass_pane + indicator: + allow-item: lime_stained_glass_pane + deny-item: red_stained_glass_pane # 1 is a show-allowed slot, # 0 is not. pattern: - - "100000001" - - "100000001" - - "100000001" - - "100000001" - - "100000001" - - "100000001" + - "000000000" + - "001101100" + - "000111000" + - "000000000" + - "000000000" + - "000000000" inscribe-slot: - row: 2 + row: 4 column: 5 scroll-slot: - row: 4 - column: 7 + row: 2 + column: 8 item-slot: - row: 4 - column: 3 + row: 2 + column: 2 close: - material: barrier + item: barrier name: "&cClose" lore: [] location: @@ -67,7 +69,7 @@ gui: column: 5 allow: - material: feather unbreaking:1 hide_enchants + item: feather unbreaking:1 hide_enchants name: "&aInscribe Item" lore: - "&7Inscribe %scroll% &7onto" @@ -80,13 +82,13 @@ gui: - "&eClick to inscribe!" deny: - material: barrier + item: barrier name: "&cCannot Inscribe" lore: - "&7You cannot inscribe this item with this!" empty: - material: feather unbreaking:1 hide_enchants + item: feather unbreaking:1 hide_enchants name: "&aInscribe Item" lore: - "&7Place an item on the left and" @@ -104,3 +106,6 @@ gui: # Effects to run when trying to inscribe an item without meeting the conditions deny-effects: [ ] + + # Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots + custom-slots: [ ] diff --git a/eco-core/core-plugin/src/main/resources/eco.yml b/eco-core/core-plugin/src/main/resources/eco.yml index 1110188..bddc024 100644 --- a/eco-core/core-plugin/src/main/resources/eco.yml +++ b/eco-core/core-plugin/src/main/resources/eco.yml @@ -5,4 +5,4 @@ environment: options: resource-id: 2873 bstats-id: 16436 - color: "d2d2d" + color: "e3c72" diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml index 51c35f3..4899eb9 100644 --- a/eco-core/core-plugin/src/main/resources/lang.yml +++ b/eco-core/core-plugin/src/main/resources/lang.yml @@ -1,8 +1,13 @@ messages: - prefix: "d2d2d&lEcoScrolls&r &8» &r" + prefix: "F0743&lEcoScrolls&r &8» &r" no-permission: "&cYou don't have permission to do this!" not-player: "&cThis command must be run by a player" invalid-command: "&cUnknown subcommand!" reloaded: "Reloaded!" all: "All" + needs-player: "&cYou must specify a player!" + needs-scroll: "&cYou must specify a scroll!" + invalid-player: "&cYou must specify a player!" + invalid-scroll: "&cYou must specify a scroll!" + give-success: "Gave %scroll%&r to %recipient%&r!" diff --git a/eco-core/core-plugin/src/main/resources/scrolls/_example.yml b/eco-core/core-plugin/src/main/resources/scrolls/_example.yml index 3093148..7f4120b 100644 --- a/eco-core/core-plugin/src/main/resources/scrolls/_example.yml +++ b/eco-core/core-plugin/src/main/resources/scrolls/_example.yml @@ -23,7 +23,6 @@ item: # Options for inscribing items with the scroll inscription: # The conditions required to inscribe the item - # not-met-lines will show on the inscription table if the conditions are not met # not-met-effects will run if someone tries to inscribe the item without meeting the conditions conditions: [ ] @@ -41,18 +40,28 @@ inscription: targets: - sword +# The conflicts that the scroll has with other scrolls +conflicts: [ ] + +# The lore added to items when inscribed with the scroll +lore: + - "" + - "&7This item has been inscribed with" + - "&6Example Scroll" + +# Item placeholders, can be used in other plugins. +# The placeholder is %ecoscrolls_scroll__% +placeholders: + bonus: "%level% * 2" + # Read https://plugins.auxilor.io/effects/configuring-an-effect # The effects for the scroll effects: - - id: give_money + - id: send_message args: - amount: "0.25 * %victim_level%" + message: "&6You have used the Example Scroll!" triggers: - - kill - filters: - not_entities: - - player - + - alt_click # Read https://plugins.auxilor.io/effects/configuring-a-condition # The conditions for the scroll to work