Implements netherite salvaging #24
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	EpicKnarvik97/Blacksmith/pipeline/head This commit looks good
				
			This commit is contained in:
		
							
								
								
									
										24
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								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) | ||||
| @@ -213,8 +217,10 @@ 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.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              | | ||||
| |-----------------------|------------------------------------------------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||
| | 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`. | | ||||
| @@ -234,12 +240,13 @@ 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.               | | ||||
| @@ -249,13 +256,16 @@ All currently supported presets, and available filters for each preset: | ||||
| | 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.                                             | | ||||
| | 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. | | ||||
| | 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 | ||||
|  | ||||
|   | ||||
| @@ -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, | ||||
|  | ||||
| } | ||||
| @@ -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) | ||||
|   | ||||
| @@ -34,7 +34,7 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> { | ||||
|      * | ||||
|      * @param instance <p>A reference to the blacksmith plugin</p> | ||||
|      */ | ||||
|     public GlobalScrapperSettings(BlacksmithPlugin instance) { | ||||
|     public GlobalScrapperSettings(@NotNull BlacksmithPlugin instance) { | ||||
|         this.instance = instance; | ||||
|     } | ||||
|  | ||||
| @@ -78,7 +78,8 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> { | ||||
|      * @param scrapperSetting <p>The setting to get</p> | ||||
|      * @return <p>The current raw setting value</p> | ||||
|      */ | ||||
|     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<ScrapperSetting> { | ||||
|      * | ||||
|      * @return <p>The current value of the default NPC settings</p> | ||||
|      */ | ||||
|     @NotNull | ||||
|     public Map<ScrapperSetting, Object> getDefaultNPCSettings() { | ||||
|         return new HashMap<>(this.settings); | ||||
|     } | ||||
| @@ -108,10 +110,22 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> { | ||||
|      * @param setting <p>The setting to get the value of</p> | ||||
|      * @return <p>The value of the given setting as a boolean</p> | ||||
|      */ | ||||
|     public boolean asBoolean(ScrapperSetting setting) { | ||||
|     public boolean asBoolean(@NotNull ScrapperSetting setting) { | ||||
|         return ConfigHelper.asBoolean(getValue(setting)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the given value as a double | ||||
|      * | ||||
|      * <p>This will throw an exception if used for a non-double setting</p> | ||||
|      * | ||||
|      * @param setting <p>The setting to get the value of</p> | ||||
|      * @return <p>The value of the given setting as a double</p> | ||||
|      */ | ||||
|     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<ScrapperSetting> { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the cost of using a scrapper | ||||
|      * Gets the cost of using a scrapper to salvage an item | ||||
|      * | ||||
|      * @return <p>The cost of using a scrapper</p> | ||||
|      * @return <p>The cost of using a scrapper to salvage an item</p> | ||||
|      */ | ||||
|     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 <p>The cost of using a scrapper to remove armor trim</p> | ||||
|      */ | ||||
|     public double getArmorTrimSalvageCost() { | ||||
|         return asDouble(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the cost of using a scrapper to remove netherite from an item | ||||
|      * | ||||
|      * @return <p>The cost of using a scrapper to remove netherite from an item</p> | ||||
|      */ | ||||
|     public double getNetheriteSalvageCost() { | ||||
|         return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -151,6 +151,16 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> { | ||||
|         return asString(ScrapperSetting.COST_MESSAGE_ARMOR_TRIM); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the message to use for displaying netherite salvage cost | ||||
|      * | ||||
|      * @return <p>The message to use for displaying netherite salvage cost</p> | ||||
|      */ | ||||
|     @NotNull | ||||
|     public String getNetheriteCostMessage() { | ||||
|         return asString(ScrapperSetting.COST_MESSAGE_NETHERITE); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @NotNull | ||||
|     public String getCoolDownUnexpiredMessage() { | ||||
| @@ -316,6 +326,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> { | ||||
|         return asBoolean(ScrapperSetting.SALVAGE_ARMOR_TRIMS); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Whether salvage of netherite items is enabled | ||||
|      * | ||||
|      * @return <p>True if this scrapper can salvage netherite items</p> | ||||
|      */ | ||||
|     public boolean salvageNetherite() { | ||||
|         return asBoolean(ScrapperSetting.SALVAGE_NETHERITE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the title of this scrapper NPC | ||||
|      * | ||||
| @@ -415,4 +434,14 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> { | ||||
|         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 <p>The message to display when explaining that this scrapper is unable to salvage netherite items</p> | ||||
|      */ | ||||
|     @NotNull | ||||
|     public String getCannotSalvageNetheriteMessage() { | ||||
|         return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ public enum ScrapperSetting implements Setting { | ||||
|      * <p>If set to false, the item will be directly put in the player's inventory instead</p> | ||||
|      */ | ||||
|     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), | ||||
|  | ||||
|     /** | ||||
| @@ -86,6 +86,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    <p>Whether this setting is per-NPC or global</p> | ||||
|      * @param isMessage   <p>Whether this option is for an NPC message</p> | ||||
|      */ | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| @@ -55,10 +57,11 @@ public class EconomyManager { | ||||
|      * Gets whether the given player cannot pay for salvaging an item | ||||
|      * | ||||
|      * @param player        <p>The player holding an item</p> | ||||
|      * @param salvageMethod <p>The salvage method to check</p> | ||||
|      * @return <p>Whether the player cannot pay for the salvage</p> | ||||
|      */ | ||||
|     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 <p>The salvage method to get the cost for</p> | ||||
|      * @return <p>The formatted cost</p> | ||||
|      */ | ||||
|     @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 <p>The salvage method to get cost for</p> | ||||
|      * @return <p>The salvage cost</p> | ||||
|      */ | ||||
|     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(); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -102,9 +120,10 @@ public class EconomyManager { | ||||
|      * Withdraws the salvaging cost from the given player | ||||
|      * | ||||
|      * @param player        <p>The player to withdraw from</p> | ||||
|      * @param salvageMethod <p>The salvage method to withdraw for</p> | ||||
|      */ | ||||
|     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); | ||||
|         } | ||||
|   | ||||
| @@ -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<K extends Setting> 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<K extends Setting> 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); | ||||
|   | ||||
| @@ -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 <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p> | ||||
|      */ | ||||
|     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<Enchantment> 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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<ItemStack> 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        <p>The player initiating the session</p> | ||||
|      * @param npc           <p>The scrapper NPC involved in the session</p> | ||||
|      * @param config        <p>The config to use for the session</p> | ||||
|      * @param salvageMethod <p>The salvage method performed in this session</p> | ||||
|      */ | ||||
|     SalvageSession(@NotNull ScrapperTrait scrapperTrait, @NotNull Player player, @NotNull NPC npc, | ||||
|                    @NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> salvage) { | ||||
|                    @NotNull ScrapperNPCSettings config, @NotNull List<ItemStack> 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 <p>True if the salvage was successful. False otherwise.</p> | ||||
|      */ | ||||
|     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); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -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<ScrapperSetting> { | ||||
|         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<ScrapperSetting> { | ||||
|         List<ItemStack> 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 | ||||
| @@ -122,27 +142,54 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | ||||
|         } | ||||
|  | ||||
|         //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(); | ||||
|         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        <p>The player that interacted with the scrapper</p> | ||||
|      * @param itemInHand    <p>The item the player wants to salvage</p> | ||||
|      * @param cost          <p>The cost of salvaging the item</p> | ||||
|      * @param salvageMethod <p>The type of salvage performed</p> | ||||
|      */ | ||||
|     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(); | ||||
|             } | ||||
|  | ||||
|         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))); | ||||
|             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        <p>The player to start the session for</p> | ||||
|      * @param salvage       <p>The salvage to return to the player</p> | ||||
|      * @param salvageMethod <p>The type of salvage performed</p> | ||||
|      */ | ||||
|     private void startSession(@NotNull Player player, @NotNull List<ItemStack> salvage, | ||||
|                               @NotNull SalvageMethod salvageMethod) { | ||||
|         //Start a new scrapper session for the player | ||||
|         currentSessionStartTime = System.currentTimeMillis(); | ||||
|         session = new SalvageSession(this, player, npc, getSettings(), salvage, salvageMethod); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected boolean showExactTime() { | ||||
|         return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime(); | ||||
| @@ -151,17 +198,14 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> { | ||||
|     /** | ||||
|      * Gets whether this scrapper can salvage the given item | ||||
|      * | ||||
|      * @param server           <p>The server to get recipes from</p> | ||||
|      * @param item             <p>The item to check</p> | ||||
|      * @param salvageAbleItems <p>The items this scrapper can salvage</p> | ||||
|      * @param extended         <p>Whether extended salvage is enabled</p> | ||||
|      * @return <p>True if the item can be theoretically salvaged</p> | ||||
|      */ | ||||
|     private boolean canBeSalvaged(@NotNull Server server, @NotNull ItemStack item, | ||||
|                                   @NotNull List<Material> 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<Material> salvageAbleItems, boolean extended) { | ||||
|         return (extended || ItemHelper.isRepairable(item)) && | ||||
|                 (salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -110,6 +110,7 @@ public final class ConfigHelper { | ||||
|     /** | ||||
|      * Changes all configuration values from the old name to the new name | ||||
|      * | ||||
|      * @param dataFolderPath       <p>The path to this plugin's data</p> | ||||
|      * @param currentConfiguration <p>The current config to back up</p> | ||||
|      */ | ||||
|     public static void migrateConfig(@NotNull String dataFolderPath, @NotNull FileConfiguration currentConfiguration) { | ||||
|   | ||||
| @@ -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 <p>The server to get recipes from</p> | ||||
|      * @param item   <p>The item to check</p> | ||||
|      * @return <p>True if the item can be salvaged</p> | ||||
|      */ | ||||
|     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 <p>The server to get recipes from</p> | ||||
|      * @param item   <p>The item to check</p> | ||||
|      * @return <p>The number of items required for salvage, or -1 if the recipe was not found</p> | ||||
|      */ | ||||
|     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 | ||||
|      * | ||||
|   | ||||
| @@ -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 <p>The netherite armor/tool to salvage</p> | ||||
|      * @return <p></p> | ||||
|      */ | ||||
|     @Nullable | ||||
|     public static List<ItemStack> 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<ItemStack> 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 <p>The salvage, or null if salvage could not be calculated</p> | ||||
|      */ | ||||
|     @Nullable | ||||
|     public static List<ItemStack> getTrimSalvage(@NotNull ItemStack item, @NotNull ArmorMeta armorMeta) { | ||||
|     public static List<ItemStack> 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 server <p>The server to get recipes from</p> | ||||
|      * @param item   <p>The item to check</p> | ||||
|      * @return <p>True if the item has a valid crafting recipe</p> | ||||
|      * @return <p>True if the item can be salvaged</p> | ||||
|      */ | ||||
|     public static boolean hasRecipe(@NotNull ItemStack item) { | ||||
|         List<Recipe> recipes = Bukkit.getRecipesFor(new ItemStack(item.getType(), item.getAmount())); | ||||
|     public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) { | ||||
|         List<Recipe> 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 <p>The server to get recipes from</p> | ||||
|      * @param item   <p>The item to check</p> | ||||
|      * @return <p>The number of items required for salvage, or -1 if the recipe was not found</p> | ||||
|      */ | ||||
|     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 | ||||
|      * | ||||
|   | ||||
| @@ -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" | ||||
| @@ -222,3 +234,6 @@ scrapper: | ||||
|        | ||||
|       # 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!" | ||||
|        | ||||
|       # 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!" | ||||
		Reference in New Issue
	
	Block a user