From 1d7e8a07324efdfa3b9680b67d2cbb7a5f795c1c Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Mon, 6 May 2024 21:26:21 +0200 Subject: [PATCH] Implements netherite salvaging #24 --- README.md | 60 ++++++----- .../blacksmith/config/SalvageMethod.java | 23 ++++ .../blacksmith/config/SmithPreset.java | 3 +- .../scrapper/GlobalScrapperSettings.java | 46 ++++++-- .../config/scrapper/ScrapperNPCSettings.java | 29 +++++ .../config/scrapper/ScrapperSetting.java | 66 +++++++++--- .../blacksmith/manager/EconomyManager.java | 37 +++++-- .../blacksmith/trait/CustomTrait.java | 8 +- .../blacksmith/trait/ReforgeSession.java | 76 ++++++------- .../blacksmith/trait/SalvageSession.java | 61 ++++++----- .../blacksmith/trait/ScrapperTrait.java | 102 +++++++++++++----- .../blacksmith/util/ConfigHelper.java | 1 + .../knarcraft/blacksmith/util/ItemHelper.java | 37 ------- .../blacksmith/util/SalvageHelper.java | 59 ++++++++-- src/main/resources/config.yml | 31 ++++-- 15 files changed, 430 insertions(+), 209 deletions(-) create mode 100644 src/main/java/net/knarcraft/blacksmith/config/SalvageMethod.java diff --git a/README.md b/README.md index 1bfa895..4b2d63c 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ repair all items, except diamond armor. All currently supported presets, and available filters for each preset: - BLACKSMITH (WEAPON_SMITH + ARMOR_SMITH + TOOL_SMITH) + - GOLD + - IRON + - DIAMOND + - NETHERITE - WEAPON_SMITH: (RANGED + SWORD + SHIELD) - BOW (bows and crossbows) - SWORD (swords) @@ -212,12 +216,14 @@ All currently supported presets, and available filters for each preset: ### Scrapper global-only options -| Key | Value type | Default | Description | -|----------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| basePrice | positive decimal number | 0 | The cost of using a scrapper. | -| showExactTime | true/false | false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions. | -| giveExperience | true/false | true | If true, each enchantment level on the salvaged item will give one EXP level as salvage. | -| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | `"*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"` | The items that should be deferred when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK` (the default) for deferring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the trash salvage. Different item specifications are split by a `;` character. Use `,` to split separate trash salvages when using commands, like: `SHIELD:STICK,BOW_STRING`. | +| Key | Value type | Default | Description | +|-----------------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| salvagePrice | positive decimal number | 0 | The cost of using a scrapper to salvage an item. | +| armorTrimSalvagePrice | positive decimal number | 5 | The cost of using a scrapper to remove armor trim from an item. | +| netheriteSalvagePrice | positive decimal number | 15 | The cost of using a scrapper to remove netherite from an item. | +| showExactTime | true/false | false | If true, scrappers will display exact time remaining in minutes and seconds, instead of vague expressions. | +| giveExperience | true/false | true | If true, each enchantment level on the salvaged item will give one EXP level as salvage. | +| trashSalvage | TARGET_MATERIAL:IGNORED_MATERIAL\[,\*_TARGET2:\*_IGNORED2] | `"*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK"` | The items that should be deferred when calculating partial salvage. Because receiving just the sticks when salvaging a diamond pickaxe is kind of sad, this allows specifying for example: `*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK` (the default) for deferring sticks in salvage for shovels, pickaxes, axes, hoes and swords. A `:` character splits selected items and the trash salvage. Different item specifications are split by a `;` character. Use `,` to split separate trash salvages when using commands, like: `SHIELD:STICK,BOW_STRING`. | ### Scrapper per-npc (with default values set in config.yml) @@ -234,28 +240,32 @@ All currently supported presets, and available filters for each preset: | scrapperTitle | text string | scrapper | The title displayed as part of the message explaining that a scrapper doesn't recognize a player's held item. | | extendedSalvageEnabled | true/false | false | Whether to enable the extended salvage behavior for this scrapper. As long as it is allowed by salvageAbleItems and it can be crafted in a crafting table, it can be salvaged. This includes things like four planks salvaged into wood. | | salvageEnchanted | true/false | false | Whether the scrapper is able to salvage enchanted items. This is disabled by default as it's very easy to accidentally salvage heavily enchanted items if one is not careful. | -| salvageArmorTrims | true/false | true | Whether the scrapper is able to salvage armor trims. | +| salvageArmorTrims | true/false | true | Whether the scrapper is able to salvage armor trims from items. | +| salvageNetherite | true/false | true | Whether the scrapper is able to salvage netherite items into diamond items. | #### Messages -| Message Key | Default | Explanation | -|---------------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| -| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the scrapper is serving another player. | -| busySalvageMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the scrapper is busy salvaging an item. | -| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again. | -| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to salvage that! | The message displayed when a scrapper is presented an item which it cannot salvage. | -| tooDamagedForSalvageMessage | &cThat item is too damaged to be salvaged into anything useful | The message displayed when a scrapper is presented with an item too damaged to produce salvage. | -| successSalvagedMessage | There you go! | The message displayed when a scrapper successfully repairs an item. | -| failSalvageMessage | &cWhoops! The item broke! Maybe next time? | The message displayed when a scrapper fails to salvage an item. | -| itemChangedMessage | &cThat's not the item you wanted to salvage before! | The message displayed when a player changes their item after being shown the salvage cost. | -| startSalvageMessage | &eOk, let's see what I can do... | The message displayed when a scrapper starts salvaging an item. | -| insufficientFundsMessage | &cYou don't have enough money to salvage an item! | The message displayed when a player is unable to pay for scrapping an item. | -| costMessage | &eIt will cost &a{cost}&e to salvage that item! {yield} &eClick again to salvage! | The message displayed when telling a player about the cost of scrapping an item. | -| fullSalvageMessage | &aI should be able to extract all components from that pristine item.&r | The message displayed as part of costMessage's yield placeholder if all components will be returned. | -| partialSalvageMessage | &cI cannot extract all components from that damaged item.&r | The message displayed as part of costMessage's yield placeholder if only some components will be returned. | -| cannotSalvageEnchantedMessage | &cI'm sorry, but I'm unable to salvage enchanted items! | The message displayed when telling a player that the scrapper cannot salvage enchanted items. | -| cannotSalvageArmorTrimMessage | &cI'm sorry, but I'm unable to salvage armor trims! | The message displayed when telling a player that the scrapper cannot salvage items with armor trim. | -| armorTrimSalvageNotFoundMessage | "&cI'm sorry, but I don't know how to salvage that armor trim!" | The message displayed when telling a player that the scrapper cannot find the correct items to return as armor trim salvage. | +| Message Key | Default | Explanation | +|---------------------------------|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| +| busyPlayerMessage | &cI'm busy at the moment. Come back later! | The message displayed when the scrapper is serving another player. | +| busySalvageMessage | &cI'm working on it. Be patient! I'll finish {time}! | The message displayed when the scrapper is busy salvaging an item. | +| coolDownUnexpiredMessage | &cYou've already had your chance! Give me a break! I'll be ready {time}! | The message displayed when the player has to wait for the cool-down to expire before using the scrapper again. | +| invalidItemMessage | &cI'm sorry, but I'm a/an {title}, I don't know how to salvage that! | The message displayed when a scrapper is presented an item which it cannot salvage. | +| tooDamagedForSalvageMessage | &cThat item is too damaged to be salvaged into anything useful | The message displayed when a scrapper is presented with an item too damaged to produce salvage. | +| successSalvagedMessage | There you go! | The message displayed when a scrapper successfully repairs an item. | +| failSalvageMessage | &cWhoops! The item broke! Maybe next time? | The message displayed when a scrapper fails to salvage an item. | +| itemChangedMessage | &cThat's not the item you wanted to salvage before! | The message displayed when a player changes their item after being shown the salvage cost. | +| startSalvageMessage | &eOk, let's see what I can do... | The message displayed when a scrapper starts salvaging an item. | +| insufficientFundsMessage | &cYou don't have enough money to salvage an item! | The message displayed when a player is unable to pay for salvaging an item. | +| costMessage | &eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage! | The message displayed when telling a player about the cost of salvaging an item. | +| costMessageArmorTrim | &eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim! | The message displayed when telling a player about the cost of salvaging an item's armor trim. | +| costMessageNetherite | &eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond! | The message displayed when telling a player about the cost of salvaging a netherite item into a diamond item. | +| fullSalvageMessage | &aI should be able to extract all components from that pristine item.&r | The message displayed as part of costMessage's yield placeholder if all components will be returned. | +| partialSalvageMessage | &cI cannot extract all components from that damaged item.&r | The message displayed as part of costMessage's yield placeholder if only some components will be returned. | +| cannotSalvageEnchantedMessage | &cI'm sorry, but I'm unable to salvage enchanted items! | The message displayed when telling a player that the scrapper cannot salvage enchanted items. | +| cannotSalvageArmorTrimMessage | &cI'm sorry, but I'm unable to salvage armor trims! | The message displayed when telling a player that the scrapper cannot salvage items with armor trim. | +| armorTrimSalvageNotFoundMessage | &cI'm sorry, but I don't know how to salvage that armor trim! | The message displayed when telling a player that the scrapper cannot find the correct items to return as armor trim salvage. | +| cannotSalvageNetheriteMessage | &cI'm sorry, but I'm unable to salvage netherite items! | The message displayed when telling a player that the scrapper cannot salvage netherite items. | ## Language customization diff --git a/src/main/java/net/knarcraft/blacksmith/config/SalvageMethod.java b/src/main/java/net/knarcraft/blacksmith/config/SalvageMethod.java new file mode 100644 index 0000000..b6b9ff5 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/SalvageMethod.java @@ -0,0 +1,23 @@ +package net.knarcraft.blacksmith.config; + +/** + * A representation of the different ways an item can be salvaged + */ +public enum SalvageMethod { + + /** + * Salvaging the item normally by returning the item's crafting recipe + */ + SALVAGE, + + /** + * Removing the armor trim from an item + */ + ARMOR_TRIM, + + /** + * Un-doing netherite application for an item + */ + NETHERITE, + +} diff --git a/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java b/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java index 765896b..b8c8e8f 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java +++ b/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java @@ -22,7 +22,8 @@ public enum SmithPreset { /** * A blacksmith capable of re-forging everything */ - BLACKSMITH(new SmithPresetFilter[]{}), + BLACKSMITH(new SmithPresetFilter[]{SmithPresetFilter.GOLD, SmithPresetFilter.IRON, SmithPresetFilter.DIAMOND, + SmithPresetFilter.NETHERITE}), /** * A blacksmith capable of re-forging all weapons (including shields) diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java index cbc518c..14454ca 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java @@ -34,7 +34,7 @@ public class GlobalScrapperSettings implements Settings { * * @param instance

A reference to the blacksmith plugin

*/ - public GlobalScrapperSettings(BlacksmithPlugin instance) { + public GlobalScrapperSettings(@NotNull BlacksmithPlugin instance) { this.instance = instance; } @@ -78,7 +78,8 @@ public class GlobalScrapperSettings implements Settings { * @param scrapperSetting

The setting to get

* @return

The current raw setting value

*/ - public @NotNull Object getRawValue(@NotNull ScrapperSetting scrapperSetting) { + @NotNull + public Object getRawValue(@NotNull ScrapperSetting scrapperSetting) { return this.settings.get(scrapperSetting); } @@ -87,6 +88,7 @@ public class GlobalScrapperSettings implements Settings { * * @return

The current value of the default NPC settings

*/ + @NotNull public Map getDefaultNPCSettings() { return new HashMap<>(this.settings); } @@ -108,10 +110,22 @@ public class GlobalScrapperSettings implements Settings { * @param setting

The setting to get the value of

* @return

The value of the given setting as a boolean

*/ - public boolean asBoolean(ScrapperSetting setting) { + public boolean asBoolean(@NotNull ScrapperSetting setting) { return ConfigHelper.asBoolean(getValue(setting)); } + /** + * Gets the given value as a double + * + *

This will throw an exception if used for a non-double setting

+ * + * @param setting

The setting to get the value of

+ * @return

The value of the given setting as a double

+ */ + public double asDouble(@NotNull ScrapperSetting setting) { + return ConfigHelper.asDouble(getValue(setting)); + } + /** * Gets the value of a setting, using the default if not set * @@ -173,12 +187,30 @@ public class GlobalScrapperSettings implements Settings { } /** - * Gets the cost of using a scrapper + * Gets the cost of using a scrapper to salvage an item * - * @return

The cost of using a scrapper

+ * @return

The cost of using a scrapper to salvage an item

*/ - public double getCost() { - return ConfigHelper.asDouble(getValue(ScrapperSetting.USE_COST)); + public double getSalvageCost() { + return asDouble(ScrapperSetting.SALVAGE_COST); + } + + /** + * Gets the cost of using a scrapper to remove armor trim + * + * @return

The cost of using a scrapper to remove armor trim

+ */ + public double getArmorTrimSalvageCost() { + return asDouble(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST); + } + + /** + * Gets the cost of using a scrapper to remove netherite from an item + * + * @return

The cost of using a scrapper to remove netherite from an item

+ */ + public double getNetheriteSalvageCost() { + return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST); } /** diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperNPCSettings.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperNPCSettings.java index 3d1873c..579b47d 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperNPCSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperNPCSettings.java @@ -151,6 +151,16 @@ public class ScrapperNPCSettings implements TraitSettings { return asString(ScrapperSetting.COST_MESSAGE_ARMOR_TRIM); } + /** + * Gets the message to use for displaying netherite salvage cost + * + * @return

The message to use for displaying netherite salvage cost

+ */ + @NotNull + public String getNetheriteCostMessage() { + return asString(ScrapperSetting.COST_MESSAGE_NETHERITE); + } + @Override @NotNull public String getCoolDownUnexpiredMessage() { @@ -316,6 +326,15 @@ public class ScrapperNPCSettings implements TraitSettings { return asBoolean(ScrapperSetting.SALVAGE_ARMOR_TRIMS); } + /** + * Whether salvage of netherite items is enabled + * + * @return

True if this scrapper can salvage netherite items

+ */ + public boolean salvageNetherite() { + return asBoolean(ScrapperSetting.SALVAGE_NETHERITE); + } + /** * Gets the title of this scrapper NPC * @@ -415,4 +434,14 @@ public class ScrapperNPCSettings implements TraitSettings { return asString(ScrapperSetting.ARMOR_TRIM_SALVAGE_NOT_FOUND_MESSAGE); } + /** + * Gets the message to display when explaining that this scrapper is unable to salvage netherite items + * + * @return

The message to display when explaining that this scrapper is unable to salvage netherite items

+ */ + @NotNull + public String getCannotSalvageNetheriteMessage() { + return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE); + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java index 91bf566..6eb3804 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java @@ -19,7 +19,7 @@ public enum ScrapperSetting implements Setting { *

If set to false, the item will be directly put in the player's inventory instead

*/ DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "Whether the " + - "item will drop materials resulting from scrapping on the ground, instead of putting them into the user's" + + "item will drop materials resulting from salvaging on the ground, instead of putting them into the user's" + " inventory", true, false), /** @@ -85,6 +85,12 @@ public enum ScrapperSetting implements Setting { */ SALVAGE_ARMOR_TRIMS("salvageArmorTrims", SettingValueType.BOOLEAN, true, "Whether to enable salvaging of armor trims.", true, false), + + /** + * The setting for whether the NPC should allow salvaging netherite items to diamond items + */ + SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true, + "Whether to enable salvaging of netherite items", true, false), /*----------- | Messages | @@ -164,16 +170,23 @@ public enum ScrapperSetting implements Setting { * The message displayed when displaying the cost of salvaging the held item to the player */ COST_MESSAGE("costMessage", SettingValueType.STRING, - "&eIt will cost &a{cost}&e to salvage that item! {yield} Click again to salvage!", + "&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!", "The message to display when informing a player about the salvaging cost", true, true), /** * The message displayed when displaying the cost of salvaging the armor trim of the held item to the player */ COST_MESSAGE_ARMOR_TRIM("costMessageArmorTrim", SettingValueType.STRING, - "&eIt will cost &a{cost}&e to salvage that armor trim!", + "&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!", "The message to display when explaining the shown item's armor trim's salvage cost", true, true), + /** + * The message displayed when displaying the cost of salvaging the netherite of the held item to the player + */ + COST_MESSAGE_NETHERITE("costMessageNetherite", SettingValueType.STRING, + "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!", + "The message to display when explaining the shown item's netherite salvage cost", true, true), + /** * The message displayed when explaining that all items will be returned as salvage */ @@ -209,21 +222,40 @@ public enum ScrapperSetting implements Setting { "&cI'm sorry, but I don't know how to salvage that armor trim!", "The message to display if the correct materials to return for the armor trim are unknown", true, true), + /** + * The message displayed when explaining that netherite salvage is disabled + */ + CANNOT_SALVAGE_NETHERITE_MESSAGE("cannotSalvageNetheriteMessage", SettingValueType.STRING, + "&cI'm sorry, but I'm unable to salvage netherite items!", + "The message to display when asked to salvage netherite items, and that option is disabled", true, true), + /*------------------ | Global settings | ------------------*/ /** - * The setting for the use cost of using the scrapper + * The setting for the salvage cost */ - USE_COST("basePrice", SettingValueType.POSITIVE_DOUBLE, 0, "The cost of using a scrapper", - false, false), + SALVAGE_COST("salvagePrice", SettingValueType.POSITIVE_DOUBLE, 0, + "The cost of using a scrapper to salvage an item", false, false), + + /** + * The setting for the armor trim salvage cost + */ + ARMOR_TRIM_SALVAGE_COST("armorTrimSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 5, + "The cost of using the scrapper to remove armor trim", false, false), + + /** + * The setting for the netherite salvage cost + */ + NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15, + "The cost of using the scrapper to remove netherite from an item", false, false), /** * Whether to display exact time in minutes and seconds when displaying a remaining cool-down */ SHOW_EXACT_TIME("showExactTime", SettingValueType.BOOLEAN, "false", "Exact time displays the " + - "exact number of seconds and minutes remaining as part of the scrapping cool-down and scrapping delay " + + "exact number of seconds and minutes remaining as part of the salvaging cool-down and salvaging delay " + "messages, instead of just vaguely hinting at the remaining time.", false, false), /** @@ -263,7 +295,7 @@ public enum ScrapperSetting implements Setting { * @param isPerNPC

Whether this setting is per-NPC or global

* @param isMessage

Whether this option is for an NPC message

*/ - ScrapperSetting(String key, SettingValueType valueType, Object value, + ScrapperSetting(@NotNull String key, @NotNull SettingValueType valueType, @NotNull Object value, @NotNull String description, boolean isPerNPC, boolean isMessage) { if (isPerNPC) { if (isMessage) { @@ -289,32 +321,38 @@ public enum ScrapperSetting implements Setting { } @Override - public @NotNull String getPath() { + @NotNull + public String getPath() { return this.path; } @Override - public @NotNull String getChildPath() { + @NotNull + public String getChildPath() { return this.childPath; } @Override - public @NotNull Object getDefaultValue() { + @NotNull + public Object getDefaultValue() { return this.value; } @Override - public @NotNull String getCommandName() { + @NotNull + public String getCommandName() { return this.commandName; } @Override - public @NotNull SettingValueType getValueType() { + @NotNull + public SettingValueType getValueType() { return this.valueType; } @Override - public @NotNull String getDescription() { + @NotNull + public String getDescription() { return this.description; } diff --git a/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java b/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java index 8d374c4..802cd97 100644 --- a/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java +++ b/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java @@ -1,7 +1,9 @@ package net.knarcraft.blacksmith.manager; import net.knarcraft.blacksmith.BlacksmithPlugin; +import net.knarcraft.blacksmith.config.SalvageMethod; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings; +import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings; import net.knarcraft.blacksmith.util.ItemHelper; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; @@ -54,11 +56,12 @@ public class EconomyManager { /** * Gets whether the given player cannot pay for salvaging an item * - * @param player

The player holding an item

+ * @param player

The player holding an item

+ * @param salvageMethod

The salvage method to check

* @return

Whether the player cannot pay for the salvage

*/ - public static boolean cannotPayForSalvage(@NotNull Player player) { - return economy.getBalance(player) - BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost() < 0; + public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { + return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0; } /** @@ -76,12 +79,27 @@ public class EconomyManager { /** * Gets the human-readable cost of salvaging an item * + * @param salvageMethod

The salvage method to get the cost for

* @return

The formatted cost

*/ @NotNull - public static String formatScrapperCost() { - double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost(); - return economy.format(cost); + public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) { + return economy.format(getSalvageCost(salvageMethod)); + } + + /** + * Gets the cost of salvaging using the specified method + * + * @param salvageMethod

The salvage method to get cost for

+ * @return

The salvage cost

+ */ + private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) { + GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); + return switch (salvageMethod) { + case SALVAGE -> settings.getSalvageCost(); + case NETHERITE -> settings.getNetheriteSalvageCost(); + case ARMOR_TRIM -> settings.getArmorTrimSalvageCost(); + }; } /** @@ -101,10 +119,11 @@ public class EconomyManager { /** * Withdraws the salvaging cost from the given player * - * @param player

The player to withdraw from

+ * @param player

The player to withdraw from

+ * @param salvageMethod

The salvage method to withdraw for

*/ - public static void withdrawScrapper(Player player) { - double cost = BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getCost(); + public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { + double cost = getSalvageCost(salvageMethod); if (cost > 0) { economy.withdrawPlayer(player, cost); } diff --git a/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java index ab20af5..c52d82f 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java @@ -7,7 +7,7 @@ import net.knarcraft.blacksmith.config.Settings; import net.knarcraft.blacksmith.config.TraitSettings; import net.knarcraft.blacksmith.formatting.TimeFormatter; import net.knarcraft.blacksmith.manager.EconomyManager; -import net.knarcraft.blacksmith.util.ItemHelper; +import net.knarcraft.blacksmith.util.SalvageHelper; import net.knarcraft.knarlib.formatting.StringFormatter; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -181,8 +181,8 @@ public abstract class CustomTrait extends Trait { if (isBlacksmith) { EconomyManager.withdrawBlacksmith(player); - } else { - EconomyManager.withdrawScrapper(player); + } else if (this.session instanceof SalvageSession salvageSession) { + EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod); } session.scheduleAction(); @@ -198,7 +198,7 @@ public abstract class CustomTrait extends Trait { //Remove the item from the player's inventory if (!isBlacksmith) { // For scrappers, just reduce the amounts of items, unless the remaining stack is salvaged - int amount = ItemHelper.getRequiredAmountForSalvage(player.getServer(), heldItem); + int amount = SalvageHelper.getRequiredAmountForSalvage(player.getServer(), heldItem); if (amount != heldItem.getAmount()) { heldItem.setAmount(heldItem.getAmount() - amount); playerInventory.setItemInMainHand(heldItem); diff --git a/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java b/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java index c8e6432..4f574e0 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java @@ -69,14 +69,14 @@ public class ReforgeSession extends Session implements Runnable { @Override public boolean isSessionInvalid() { // Prevent player from switching items during session - ItemStack itemInHand = player.getInventory().getItemInMainHand(); + ItemStack itemInHand = this.player.getInventory().getItemInMainHand(); if (!itemToReforge.equals(itemInHand)) { - sendNPCMessage(this.npc, player, config.getItemChangedMessage()); + sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage()); return true; } // The player is unable to pay - if (EconomyManager.cannotPayForHeldItemReforge(player)) { - sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage()); + if (EconomyManager.cannotPayForHeldItemReforge(this.player)) { + sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage()); return true; } return false; @@ -84,9 +84,9 @@ public class ReforgeSession extends Session implements Runnable { @Override protected int getActionDelay() { - if (config.getMaxReforgeDelay() > 0) { + if (this.config.getMaxReforgeDelay() > 0) { //Finish the reforging after a random delay between the max and min - return new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay(); + return new Random().nextInt(this.config.getMaxReforgeDelay()) + this.config.getMinReforgeDelay(); } else { //Finish the salvaging as soon as possible return 0; @@ -98,41 +98,41 @@ public class ReforgeSession extends Session implements Runnable { */ @Override public void run() { - sendNPCMessage(this.npc, player, reforgeItem() ? config.getSuccessMessage() : config.getFailMessage()); + sendNPCMessage(this.npc, this.player, reforgeItem() ? this.config.getSuccessMessage() : this.config.getFailMessage()); //Stop the reforged item from displaying in the blacksmith's hand - if (npc.getEntity() instanceof Player) { - ((Player) npc.getEntity()).getInventory().setItemInMainHand(null); + if (this.npc.getEntity() instanceof Player) { + ((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null); } else { - Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null); + Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null); } //Give the item back to the player giveReforgedItem(); //Mark this blacksmith as available - blacksmithTrait.unsetSession(); + this.blacksmithTrait.unsetSession(); // Start cool-down Calendar wait = Calendar.getInstance(); - wait.add(Calendar.SECOND, config.getReforgeCoolDown()); - blacksmithTrait.addCoolDown(player.getUniqueId(), wait); + wait.add(Calendar.SECOND, this.config.getReforgeCoolDown()); + this.blacksmithTrait.addCoolDown(this.player.getUniqueId(), wait); } /** * Gives the reforged item back to the player */ private void giveReforgedItem() { - if (config.getMaxReforgeDelay() > 0) { + if (this.config.getMaxReforgeDelay() > 0) { //If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing - if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) { - player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge); + if (this.config.getDropItem() || !this.player.isOnline() || this.player.getInventory().firstEmpty() == -1) { + this.player.getWorld().dropItemNaturally(this.npc.getEntity().getLocation(), this.itemToReforge); } else { - player.getInventory().addItem(itemToReforge); + this.player.getInventory().addItem(this.itemToReforge); } } else { //It can be assumed as this happens instantly, that the player still has the item's previous slot selected - player.getInventory().setItemInMainHand(itemToReforge); + this.player.getInventory().setItemInMainHand(this.itemToReforge); } } @@ -142,7 +142,7 @@ public class ReforgeSession extends Session implements Runnable { * @return

Whether the reforge was successful. False if the blacksmith failed to fully repair the item.

*/ private boolean reforgeItem() { - if (random.nextInt(100) < config.getFailChance()) { + if (random.nextInt(100) < this.config.getFailChance()) { failReforge(); return false; } else { @@ -156,18 +156,18 @@ public class ReforgeSession extends Session implements Runnable { */ private void succeedReforge() { // Remove any damage done to the item - updateDamage(itemToReforge, 0); + updateDamage(this.itemToReforge, 0); //Replace damaged anvils with a normal anvil - if (ItemHelper.isAnvil(itemToReforge.getType(), true)) { - itemToReforge.setType(Material.ANVIL); + if (ItemHelper.isAnvil(this.itemToReforge.getType(), true)) { + this.itemToReforge.setType(Material.ANVIL); } //See if a random roll (0-99) is less than extraEnchantmentChance, and add a random enchantment int roll = random.nextInt(100); - if (roll < config.getExtraEnchantmentChance() && - itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments() && - !ItemHelper.isAnvil(itemToReforge.getType(), false)) { + if (roll < this.config.getExtraEnchantmentChance() && + this.itemToReforge.getEnchantments().keySet().size() < this.config.getMaxEnchantments() && + !ItemHelper.isAnvil(this.itemToReforge.getType(), false)) { addRandomEnchantment(); } } @@ -180,12 +180,12 @@ public class ReforgeSession extends Session implements Runnable { List usableEnchantments = new ArrayList<>(); for (String enchantmentName : enchantments) { Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName); - if (enchantment != null && enchantment.canEnchantItem(itemToReforge)) { + if (enchantment != null && enchantment.canEnchantItem(this.itemToReforge)) { usableEnchantments.add(enchantment); } } //Remove any enchantments in the block list - usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlockList()); + usableEnchantments.removeAll(this.blacksmithTrait.getSettings().getEnchantmentBlockList()); //In case all usable enchantments have been blocked, abort if (usableEnchantments.isEmpty()) { @@ -198,10 +198,10 @@ public class ReforgeSession extends Session implements Runnable { int randomBound = randomEnchantment.getMaxLevel() + 1; //A workaround for the random method's bound sometimes being negative if (randomBound >= 0) { - int existingLevel = itemToReforge.getEnchantmentLevel(randomEnchantment); + int existingLevel = this.itemToReforge.getEnchantmentLevel(randomEnchantment); /* Add a random enchantment whose level is no lower than the start level, and no lower than the existing level (to prevent making the item worse) */ - itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound), + this.itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound), randomEnchantment.getStartLevel()), existingLevel)); } } @@ -211,20 +211,20 @@ public class ReforgeSession extends Session implements Runnable { * The method to run when a blacksmith fails re-forging an item */ private void failReforge() { - if (config.getFailRemovesEnchantments()) { + if (this.config.getFailRemovesEnchantments()) { removeOrDowngradeEnchantments(); } //Damage the item - short currentItemDurability = ItemHelper.getDurability(itemToReforge); + short currentItemDurability = ItemHelper.getDurability(this.itemToReforge); short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8))); - short maxDurability = itemToReforge.getType().getMaxDurability(); + short maxDurability = this.itemToReforge.getType().getMaxDurability(); if (newDurability <= 0) { newDurability = (short) (maxDurability / 3); } else if (currentItemDurability + newDurability > maxDurability) { newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25)); } - updateDamage(itemToReforge, maxDurability - newDurability); + updateDamage(this.itemToReforge, maxDurability - newDurability); } /** @@ -232,13 +232,13 @@ public class ReforgeSession extends Session implements Runnable { */ private void removeOrDowngradeEnchantments() { //Remove or downgrade existing enchantments - for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) { + for (Enchantment enchantment : this.itemToReforge.getEnchantments().keySet()) { //Completely remove the enchantment, downgrade it, or keep it if lucky and already level 1 if (random.nextBoolean()) { - itemToReforge.removeEnchantment(enchantment); - } else if (itemToReforge.getEnchantmentLevel(enchantment) > 1) { - itemToReforge.removeEnchantment(enchantment); - itemToReforge.addEnchantment(enchantment, 1); + this.itemToReforge.removeEnchantment(enchantment); + } else if (this.itemToReforge.getEnchantmentLevel(enchantment) > 1) { + this.itemToReforge.removeEnchantment(enchantment); + this.itemToReforge.addEnchantment(enchantment, 1); } } } diff --git a/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java b/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java index 210c70e..d17837a 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java @@ -1,6 +1,7 @@ package net.knarcraft.blacksmith.trait; import net.citizensnpcs.api.npc.NPC; +import net.knarcraft.blacksmith.config.SalvageMethod; import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; import net.knarcraft.blacksmith.manager.EconomyManager; import net.knarcraft.blacksmith.util.ItemHelper; @@ -30,6 +31,7 @@ public class SalvageSession extends Session implements Runnable { private final ScrapperNPCSettings config; private final List salvage; private final int enchantmentLevels; + protected final SalvageMethod salvageMethod; private static final Random random = new Random(); /** @@ -39,9 +41,11 @@ public class SalvageSession extends Session implements Runnable { * @param player

The player initiating the session

* @param npc

The scrapper NPC involved in the session

* @param config

The config to use for the session

+ * @param salvageMethod

The salvage method performed in this session

*/ SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc, - @NotNull ScrapperNPCSettings config, @NotNull List salvage) { + @NotNull ScrapperNPCSettings config, @NotNull List salvage, + @NotNull SalvageMethod salvageMethod) { super(player); this.scrapperTrait = scrapperTrait; this.npc = npc; @@ -49,19 +53,20 @@ public class SalvageSession extends Session implements Runnable { this.config = config; this.salvage = salvage; this.enchantmentLevels = SalvageHelper.getTotalEnchantmentLevels(this.itemToSalvage); + this.salvageMethod = salvageMethod; } @Override public boolean isSessionInvalid() { // Prevent player from switching items during session - ItemStack itemInHand = player.getInventory().getItemInMainHand(); + ItemStack itemInHand = this.player.getInventory().getItemInMainHand(); if (!itemToSalvage.equals(itemInHand)) { - sendNPCMessage(this.npc, player, config.getItemChangedMessage()); + sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage()); return true; } - if (EconomyManager.cannotPayForSalvage(player)) { - sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage()); + if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) { + sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage()); return true; } return false; @@ -69,9 +74,9 @@ public class SalvageSession extends Session implements Runnable { @Override protected int getActionDelay() { - if (config.getMaxSalvageDelay() > 0) { + if (this.config.getMaxSalvageDelay() > 0) { //Finish the salvaging after a random delay between the max and min - return new Random().nextInt(config.getMaxSalvageDelay()) + config.getMinSalvageDelay(); + return new Random().nextInt(this.config.getMaxSalvageDelay()) + this.config.getMinSalvageDelay(); } else { //Finish the salvaging as soon as possible return 0; @@ -83,22 +88,22 @@ public class SalvageSession extends Session implements Runnable { */ @Override public void run() { - sendNPCMessage(this.npc, player, salvageItem() ? config.getSuccessMessage() : config.getFailMessage()); + sendNPCMessage(this.npc, this.player, salvageItem() ? this.config.getSuccessMessage() : this.config.getFailMessage()); //Stop the reforged item from displaying in the scrapper's hand - if (npc.getEntity() instanceof Player) { - ((Player) npc.getEntity()).getInventory().setItemInMainHand(null); + if (this.npc.getEntity() instanceof Player) { + ((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null); } else { - Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null); + Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null); } //Mark this scrapper as available - scrapperTrait.unsetSession(); + this.scrapperTrait.unsetSession(); // Start cool-down Calendar wait = Calendar.getInstance(); - wait.add(Calendar.SECOND, config.getSalvageCoolDown()); - scrapperTrait.addCoolDown(player.getUniqueId(), wait); + wait.add(Calendar.SECOND, this.config.getSalvageCoolDown()); + this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait); } /** @@ -107,7 +112,7 @@ public class SalvageSession extends Session implements Runnable { * @return

True if the salvage was successful. False otherwise.

*/ private boolean salvageItem() { - if (random.nextInt(100) < config.getFailChance()) { + if (random.nextInt(100) < this.config.getFailChance()) { failSalvage(); return false; } else { @@ -121,19 +126,19 @@ public class SalvageSession extends Session implements Runnable { * The method to run when a crapper fails salvaging an item */ private void failSalvage() { - if (itemToSalvage.getItemMeta() instanceof Damageable) { + if (this.itemToSalvage.getItemMeta() instanceof Damageable) { //Damage the item - short currentItemDurability = ItemHelper.getDurability(itemToSalvage); + short currentItemDurability = ItemHelper.getDurability(this.itemToSalvage); short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8))); - short maxDurability = itemToSalvage.getType().getMaxDurability(); + short maxDurability = this.itemToSalvage.getType().getMaxDurability(); if (newDurability <= 0) { newDurability = (short) (maxDurability / 3); } else if (currentItemDurability + newDurability > maxDurability) { newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25)); } - updateDamage(itemToSalvage, maxDurability - newDurability); + updateDamage(this.itemToSalvage, maxDurability - newDurability); } else { - itemToSalvage.setAmount(Math.max(itemToSalvage.getAmount() - 1, 1)); + this.itemToSalvage.setAmount(Math.max(this.itemToSalvage.getAmount() - 1, 1)); } } @@ -143,20 +148,20 @@ public class SalvageSession extends Session implements Runnable { private void giveSalvage() { // TODO: Find a better calculation than 1 enchantment level = 1 exp level // Gives the player back some of the EXP used on an item - player.giveExpLevels(enchantmentLevels); - if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) { + this.player.giveExpLevels(this.enchantmentLevels); + if (this.config.getDropItem() || !this.player.isOnline() || this.player.getInventory().firstEmpty() == -1) { // If the player isn't online, or the player cannot fit the item, drop the item to prevent it from // disappearing, even if drop item is disabled. - for (ItemStack item : salvage) { - player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), item); + for (ItemStack item : this.salvage) { + this.player.getWorld().dropItemNaturally(this.npc.getEntity().getLocation(), item); } } else { - for (ItemStack item : salvage) { - if (ItemHelper.canFitItem(player.getInventory(), item)) { - player.getInventory().addItem(item); + for (ItemStack item : this.salvage) { + if (ItemHelper.canFitItem(this.player.getInventory(), item)) { + this.player.getInventory().addItem(item); } else { // If the player cannot fit all the salvage, drop it on the ground - player.getWorld().dropItemNaturally(player.getLocation(), item); + this.player.getWorld().dropItemNaturally(this.player.getLocation(), item); } } } diff --git a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java index 068d5fe..e59ff5d 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java @@ -2,15 +2,18 @@ package net.knarcraft.blacksmith.trait; import net.citizensnpcs.api.util.DataKey; import net.knarcraft.blacksmith.BlacksmithPlugin; +import net.knarcraft.blacksmith.config.SalvageMethod; +import net.knarcraft.blacksmith.config.SmithPreset; +import net.knarcraft.blacksmith.config.SmithPresetFilter; import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting; import net.knarcraft.blacksmith.manager.EconomyManager; import net.knarcraft.blacksmith.util.ItemHelper; import net.knarcraft.blacksmith.util.SalvageHelper; import net.knarcraft.knarlib.formatting.StringFormatter; +import net.knarcraft.knarlib.formatting.StringReplacer; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.Server; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -82,7 +85,7 @@ public class ScrapperTrait extends CustomTrait { boolean extended = getSettings().extendedSalvageEnabled(); // Check if the item can be salvaged - if (!canBeSalvaged(player.getServer(), itemInHand, salvageAbleItems, extended)) { + if (!canBeSalvaged(itemInHand, salvageAbleItems, extended)) { sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), "{title}", getSettings().getScrapperTitle())); return; @@ -91,18 +94,35 @@ public class ScrapperTrait extends CustomTrait { List salvage = null; // Deal with armor trim salvage - boolean salvagingArmorTrim = false; + SalvageMethod salvageMethod = SalvageMethod.SALVAGE; if (itemInHand.getItemMeta() instanceof ArmorMeta armorMeta && armorMeta.hasTrim()) { if (!getSettings().salvageArmorTrims()) { sendNPCMessage(this.npc, player, getSettings().getCannotSalvageArmorTrimMessage()); return; } - salvage = SalvageHelper.getTrimSalvage(itemInHand, armorMeta); + salvage = SalvageHelper.getArmorTrimSalvage(itemInHand, armorMeta); if (salvage == null) { sendNPCMessage(this.npc, player, getSettings().getArmorTrimSalvageNotFoundMessage()); return; } - salvagingArmorTrim = true; + salvageMethod = SalvageMethod.ARMOR_TRIM; + } + + // Remove the netherite ingot from the item + if (salvage == null && SmithPreset.BLACKSMITH.getFilteredMaterials(SmithPresetFilter.NETHERITE).contains(itemInHand.getType())) { + if (!getSettings().salvageNetherite()) { + sendNPCMessage(this.npc, player, getSettings().getCannotSalvageNetheriteMessage()); + return; + } + + salvage = SalvageHelper.getNetheriteSalvage(itemInHand); + salvageMethod = SalvageMethod.NETHERITE; + } + + // As there is no recipe for netherite items, the check needs to be after the netherite salvage check + if (salvageMethod == SalvageMethod.SALVAGE && !SalvageHelper.isSalvageable(player.getServer(), itemInHand)) { + sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getInvalidItemMessage(), + "{title}", getSettings().getScrapperTitle())); } // Check if the item is enchanted, and whether this blacksmith can salvage it @@ -121,26 +141,53 @@ public class ScrapperTrait extends CustomTrait { return; } + //Start a new scrapper session for the player + startSession(player, salvage, salvageMethod); + // Print the cost to the player + printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(salvageMethod), salvageMethod); + } + + /** + * Prints a message to the given player, explaining the cost of salvaging the held item + * + * @param player

The player that interacted with the scrapper

+ * @param itemInHand

The item the player wants to salvage

+ * @param cost

The cost of salvaging the item

+ * @param salvageMethod

The type of salvage performed

+ */ + private void printCostMessage(@NotNull Player player, @NotNull ItemStack itemInHand, @NotNull String cost, + @NotNull SalvageMethod salvageMethod) { + StringReplacer replacer = new StringReplacer(); + replacer.add("{cost}", cost); + replacer.add("{item}", itemInHand.getType().name().toLowerCase().replace('_', ' ')); + if (salvageMethod == SalvageMethod.ARMOR_TRIM) { + sendNPCMessage(this.npc, player, replacer.replace(getSettings().getArmorTrimCostMessage())); + } else if (salvageMethod == SalvageMethod.SALVAGE) { + String expectedYield; + if (ItemHelper.getDamage(itemInHand) <= 0) { + expectedYield = getSettings().getFullSalvageMessage(); + } else { + expectedYield = getSettings().getPartialSalvageMessage(); + } + replacer.add("{yield}", expectedYield); + sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage())); + } else if (salvageMethod == SalvageMethod.NETHERITE) { + sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage())); + } + } + + /** + * Starts a new scrapper session + * + * @param player

The player to start the session for

+ * @param salvage

The salvage to return to the player

+ * @param salvageMethod

The type of salvage performed

+ */ + private void startSession(@NotNull Player player, @NotNull List salvage, + @NotNull SalvageMethod salvageMethod) { //Start a new scrapper session for the player currentSessionStartTime = System.currentTimeMillis(); - session = new SalvageSession(this, player, npc, getSettings(), salvage); - //Tell the player the cost of repairing the item - String cost = EconomyManager.formatScrapperCost(); - - String expectedYield; - if (ItemHelper.getDamage(itemInHand) <= 0) { - expectedYield = getSettings().getFullSalvageMessage(); - } else { - expectedYield = getSettings().getPartialSalvageMessage(); - } - - if (salvagingArmorTrim) { - sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholder(getSettings().getArmorTrimCostMessage(), - "{cost}", cost)); - } else { - sendNPCMessage(this.npc, player, StringFormatter.replacePlaceholders(getSettings().getCostMessage(), - List.of("{cost}", "{yield}"), List.of(cost, expectedYield))); - } + session = new SalvageSession(this, player, npc, getSettings(), salvage, salvageMethod); } @Override @@ -151,17 +198,14 @@ public class ScrapperTrait extends CustomTrait { /** * Gets whether this scrapper can salvage the given item * - * @param server

The server to get recipes from

* @param item

The item to check

* @param salvageAbleItems

The items this scrapper can salvage

* @param extended

Whether extended salvage is enabled

* @return

True if the item can be theoretically salvaged

*/ - private boolean canBeSalvaged(@NotNull Server server, @NotNull ItemStack item, - @NotNull List salvageAbleItems, boolean extended) { - return (extended || ItemHelper.isRepairable(item)) && ItemHelper.isSalvageable(server, item) && - (salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())) && - SalvageHelper.hasRecipe(item); + private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List salvageAbleItems, boolean extended) { + return (extended || ItemHelper.isRepairable(item)) && + (salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())); } /** diff --git a/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java b/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java index 395d418..7960265 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java @@ -110,6 +110,7 @@ public final class ConfigHelper { /** * Changes all configuration values from the old name to the new name * + * @param dataFolderPath

The path to this plugin's data

* @param currentConfiguration

The current config to back up

*/ public static void migrateConfig(@NotNull String dataFolderPath, @NotNull FileConfiguration currentConfiguration) { diff --git a/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java b/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java index b36a2da..ff8f360 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/ItemHelper.java @@ -3,11 +3,8 @@ package net.knarcraft.blacksmith.util; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.SmithPreset; import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.inventory.CraftingRecipe; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; @@ -168,40 +165,6 @@ public final class ItemHelper { return false; } - /** - * Checks whether the given item can be salvaged, assuming no restrictions apply - * - * @param server

The server to get recipes from

- * @param item

The item to check

- * @return

True if the item can be salvaged

- */ - public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) { - for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { - // Only crafting recipes are allowed. - if ((recipe instanceof CraftingRecipe) && item.getAmount() >= recipe.getResult().getAmount()) { - return true; - } - } - return false; - } - - /** - * Gets the amount of an item that's required to salvage that item - * - * @param server

The server to get recipes from

- * @param item

The item to check

- * @return

The number of items required for salvage, or -1 if the recipe was not found

- */ - public static int getRequiredAmountForSalvage(@NotNull Server server, @NotNull ItemStack item) { - for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { - // Only crafting recipes are allowed. - if (recipe instanceof CraftingRecipe) { - return recipe.getResult().getAmount(); - } - } - return -1; - } - /** * Gets all materials matching the given material wildcard * diff --git a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java index 37eced8..71ad1bd 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/SalvageHelper.java @@ -1,6 +1,5 @@ package net.knarcraft.blacksmith.util; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.enchantments.Enchantment; @@ -43,6 +42,29 @@ public final class SalvageHelper { trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE); } + /** + * Gets salvage for a given netherite item + * + * @param item

The netherite armor/tool to salvage

+ * @return

+ */ + @Nullable + public static List getNetheriteSalvage(@NotNull ItemStack item) { + Material newMaterial = Material.matchMaterial(item.getType().name().replace("NETHERITE", "DIAMOND")); + if (newMaterial == null) { + return null; + } + ItemStack clone = item.clone(); + clone.setType(newMaterial); + + List salvage = new ArrayList<>(); + salvage.add(clone); + salvage.add(new ItemStack(Material.NETHERITE_INGOT, 1)); + salvage.add(new ItemStack(Material.NETHERITE_UPGRADE_SMITHING_TEMPLATE, 1)); + + return salvage; + } + /** * Gets salvage for the given armor trim * @@ -51,7 +73,7 @@ public final class SalvageHelper { * @return

The salvage, or null if salvage could not be calculated

*/ @Nullable - public static List getTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) { + public static List getArmorTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) { ArmorTrim armorTrim = armorMeta.getTrim(); if (armorTrim == null) { return null; @@ -82,22 +104,41 @@ public final class SalvageHelper { } /** - * Gets whether the given item has a valid crafting recipe + * Checks whether the given item can be salvaged, assuming no restrictions apply * - * @param item

The item to check

- * @return

True if the item has a valid crafting recipe

+ * @param server

The server to get recipes from

+ * @param item

The item to check

+ * @return

True if the item can be salvaged

*/ - public static boolean hasRecipe(@NotNull ItemStack item) { - List recipes = Bukkit.getRecipesFor(new ItemStack(item.getType(), item.getAmount())); + public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) { + List recipes = server.getRecipesFor(new ItemStack(item.getType(), item.getAmount())); for (Recipe recipe : recipes) { - if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) { + // Only crafting recipes are allowed. + if ((recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) && + item.getAmount() >= recipe.getResult().getAmount()) { return true; } } - return false; } + /** + * Gets the amount of an item that's required to salvage that item + * + * @param server

The server to get recipes from

+ * @param item

The item to check

+ * @return

The number of items required for salvage, or -1 if the recipe was not found

+ */ + public static int getRequiredAmountForSalvage(@NotNull Server server, @NotNull ItemStack item) { + for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { + // Only crafting recipes are allowed. + if (recipe instanceof ShapedRecipe || recipe instanceof ShapelessRecipe) { + return recipe.getResult().getAmount(); + } + } + return 1; + } + /** * Gets the sum of all enchantment levels for the given item * diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b3795b0..ac96af8 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -116,8 +116,8 @@ blacksmith: scrapper: # The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command global: - # Exact time displays the exact number of seconds and minutes remaining as part of the scrapping cool-down and - # scrapping delay messages, instead of just vaguely hinting at the remaining time. + # Exact time displays the exact number of seconds and minutes remaining as part of the salvaging cool-down and + # salvaging delay messages, instead of just vaguely hinting at the remaining time. showExactTime: false # Whether enchanted salvaged items should return some amount of exp upon salvage @@ -130,14 +130,20 @@ scrapper: trashSalvage: - "*_SHOVEL;*_PICKAXE;*_AXE;*_HOE;*_SWORD;SHIELD;*_BOW:STICK" - # The cost of using the scrapper - basePrice: 0 + # The cost of using a scrapper to salvage an item + salvagePrice: 0 + + # The cost of using the scrapper to remove armor trim + armorTrimSalvagePrice: 5 + + # The cost of using the scrapper to remove netherite from an item + netheriteSalvagePrice: 15 # The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must # change the Citizens NPC file, or use the /scrapper command defaults: - # Whether the item will drop materials resulting from scrapping on the ground, instead of putting them into the user's inventory + # Whether the item will drop materials resulting from salvaging on the ground, instead of putting them into the user's inventory dropItem: true # The chance to fail a salvage, thus destroying the item (0-100) @@ -170,6 +176,9 @@ scrapper: # Whether to enable salvaging of armor trims salvageArmorTrims: true + # Whether to enable salvaging of netherite items + salvageNetherite: true + # Default values for messages used by NPCs messages: # The message to display when another player is using the scrapper @@ -203,10 +212,13 @@ scrapper: insufficientFundsMessage: "&cYou don't have enough money to salvage an item!" # The message to display when explaining the shown item's salvage cost - costMessage: "&eIt will cost &a{cost}&e to salvage that item! {yield} &eClick again to salvage!" + costMessage: "&eIt will cost &a{cost}&e to salvage that &a{item}&e! {yield} &eClick again to salvage!" # The message to display when explaining the shown item's armor trim's salvage cost - costMessageArmorTrim: "&eIt will cost &a{cost}&e to salvage that armor trim!" + costMessageArmorTrim: "&eIt will cost &a{cost}&e to salvage that &a{item}&e's armor trim!" + + # The message to display when explaining the shown item's netherite salvage cost + costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!" # The yield message to display if trying to salvage a non-damaged item fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r" @@ -221,4 +233,7 @@ scrapper: cannotSalvageArmorTrimMessage: "&cI'm sorry, but I'm unable to salvage armor trims!" # The message to display if the correct materials to return for the armor trim are unknown - armorTrimSalvageNotFoundMessage: "&cI'm sorry, but I don't know how to salvage that armor trim!" \ No newline at end of file + armorTrimSalvageNotFoundMessage: "&cI'm sorry, but I don't know how to salvage that armor trim!" + + # The message to display when asked to salvage netherite items, and that option is disabled + cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!" \ No newline at end of file