Compare commits
15 Commits
v1.1.1
...
book-split
Author | SHA1 | Date | |
---|---|---|---|
ad5066af4b | |||
42ca42c571 | |||
7e17122bb2 | |||
b01ccfc537 | |||
e3dbeccc14 | |||
90d3c49c12 | |||
f5bfbfd4f8 | |||
d4feda78ae | |||
81e65810e1 | |||
0dab832bfd | |||
1510960089 | |||
cdb0f267a3 | |||
81c15b6600 | |||
5efba6687c | |||
d0df4800f0 |
@ -83,6 +83,11 @@ example planks into wood, four wood will be taken.
|
|||||||
|
|
||||||
When an item is salvaged, EXP will be returned based on enchantments on the item.
|
When an item is salvaged, EXP will be returned based on enchantments on the item.
|
||||||
|
|
||||||
|
Note that sticks are valid items to be handled by Scrappers if extended salvage is enabled. The item is also the default
|
||||||
|
item for selecting NPCs in Citizens. If you find the NPC selection message annoying, and don't normally use sticks for
|
||||||
|
selection, you can change the item in Citizens' config and replace it with STRUCTURE_VOID or some other unobtainable
|
||||||
|
item.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
| Command | Arguments | Description |
|
| Command | Arguments | Description |
|
||||||
@ -230,6 +235,7 @@ All currently supported presets, and available filters for each preset:
|
|||||||
| startReforgeMessage | &eOk, let's see what I can do... | The message displayed when a blacksmith starts reforging an item. |
|
| startReforgeMessage | &eOk, let's see what I can do... | The message displayed when a blacksmith starts reforging an item. |
|
||||||
| successMessage | There you go! All better! | The message displayed when a blacksmith successfully repairs an item. |
|
| successMessage | There you go! All better! | The message displayed when a blacksmith successfully repairs an item. |
|
||||||
| notDamagedMessage | &cThat item is not in need of repair | The message displayed if a player tries to reforge an item with full durability. |
|
| notDamagedMessage | &cThat item is not in need of repair | The message displayed if a player tries to reforge an item with full durability. |
|
||||||
|
| noItemMessage | Please present the item you want to reforge | The message displayed when a blacksmith is clicked with an empty hand |
|
||||||
|
|
||||||
### Scrapper global-only options
|
### Scrapper global-only options
|
||||||
|
|
||||||
@ -284,6 +290,7 @@ All currently supported presets, and available filters for each preset:
|
|||||||
| 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. |
|
| 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. This will happen if more armor trim materials are added, or the Spigot API is changed. |
|
| 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. This will happen if more armor trim materials are added, or the Spigot API is changed. |
|
||||||
| 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. |
|
| 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. |
|
||||||
|
| noItemMessage | Please present the item you want to salvage | The message displayed when a scrapper is clicked with an empty hand |
|
||||||
|
|
||||||
## Language customization
|
## Language customization
|
||||||
|
|
||||||
|
19
pom.xml
19
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>net.knarcraft</groupId>
|
<groupId>net.knarcraft</groupId>
|
||||||
<artifactId>blacksmith</artifactId>
|
<artifactId>blacksmith</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>1.1.3-SNAPSHOT</version>
|
||||||
<name>Blacksmith</name>
|
<name>Blacksmith</name>
|
||||||
<description>Blacksmith NPC for the Citizens API</description>
|
<description>Blacksmith NPC for the Citizens API</description>
|
||||||
|
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.20.6-R0.1-SNAPSHOT</version>
|
<version>1.21.4-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -92,6 +92,11 @@
|
|||||||
<version>5.10.2</version>
|
<version>5.10.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.objecthunter</groupId>
|
||||||
|
<artifactId>exp4j</artifactId>
|
||||||
|
<version>0.4.8</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- Build information -->
|
<!-- Build information -->
|
||||||
@ -127,6 +132,10 @@
|
|||||||
<pattern>org.jetbrains.annotations</pattern>
|
<pattern>org.jetbrains.annotations</pattern>
|
||||||
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
|
<shadedPattern>net.knarcraft.blacksmith.lib.annotations</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>net.objecthunter.exp4j</pattern>
|
||||||
|
<shadedPattern>net.knarcraft.blacksmith.lib.exp4j</shadedPattern>
|
||||||
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
<filters>
|
<filters>
|
||||||
<filter>
|
<filter>
|
||||||
@ -141,6 +150,12 @@
|
|||||||
<include>org/jetbrains/annotations/**</include>
|
<include>org/jetbrains/annotations/**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<artifact>net.objecthunter:exp4j</artifact>
|
||||||
|
<includes>
|
||||||
|
<include>net/objecthunter/exp4j/**</include>
|
||||||
|
</includes>
|
||||||
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -20,6 +20,7 @@ import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
|||||||
import net.knarcraft.blacksmith.listener.NPCClickListener;
|
import net.knarcraft.blacksmith.listener.NPCClickListener;
|
||||||
import net.knarcraft.blacksmith.listener.PlayerListener;
|
import net.knarcraft.blacksmith.listener.PlayerListener;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.manager.PlayerUsageManager;
|
||||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
|
||||||
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
import net.knarcraft.blacksmith.trait.ScrapperTrait;
|
||||||
import net.knarcraft.blacksmith.util.ConfigHelper;
|
import net.knarcraft.blacksmith.util.ConfigHelper;
|
||||||
@ -27,6 +28,7 @@ import net.knarcraft.knarlib.formatting.StringFormatter;
|
|||||||
import net.knarcraft.knarlib.formatting.TranslatableTimeUnit;
|
import net.knarcraft.knarlib.formatting.TranslatableTimeUnit;
|
||||||
import net.knarcraft.knarlib.formatting.Translator;
|
import net.knarcraft.knarlib.formatting.Translator;
|
||||||
import net.knarcraft.knarlib.util.UpdateChecker;
|
import net.knarcraft.knarlib.util.UpdateChecker;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.command.TabCompleter;
|
import org.bukkit.command.TabCompleter;
|
||||||
@ -183,6 +185,10 @@ public class BlacksmithPlugin extends JavaPlugin {
|
|||||||
//Alert about an update in the console
|
//Alert about an update in the console
|
||||||
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=105938",
|
UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=105938",
|
||||||
() -> this.getDescription().getVersion(), null);
|
() -> this.getDescription().getVersion(), null);
|
||||||
|
|
||||||
|
// Remove expired scrapper usage data
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> PlayerUsageManager.removeExpiredData(
|
||||||
|
System.currentTimeMillis() - 3600000), 36000, 36000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
313
src/main/java/net/knarcraft/blacksmith/command/CostCommand.java
Normal file
313
src/main/java/net/knarcraft/blacksmith/command/CostCommand.java
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
package net.knarcraft.blacksmith.command;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.container.ActionCost;
|
||||||
|
import net.knarcraft.blacksmith.formatting.BlacksmithTranslatableMessage;
|
||||||
|
import net.knarcraft.blacksmith.property.CostType;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.permissions.Permission;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
public class CostCommand implements TabExecutor {
|
||||||
|
|
||||||
|
private static List<String> plugins;
|
||||||
|
private static Map<String, List<String>> permissions;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] arguments) {
|
||||||
|
//TODO: Whenever a cost is specified (not for the per-material and per-enchantment costs), allow either a simple
|
||||||
|
// cost or an ActionCost. When loading costs, first try and parse a double. If not, parse an ActionCost object.
|
||||||
|
// TODO: The command should look like "blacksmithEdit <option> <simple|advanced> <double|economy|item|permission|exp>
|
||||||
|
// <double|blank/null|comma-separated-string|integer>"
|
||||||
|
|
||||||
|
if (!(commandSender instanceof Player player)) {
|
||||||
|
commandSender.sendMessage("This command can only be used by players");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Check arguments size
|
||||||
|
if (arguments.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionCost oldCost = new ActionCost(0, 0, null, Set.of());
|
||||||
|
|
||||||
|
ActionCost actionCost;
|
||||||
|
|
||||||
|
switch (arguments[0].toLowerCase()) {
|
||||||
|
case "simple":
|
||||||
|
// TODO: Do something with the cost
|
||||||
|
double cost = parseSimpleCost(commandSender, arguments[1]);
|
||||||
|
break;
|
||||||
|
case "advanced":
|
||||||
|
actionCost = modifyActionCost(arguments, oldCost, player);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
|
||||||
|
@NotNull String s, @NotNull String[] arguments) {
|
||||||
|
if (plugins == null) {
|
||||||
|
loadAvailablePermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.length == 1) {
|
||||||
|
return List.of("simple", "advanced");
|
||||||
|
} else if (arguments.length == 2) {
|
||||||
|
if (arguments[0].equalsIgnoreCase("simple")) {
|
||||||
|
return List.of("");
|
||||||
|
} else {
|
||||||
|
return List.of("add", "set", "clear");
|
||||||
|
}
|
||||||
|
} else if (arguments.length == 3) {
|
||||||
|
if (arguments[0].equalsIgnoreCase("simple")) {
|
||||||
|
return List.of("");
|
||||||
|
} else {
|
||||||
|
return List.of("economy", "item", "exp", "permission");
|
||||||
|
}
|
||||||
|
} else if (arguments.length == 4) {
|
||||||
|
CostType costType = CostType.parse(arguments[2]);
|
||||||
|
if (costType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return switch (costType) {
|
||||||
|
case PERMISSION -> tabCompletePermission(arguments[3]);
|
||||||
|
case ECONOMY -> List.of("0.5", "1", "10");
|
||||||
|
case EXP -> List.of("1, 5, 10");
|
||||||
|
case ITEM -> List.of();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the cost of an action
|
||||||
|
*
|
||||||
|
* @param arguments <p>The arguments given by a player</p>
|
||||||
|
* @param oldCost <p>The previous cost of the action</p>
|
||||||
|
* @param player <p>The player attempting to alter the action cost</p>
|
||||||
|
* @return <p>The modified action cost, or null if something went wrong</p>
|
||||||
|
*/
|
||||||
|
private ActionCost modifyActionCost(@NotNull String[] arguments, @NotNull ActionCost oldCost, @NotNull Player player) {
|
||||||
|
CostType costType;
|
||||||
|
if (arguments.length > 2) {
|
||||||
|
costType = CostType.parse(arguments[2]);
|
||||||
|
} else {
|
||||||
|
costType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (arguments[1].toLowerCase()) {
|
||||||
|
case "add":
|
||||||
|
if (costType == null) {
|
||||||
|
player.sendMessage("Invalid cost type specified!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length), oldCost, player);
|
||||||
|
case "clear":
|
||||||
|
// Clears one or all fields of a cost
|
||||||
|
if (costType == null) {
|
||||||
|
return new ActionCost(0, 0, null, Set.of());
|
||||||
|
} else {
|
||||||
|
return switch (costType) {
|
||||||
|
case EXP -> oldCost.changeExpCost(0);
|
||||||
|
case ITEM -> oldCost.changeItemCost(null);
|
||||||
|
case ECONOMY -> oldCost.changeMonetaryCost(0);
|
||||||
|
case PERMISSION -> oldCost.changePermissionCost(Set.of());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case "set":
|
||||||
|
if (costType == null) {
|
||||||
|
player.sendMessage("Invalid cost type specified!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length),
|
||||||
|
new ActionCost(0, 0, null, Set.of()), player);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an advanced action cost
|
||||||
|
*
|
||||||
|
* @param costType <p>The type of cost to parse</p>
|
||||||
|
* @param arguments <p>The arguments given by the player</p>
|
||||||
|
* @param oldCost <p>The old cost to modify</p>
|
||||||
|
* @param player <p>The player changing the value</p>
|
||||||
|
* @return <p>The new action cost, or null if the process failed.</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ActionCost parseCost(@NotNull CostType costType, @NotNull String[] arguments, @NotNull ActionCost oldCost,
|
||||||
|
@NotNull Player player) {
|
||||||
|
switch (costType) {
|
||||||
|
case ECONOMY:
|
||||||
|
double economyCost = Double.parseDouble(arguments[0]);
|
||||||
|
if (economyCost < 0) {
|
||||||
|
player.sendMessage("Cost cannot be negative!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return oldCost.changeMonetaryCost(economyCost);
|
||||||
|
case ITEM:
|
||||||
|
ItemStack itemCost = player.getInventory().getItemInMainHand();
|
||||||
|
if (itemCost.getType().isAir()) {
|
||||||
|
player.sendMessage("You have no item in your main hand");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return oldCost.changeItemCost(itemCost);
|
||||||
|
case PERMISSION:
|
||||||
|
Set<String> permissionSet = new HashSet<>(Arrays.asList(arguments[0].split(",")));
|
||||||
|
return oldCost.changePermissionCost(permissionSet);
|
||||||
|
case EXP:
|
||||||
|
int expCost = Integer.parseInt(arguments[0]);
|
||||||
|
if (expCost < 0) {
|
||||||
|
player.sendMessage("Exp cost cannot be negative!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return oldCost.changeExpCost(expCost);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a simple double cost
|
||||||
|
*
|
||||||
|
* @param commandSender <p>The command sender to notify of any problems</p>
|
||||||
|
* @param costString <p>The string to parse into a cost</p>
|
||||||
|
* @return <p>The parsed cost</p>
|
||||||
|
* @throws IllegalArgumentException <p>If the specified cost is invalid</p>
|
||||||
|
*/
|
||||||
|
private double parseSimpleCost(@NotNull CommandSender commandSender,
|
||||||
|
@NotNull String costString) throws IllegalArgumentException {
|
||||||
|
try {
|
||||||
|
double cost = Double.parseDouble(costString);
|
||||||
|
if (cost < 0) {
|
||||||
|
throw new NumberFormatException();
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
BlacksmithPlugin.getStringFormatter().displayErrorMessage(commandSender,
|
||||||
|
BlacksmithTranslatableMessage.DOUBLE_COST_REQUIRED);
|
||||||
|
throw new IllegalArgumentException("Invalid cost given");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the tab complete value for the permission typed
|
||||||
|
*
|
||||||
|
* @param typedNode <p>The full permission node typed by the player</p>
|
||||||
|
* @return <p>All known valid auto-complete options</p>
|
||||||
|
*/
|
||||||
|
private @NotNull List<String> tabCompletePermission(@NotNull String typedNode) {
|
||||||
|
StringBuilder permissionListString = new StringBuilder();
|
||||||
|
if (typedNode.contains(",")) {
|
||||||
|
String[] permissionList = typedNode.split(",");
|
||||||
|
for (int i = 0; i < permissionList.length - 1; i++) {
|
||||||
|
permissionListString.append(permissionList[i]);
|
||||||
|
permissionListString.append(",");
|
||||||
|
}
|
||||||
|
typedNode = permissionList[permissionList.length - 1];
|
||||||
|
}
|
||||||
|
String permissionPrefix = permissionListString.toString();
|
||||||
|
List<String> output;
|
||||||
|
if (typedNode.contains(".")) {
|
||||||
|
List<String> matchingPermissions = permissions.get(typedNode.substring(0, typedNode.lastIndexOf(".")));
|
||||||
|
if (matchingPermissions == null) {
|
||||||
|
if (permissionPrefix.isEmpty()) {
|
||||||
|
output = new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
List<String> onlyPrefix = new ArrayList<>();
|
||||||
|
onlyPrefix.add(permissionPrefix);
|
||||||
|
output = onlyPrefix;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Filter by the typed text
|
||||||
|
output = filterMatching(matchingPermissions, typedNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output = plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add previous permissions in the comma-separated lists as a prefix
|
||||||
|
if (permissionPrefix.isEmpty()) {
|
||||||
|
return output;
|
||||||
|
} else {
|
||||||
|
List<String> prefixed = new ArrayList<>(output.size());
|
||||||
|
for (String matchingCompletion : output) {
|
||||||
|
prefixed.add(permissionPrefix + matchingCompletion);
|
||||||
|
}
|
||||||
|
return prefixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find completable strings which match the text typed by the command's sender
|
||||||
|
*
|
||||||
|
* @param values <p>The values to filter</p>
|
||||||
|
* @param typedText <p>The text the player has started typing</p>
|
||||||
|
* @return <p>The given string values which start with the player's typed text</p>
|
||||||
|
*/
|
||||||
|
private @NotNull List<String> filterMatching(@NotNull List<String> values, @NotNull String typedText) {
|
||||||
|
List<String> configValues = new ArrayList<>();
|
||||||
|
for (String value : values) {
|
||||||
|
if (value.toLowerCase().startsWith(typedText.toLowerCase())) {
|
||||||
|
configValues.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all permissions available from bukkit plugins
|
||||||
|
*/
|
||||||
|
private static void loadAvailablePermissions() {
|
||||||
|
plugins = new ArrayList<>();
|
||||||
|
permissions = new HashMap<>();
|
||||||
|
|
||||||
|
for (Permission permission : Bukkit.getPluginManager().getPermissions()) {
|
||||||
|
loadPermission(permission.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a given permission into the proper lists and maps
|
||||||
|
*
|
||||||
|
* @param permissionName <p>The permission to load</p>
|
||||||
|
*/
|
||||||
|
private static void loadPermission(@NotNull String permissionName) {
|
||||||
|
String[] permissionParts = permissionName.split("\\.");
|
||||||
|
if (permissionParts.length == 1 && !plugins.contains(permissionParts[0])) {
|
||||||
|
plugins.add(permissionParts[0]);
|
||||||
|
} else if (permissionParts.length > 1) {
|
||||||
|
StringJoiner pathJoiner = new StringJoiner(".");
|
||||||
|
for (int j = 0; j < permissionParts.length - 1; j++) {
|
||||||
|
pathJoiner.add(permissionParts[j]);
|
||||||
|
}
|
||||||
|
String path = pathJoiner.toString();
|
||||||
|
List<String> permissionList = permissions.computeIfAbsent(path, k -> new ArrayList<>());
|
||||||
|
permissionList.add(permissionName);
|
||||||
|
|
||||||
|
loadPermission(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,4 +55,9 @@ public enum SettingValueType {
|
|||||||
*/
|
*/
|
||||||
ENCHANTMENT_LIST,
|
ENCHANTMENT_LIST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advanced cost, that supports either a simple double, or specifying money cost, permission requirement, exp cost and an item cost
|
||||||
|
*/
|
||||||
|
ADVANCED_COST,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,16 @@ public class BlacksmithNPCSettings implements TraitSettings<BlacksmithSetting> {
|
|||||||
return asString(BlacksmithSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
return asString(BlacksmithSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message displayed if a player presents the blacksmith with an empty hand
|
||||||
|
*
|
||||||
|
* @return <p>The no item message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getNoItemMessage() {
|
||||||
|
return asString(BlacksmithSetting.NO_ITEM_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all items reforge-able by this NPC
|
* Gets all items reforge-able by this NPC
|
||||||
*
|
*
|
||||||
|
@ -186,6 +186,12 @@ public enum BlacksmithSetting implements Setting {
|
|||||||
"The message to display if a player is trying to reforge an item with full durability",
|
"The message to display if a player is trying to reforge an item with full durability",
|
||||||
true, true),
|
true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when clicking a blacksmith with an empty hand
|
||||||
|
*/
|
||||||
|
NO_ITEM_MESSAGE("noItemMessage", SettingValueType.STRING, "Please present the item you want to reforge",
|
||||||
|
"The message to display when a blacksmith is clicked with an empty hand", true, true),
|
||||||
|
|
||||||
/*------------------
|
/*------------------
|
||||||
| Global settings |
|
| Global settings |
|
||||||
------------------*/
|
------------------*/
|
||||||
|
@ -212,6 +212,24 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
|
|||||||
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
|
return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the math formula for the increase in salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The salvage cost increase formula</p>
|
||||||
|
*/
|
||||||
|
public String getSalvageCostIncrease() {
|
||||||
|
return asString(ScrapperSetting.SALVAGE_COST_INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the math formula for the increase in salvage cooldown
|
||||||
|
*
|
||||||
|
* @return <p>The salvage cooldown increase formula</p>
|
||||||
|
*/
|
||||||
|
public String getSalvageCooldownIncrease() {
|
||||||
|
return asString(ScrapperSetting.SALVAGE_COOLDOWN_INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets trash salvage for the given material
|
* Gets trash salvage for the given material
|
||||||
*
|
*
|
||||||
@ -275,4 +293,15 @@ public class GlobalScrapperSettings implements Settings<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string value of the given setting
|
||||||
|
*
|
||||||
|
* @param setting <p>The setting to get the value of</p>
|
||||||
|
* @return <p>The value of the given setting as a string</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private String asString(@NotNull ScrapperSetting setting) {
|
||||||
|
return getValue(setting).toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this scrapper is able to split an enchanted book
|
||||||
|
*
|
||||||
|
* @return <p>True if this scrapper is able to split an enchanted book</p>
|
||||||
|
*/
|
||||||
|
public boolean splitEnchantedBook() {
|
||||||
|
return asBoolean(ScrapperSetting.SPLIT_ENCHANTED_BOOK);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the raw current value of a setting
|
* Gets the raw current value of a setting
|
||||||
*
|
*
|
||||||
@ -171,6 +180,15 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
|
return asString(ScrapperSetting.COST_MESSAGE_NETHERITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to use for displaying enchanted book salvage cost
|
||||||
|
*
|
||||||
|
* @return <p>The message to use for displaying enchanted book salvage cost</p>
|
||||||
|
*/
|
||||||
|
public String getEnchantedBookCostMessage() {
|
||||||
|
return asString(ScrapperSetting.COST_MESSAGE_ENCHANTED_BOOK);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getCoolDownUnexpiredMessage() {
|
public String getCoolDownUnexpiredMessage() {
|
||||||
@ -178,13 +196,25 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed if a player presents a different item after seeing the price to salvage an item
|
* Gets the message displayed if a player presents a different item after seeing the price to salvage an item
|
||||||
|
*
|
||||||
|
* @return <p>The item changed message</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getItemChangedMessage() {
|
public String getItemChangedMessage() {
|
||||||
return asString(ScrapperSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
return asString(ScrapperSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message displayed if a player presents the scrapper with an empty hand
|
||||||
|
*
|
||||||
|
* @return <p>The no item message</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getNoItemMessage() {
|
||||||
|
return asString(ScrapperSetting.NO_ITEM_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the minimum delay used to wait for a salvaging to finish.
|
* Gets the minimum delay used to wait for a salvaging to finish.
|
||||||
*
|
*
|
||||||
@ -454,4 +484,24 @@ public class ScrapperNPCSettings implements TraitSettings<ScrapperSetting> {
|
|||||||
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
|
return asString(ScrapperSetting.CANNOT_SALVAGE_NETHERITE_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that this scrapper is unable to salvage enchanted books
|
||||||
|
*
|
||||||
|
* @return <p>The message to display when explaining that this scrapper is unable to salvage enchanted books</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSalvageEnchantedBookMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment
|
||||||
|
*
|
||||||
|
* @return <p>The message to display when explaining that the scrapper cannot salvage an enchanted book with a single enchantment</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public String getCannotSplitEnchantedBookFurtherMessage() {
|
||||||
|
return asString(ScrapperSetting.CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,12 @@ public enum ScrapperSetting implements Setting {
|
|||||||
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
|
SALVAGE_NETHERITE("salvageNetherite", SettingValueType.BOOLEAN, true,
|
||||||
"Whether to enable salvaging of netherite items", true, false),
|
"Whether to enable salvaging of netherite items", true, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting for whether the NPC should allow salvaging an enchanted books with several enchantments into several books with one enchantment
|
||||||
|
*/
|
||||||
|
SPLIT_ENCHANTED_BOOK("splitEnchantedBook", SettingValueType.BOOLEAN, false, "Whether to enable " +
|
||||||
|
"splitting of enchanted books", true, false),
|
||||||
|
|
||||||
/*-----------
|
/*-----------
|
||||||
| Messages |
|
| Messages |
|
||||||
-----------*/
|
-----------*/
|
||||||
@ -194,6 +200,13 @@ public enum ScrapperSetting implements Setting {
|
|||||||
"&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!",
|
"&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 to display when explaining the shown item's netherite salvage cost", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when displaying the cost of salvaging the player's held enchanted book
|
||||||
|
*/
|
||||||
|
COST_MESSAGE_ENCHANTED_BOOK("costMessageEnchantedBook", SettingValueType.STRING,
|
||||||
|
"&eIt will cost &a{cost}&e to salvage that enchanted book!",
|
||||||
|
"The message to display when explaining the shown enchanted book's salvage cost", true, true),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message displayed when explaining that all items will be returned as salvage
|
* The message displayed when explaining that all items will be returned as salvage
|
||||||
*/
|
*/
|
||||||
@ -236,6 +249,26 @@ public enum ScrapperSetting implements Setting {
|
|||||||
"&cI'm sorry, but I'm unable to salvage netherite items!",
|
"&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),
|
"The message to display when asked to salvage netherite items, and that option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that enchanted book salvage is disabled
|
||||||
|
*/
|
||||||
|
CANNOT_SALVAGE_ENCHANTED_BOOK_MESSAGE("cannotSalvageEnchantedBookMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I'm unable to salvage enchanted books!",
|
||||||
|
"The message to display when asked to salvage enchanted books, and the option is disabled", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when explaining that a player cannot salvage an enchanted book containing a single enchantment
|
||||||
|
*/
|
||||||
|
CANNOT_SPLIT_ENCHANTED_BOOK_FURTHER_MESSAGE("cannotSplitEnchantedBookFurtherMessage", SettingValueType.STRING,
|
||||||
|
"&cI'm sorry, but I cannot salvage that enchanted book any further",
|
||||||
|
"The message displayed when a player attempts to salvage an enchanted book with a single enchantment", true, true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message displayed when clicking a scrapper with an empty hand
|
||||||
|
*/
|
||||||
|
NO_ITEM_MESSAGE("noItemMessage", SettingValueType.STRING, "Please present the item you want to salvage",
|
||||||
|
"The message to display when a scrapper is clicked with an empty hand", true, true),
|
||||||
|
|
||||||
/*------------------
|
/*------------------
|
||||||
| Global settings |
|
| Global settings |
|
||||||
------------------*/
|
------------------*/
|
||||||
@ -258,6 +291,20 @@ public enum ScrapperSetting implements Setting {
|
|||||||
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
|
NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15,
|
||||||
"The cost of using the scrapper to remove netherite from an item", false, false),
|
"The cost of using the scrapper to remove netherite from an item", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mathematical formula for increasing salvage cost
|
||||||
|
*/
|
||||||
|
SALVAGE_COST_INCREASE("salvageCostIncrease", SettingValueType.STRING, "{cost}*{timesUsed}",
|
||||||
|
"The mathematical formula for salvage cost increase when continually used within the same hour. " +
|
||||||
|
"This is necessary for some servers where items can be easily farmed. Set to {cost} to disable behavior.", false, false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mathematical formula for increasing salvage cooldown
|
||||||
|
*/
|
||||||
|
SALVAGE_COOLDOWN_INCREASE("salvageCooldownIncrease", SettingValueType.STRING, "{cooldown}*{timesUsed}",
|
||||||
|
"The mathematical formula for salvage cooldown increase when continually used within the same hour. " +
|
||||||
|
"This is necessary for some servers where items can be easily farmed. Set to {cooldown} to disable behavior.", false, false),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
|
* Whether to display exact time in minutes and seconds when displaying a remaining cool-down
|
||||||
*/
|
*/
|
||||||
|
252
src/main/java/net/knarcraft/blacksmith/container/ActionCost.java
Normal file
252
src/main/java/net/knarcraft/blacksmith/container/ActionCost.java
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
package net.knarcraft.blacksmith.container;
|
||||||
|
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost of performing an action
|
||||||
|
*
|
||||||
|
* @param monetaryCost <p>The monetary cost of the action</p>
|
||||||
|
* @param expCost <p>The experience cost of the action</p>
|
||||||
|
* @param itemCost <p>The item-based cost of the action</p>
|
||||||
|
* @param requiredPermissions <p>The permission required for the action</p>
|
||||||
|
*/
|
||||||
|
public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost,
|
||||||
|
@NotNull Set<String> requiredPermissions) implements ConfigurationSerializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the monetary cost of this action
|
||||||
|
*
|
||||||
|
* @param monetaryCost <p>The new monetary cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeMonetaryCost(double monetaryCost) {
|
||||||
|
return new ActionCost(monetaryCost, this.expCost, this.itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the experience cost of this action
|
||||||
|
*
|
||||||
|
* @param expCost <p>The new experience cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeExpCost(int expCost) {
|
||||||
|
return new ActionCost(this.monetaryCost, expCost, this.itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the item cost of this action
|
||||||
|
*
|
||||||
|
* @param itemCost <p>The new item cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changeItemCost(@Nullable ItemStack itemCost) {
|
||||||
|
return new ActionCost(this.monetaryCost, this.expCost, itemCost, this.requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the permission cost of this action
|
||||||
|
*
|
||||||
|
* @param requiredPermissions <p>The new permission cost</p>
|
||||||
|
* @return <p>The resulting action cost</p>
|
||||||
|
*/
|
||||||
|
public ActionCost changePermissionCost(@NotNull Set<String> requiredPermissions) {
|
||||||
|
return new ActionCost(this.monetaryCost, this.expCost, this.itemCost, requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public String displayCost() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (monetaryCost > 0) {
|
||||||
|
builder.append(EconomyManager.format(monetaryCost)).append(", ");
|
||||||
|
}
|
||||||
|
if (expCost > 0) {
|
||||||
|
builder.append(expCost).append("exp, ");
|
||||||
|
}
|
||||||
|
if (itemCost != null) {
|
||||||
|
// TODO: Present name, amount and name + lore
|
||||||
|
builder.append(itemCost);
|
||||||
|
}
|
||||||
|
// TODO: Display required permissions if the player doesn't have them?
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given player is able to pay this action cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @return <p>True if the player is able to pay</p>
|
||||||
|
*/
|
||||||
|
public boolean canPay(@NotNull Player player) {
|
||||||
|
for (String permission : this.requiredPermissions) {
|
||||||
|
if (!player.hasPermission(permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getExp() < this.expCost || !EconomyManager.hasEnough(player, this.monetaryCost)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasEnoughValidItemsInInventory(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes exp, money and items from the player, according to this cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to take the payment from</p>
|
||||||
|
*/
|
||||||
|
public void takePayment(@NotNull Player player) {
|
||||||
|
player.giveExp(-expCost);
|
||||||
|
EconomyManager.withdraw(player, monetaryCost);
|
||||||
|
takeItemCost(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given player has enough items specified as the item cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @return <p>True if the player has enough items in their inventory</p>
|
||||||
|
*/
|
||||||
|
private boolean hasEnoughValidItemsInInventory(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amountInInventory = 0;
|
||||||
|
for (Map.Entry<Integer, Integer> entry : getValidItems(player).entrySet()) {
|
||||||
|
amountInInventory += entry.getValue();
|
||||||
|
}
|
||||||
|
return this.itemCost.getAmount() >= amountInInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all items in a player's inventory equal to the specified item
|
||||||
|
*
|
||||||
|
* @param player <p>The player to get valid items for</p>
|
||||||
|
* @return <p>All valid items in the format: Inventory id -> Amount</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
private Map<Integer, Integer> getValidItems(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
|
ItemMeta targetMeta = this.itemCost.getItemMeta();
|
||||||
|
String displayName = null;
|
||||||
|
List<String> lore = null;
|
||||||
|
if (targetMeta != null) {
|
||||||
|
displayName = targetMeta.hasDisplayName() ? targetMeta.getDisplayName() : null;
|
||||||
|
lore = targetMeta.hasLore() ? targetMeta.getLore() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Integer> output = new HashMap<>();
|
||||||
|
HashMap<Integer, ? extends ItemStack> itemsOfType = playerInventory.all(this.itemCost.getType());
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, ? extends ItemStack> entry : itemsOfType.entrySet()) {
|
||||||
|
if (targetMeta != null) {
|
||||||
|
// Only consider item if the name and lore is the same
|
||||||
|
ItemMeta meta = entry.getValue().getItemMeta();
|
||||||
|
if (meta == null || (displayName != null && (!meta.hasDisplayName() ||
|
||||||
|
!meta.getDisplayName().equals(displayName)) || lore != null && (!meta.hasLore() ||
|
||||||
|
meta.getLore() == null || !meta.getLore().equals(lore)))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.put(entry.getKey(), (Integer) entry.getValue().getAmount());
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the amount of items specified as the cost for this action
|
||||||
|
*
|
||||||
|
* @param player <p>The player to take the items from</p>
|
||||||
|
*/
|
||||||
|
private void takeItemCost(@NotNull Player player) {
|
||||||
|
if (this.itemCost == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clearedAmount = 0;
|
||||||
|
for (Map.Entry<Integer, Integer> entry : getValidItems(player).entrySet()) {
|
||||||
|
int inventory = entry.getKey();
|
||||||
|
int amount = entry.getValue();
|
||||||
|
if (amount <= this.itemCost.getAmount() - clearedAmount) {
|
||||||
|
clearedAmount += amount;
|
||||||
|
player.getInventory().clear(entry.getKey());
|
||||||
|
} else {
|
||||||
|
clearedAmount = this.itemCost.getAmount();
|
||||||
|
ItemStack item = player.getInventory().getItem(inventory);
|
||||||
|
if (item != null) {
|
||||||
|
item.setAmount(amount - clearedAmount);
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.error("An item changed after calculating item cost. Was unable to take " +
|
||||||
|
amount + " items");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clearedAmount >= this.itemCost.getAmount()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads an action cost from a configuration section
|
||||||
|
*
|
||||||
|
* @param configurationSection <p>The configuration section to load from</p>
|
||||||
|
* @param key <p>The key of the cost to load</p>
|
||||||
|
* @return <p>The loaded cost</p>
|
||||||
|
*/
|
||||||
|
private static ActionCost loadActionCost(@NotNull ConfigurationSection configurationSection, @NotNull String key) {
|
||||||
|
double cost = configurationSection.getDouble(key, Double.MIN_VALUE);
|
||||||
|
if (cost != Double.MIN_VALUE) {
|
||||||
|
return new ActionCost(cost, 0, null, Set.of());
|
||||||
|
} else {
|
||||||
|
return (ActionCost) configurationSection.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes an action cost
|
||||||
|
*
|
||||||
|
* @param serialized <p>The serialized action cost</p>
|
||||||
|
* @return <p>The deserialized action cost</p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unused", "unchecked"})
|
||||||
|
public static ActionCost deserialize(Map<String, Object> serialized) {
|
||||||
|
double monetaryCost = (double) serialized.get("monetaryCost");
|
||||||
|
int expCost = (int) serialized.get("expCost");
|
||||||
|
ItemStack itemCost = (ItemStack) serialized.get("itemCost");
|
||||||
|
Set<String> requiredPermissions = (Set<String>) serialized.get("requiredPermissions");
|
||||||
|
return new ActionCost(monetaryCost, expCost, itemCost, requiredPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> serialize() {
|
||||||
|
Map<String, Object> serialized = new HashMap<>();
|
||||||
|
serialized.put("monetaryCost", Optional.of(this.monetaryCost));
|
||||||
|
serialized.put("expCost", Optional.of(this.expCost));
|
||||||
|
serialized.put("itemCost", itemCost);
|
||||||
|
serialized.put("requiredPermissions", this.requiredPermissions);
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -13,15 +14,18 @@ public abstract class AbstractBlacksmithPluginEvent extends Event implements Bla
|
|||||||
|
|
||||||
protected final NPC npc;
|
protected final NPC npc;
|
||||||
protected final Player player;
|
protected final Player player;
|
||||||
|
protected final Entity entity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new blacksmith plugin event
|
* Instantiates a new blacksmith plugin event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public AbstractBlacksmithPluginEvent(@NotNull NPC npc, @NotNull Player player) {
|
public AbstractBlacksmithPluginEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
this.npc = npc;
|
this.npc = npc;
|
||||||
|
this.entity = entity;
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +35,12 @@ public abstract class AbstractBlacksmithPluginEvent extends Event implements Bla
|
|||||||
return this.npc;
|
return this.npc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public Entity getEntity() {
|
||||||
|
return this.entity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event triggered when a blacksmith or scrapper starts reforging or salvaging an item
|
* An event triggered when a blacksmith or scrapper starts reforging or salvaging an item
|
||||||
*/
|
*/
|
||||||
@ -13,4 +15,11 @@ public interface ActionStartEvent extends BlacksmithPluginEvent {
|
|||||||
*/
|
*/
|
||||||
long getActionDurationTicks();
|
long getActionDurationTicks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the appropriate crafting station for this action
|
||||||
|
*
|
||||||
|
* @return <p>The appropriate crafting station</p>
|
||||||
|
*/
|
||||||
|
Material getCraftingStation();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -18,6 +19,14 @@ public interface BlacksmithPluginEvent {
|
|||||||
@NotNull
|
@NotNull
|
||||||
NPC getNpc();
|
NPC getNpc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entity of the NPC
|
||||||
|
*
|
||||||
|
* @return <p>The NPC entity</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Entity getEntity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the player involved in the event
|
* Gets the player involved in the event
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,9 +17,11 @@ public class BlacksmithReforgeFailEvent extends AbstractBlacksmithPluginEvent im
|
|||||||
* Instantiates a new blacksmith reforge fail event
|
* Instantiates a new blacksmith reforge fail event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
|
* @param player <p>The player that initiated the session</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
public BlacksmithReforgeFailEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -12,17 +14,22 @@ public class BlacksmithReforgeStartEvent extends AbstractBlacksmithPluginEvent i
|
|||||||
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private final long durationTicks;
|
private final long durationTicks;
|
||||||
|
private final Material craftingStation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new blacksmith reforge start event
|
* Instantiates a new blacksmith reforge start event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
* @param durationTicks <p>The duration of the reforge</p>
|
* @param durationTicks <p>The duration of the reforge</p>
|
||||||
|
* @param craftingStation <p>The appropriate crafting station for this reforging</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks) {
|
public BlacksmithReforgeStartEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, long durationTicks,
|
||||||
super(npc, player);
|
@NotNull Material craftingStation) {
|
||||||
|
super(npc, entity, player);
|
||||||
this.durationTicks = durationTicks;
|
this.durationTicks = durationTicks;
|
||||||
|
this.craftingStation = craftingStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -30,6 +37,11 @@ public class BlacksmithReforgeStartEvent extends AbstractBlacksmithPluginEvent i
|
|||||||
return durationTicks;
|
return durationTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material getCraftingStation() {
|
||||||
|
return craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a handler-list containing all event handlers
|
* Gets a handler-list containing all event handlers
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class BlacksmithReforgeSucceedEvent extends AbstractBlacksmithPluginEvent
|
|||||||
* Instantiates a new blacksmith reforge succeed event
|
* Instantiates a new blacksmith reforge succeed event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public BlacksmithReforgeSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
public BlacksmithReforgeSucceedEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.event;
|
|||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.SoundCategory;
|
import org.bukkit.SoundCategory;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
@ -25,15 +26,16 @@ public class NPCSoundEvent extends AbstractBlacksmithPluginEvent implements Canc
|
|||||||
* Instantiates a new NPC sound event
|
* Instantiates a new NPC sound event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC playing the sound</p>
|
* @param npc <p>The NPC playing the sound</p>
|
||||||
|
* @param entity <p>The entity playing the sound</p>
|
||||||
* @param player <p>The player whose interaction triggered the sound</p>
|
* @param player <p>The player whose interaction triggered the sound</p>
|
||||||
* @param soundCategory <p>The category the sound is to play in</p>
|
* @param soundCategory <p>The category the sound is to play in</p>
|
||||||
* @param sound <p>The sound to play</p>
|
* @param sound <p>The sound to play</p>
|
||||||
* @param volume <p>The volume of the played sound</p>
|
* @param volume <p>The volume of the played sound</p>
|
||||||
* @param pitch <p>The pitch of the played sound</p>
|
* @param pitch <p>The pitch of the played sound</p>
|
||||||
*/
|
*/
|
||||||
public NPCSoundEvent(@NotNull NPC npc, @NotNull Player player, @NotNull SoundCategory soundCategory,
|
public NPCSoundEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, @NotNull SoundCategory soundCategory,
|
||||||
@NotNull Sound sound, float volume, float pitch) {
|
@NotNull Sound sound, float volume, float pitch) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
this.soundCategory = soundCategory;
|
this.soundCategory = soundCategory;
|
||||||
this.sound = sound;
|
this.sound = sound;
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class ScrapperSalvageFailEvent extends AbstractBlacksmithPluginEvent impl
|
|||||||
* Instantiates a new scrapper salvage fail event
|
* Instantiates a new scrapper salvage fail event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageFailEvent(@NotNull NPC npc, @NotNull Player player) {
|
public ScrapperSalvageFailEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -13,17 +15,22 @@ public class ScrapperSalvageStartEvent extends AbstractBlacksmithPluginEvent imp
|
|||||||
|
|
||||||
private static final HandlerList handlers = new HandlerList();
|
private static final HandlerList handlers = new HandlerList();
|
||||||
private final long durationTicks;
|
private final long durationTicks;
|
||||||
|
private final Material craftingStation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new scrapper salvage start event
|
* Instantiates a new scrapper salvage start event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
* @param durationTicks <p>The duration of the salvage</p>
|
* @param durationTicks <p>The duration of the salvage</p>
|
||||||
|
* @param craftingStation <p>The appropriate crafting station for this salvaging</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageStartEvent(@NotNull NPC npc, @NotNull Player player, long durationTicks) {
|
public ScrapperSalvageStartEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player, long durationTicks,
|
||||||
super(npc, player);
|
@NotNull Material craftingStation) {
|
||||||
|
super(npc, entity, player);
|
||||||
this.durationTicks = durationTicks;
|
this.durationTicks = durationTicks;
|
||||||
|
this.craftingStation = craftingStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,6 +38,11 @@ public class ScrapperSalvageStartEvent extends AbstractBlacksmithPluginEvent imp
|
|||||||
return this.durationTicks;
|
return this.durationTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Material getCraftingStation() {
|
||||||
|
return this.craftingStation;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a handler-list containing all event handlers
|
* Gets a handler-list containing all event handlers
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.knarcraft.blacksmith.event;
|
package net.knarcraft.blacksmith.event;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,10 +17,11 @@ public class ScrapperSalvageSucceedEvent extends AbstractBlacksmithPluginEvent i
|
|||||||
* Instantiates a new scrapper salvage succeed event
|
* Instantiates a new scrapper salvage succeed event
|
||||||
*
|
*
|
||||||
* @param npc <p>The NPC involved in the event</p>
|
* @param npc <p>The NPC involved in the event</p>
|
||||||
|
* @param entity <p>The entity of the NPC</p>
|
||||||
* @param player <p>The player involved in the event</p>
|
* @param player <p>The player involved in the event</p>
|
||||||
*/
|
*/
|
||||||
public ScrapperSalvageSucceedEvent(@NotNull NPC npc, @NotNull Player player) {
|
public ScrapperSalvageSucceedEvent(@NotNull NPC npc, @NotNull Entity entity, @NotNull Player player) {
|
||||||
super(npc, player);
|
super(npc, entity, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,7 +27,8 @@ public final class BlacksmithStringFormatter {
|
|||||||
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
public static void sendNPCMessage(NPC npc, Player player, String message) {
|
||||||
player.sendMessage(BlacksmithPlugin.getStringFormatter().replacePlaceholders(
|
player.sendMessage(BlacksmithPlugin.getStringFormatter().replacePlaceholders(
|
||||||
BlacksmithTranslatableMessage.NPC_TALK_FORMAT, List.of("{npc}", "{message}"),
|
BlacksmithTranslatableMessage.NPC_TALK_FORMAT, List.of("{npc}", "{message}"),
|
||||||
List.of(npc.getName(), ColorHelper.translateColorCodes(message, ColorConversion.RGB))));
|
List.of(ColorHelper.translateColorCodes(npc.getRawName(), ColorConversion.RGB),
|
||||||
|
ColorHelper.translateColorCodes(message, ColorConversion.RGB))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,12 @@ public enum BlacksmithTranslatableMessage implements TranslatableMessage {
|
|||||||
/**
|
/**
|
||||||
* The format to use for formatting any message spoken by a blacksmith NPC
|
* The format to use for formatting any message spoken by a blacksmith NPC
|
||||||
*/
|
*/
|
||||||
NPC_TALK_FORMAT;
|
NPC_TALK_FORMAT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text to display when explaining that a cost must be a positive double
|
||||||
|
*/
|
||||||
|
DOUBLE_COST_REQUIRED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the message to display when displaying the raw value of messages
|
* Gets the message to display when displaying the raw value of messages
|
||||||
|
@ -5,7 +5,10 @@ import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings;
|
|||||||
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
import net.knarcraft.blacksmith.property.SalvageMethod;
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
import net.milkbowl.vault.economy.Economy;
|
import net.milkbowl.vault.economy.Economy;
|
||||||
|
import net.objecthunter.exp4j.Expression;
|
||||||
|
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -54,10 +57,12 @@ public class EconomyManager {
|
|||||||
*
|
*
|
||||||
* @param player <p>The player holding an item</p>
|
* @param player <p>The player holding an item</p>
|
||||||
* @param salvageMethod <p>The salvage method to check</p>
|
* @param salvageMethod <p>The salvage method to check</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
* @return <p>Whether the player cannot pay for the salvage</p>
|
* @return <p>Whether the player cannot pay for the salvage</p>
|
||||||
*/
|
*/
|
||||||
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) {
|
||||||
return economy.getBalance(player) - getSalvageCost(salvageMethod) < 0;
|
// TODO: Account for advanced cost options
|
||||||
|
return economy.getBalance(player) - getSalvageCost(salvageMethod, item, player) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,26 +81,61 @@ public class EconomyManager {
|
|||||||
* Gets the human-readable cost of salvaging an item
|
* Gets the human-readable cost of salvaging an item
|
||||||
*
|
*
|
||||||
* @param salvageMethod <p>The salvage method to get the cost for</p>
|
* @param salvageMethod <p>The salvage method to get the cost for</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
|
* @param player <p>The player to provide the cost to</p>
|
||||||
* @return <p>The formatted cost</p>
|
* @return <p>The formatted cost</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item,
|
||||||
return economy.format(getSalvageCost(salvageMethod));
|
@NotNull Player player) {
|
||||||
|
return economy.format(getSalvageCost(salvageMethod, item, player));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the given player has enough money to pay the given cost
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check</p>
|
||||||
|
* @param cost <p>The required cost</p>
|
||||||
|
* @return <p>True if the player has enough money to cover the cost</p>
|
||||||
|
*/
|
||||||
|
public static boolean hasEnough(@NotNull Player player, double cost) {
|
||||||
|
return economy.getBalance(player) >= cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a number as an economy cost
|
||||||
|
*
|
||||||
|
* @param cost <p>The cost to format</p>
|
||||||
|
* @return <p>The formatted cost</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String format(double cost) {
|
||||||
|
return economy.format(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cost of salvaging using the specified method
|
* Gets the cost of salvaging using the specified method
|
||||||
*
|
*
|
||||||
* @param salvageMethod <p>The salvage method to get cost for</p>
|
* @param salvageMethod <p>The salvage method to get cost for</p>
|
||||||
|
* @param item <p>The item to be salvaged</p>
|
||||||
* @return <p>The salvage cost</p>
|
* @return <p>The salvage cost</p>
|
||||||
*/
|
*/
|
||||||
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod) {
|
private static double getSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item,
|
||||||
|
@NotNull Player player) {
|
||||||
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
return switch (salvageMethod) {
|
double baseCost = switch (salvageMethod) {
|
||||||
case SALVAGE -> settings.getSalvageCost();
|
case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost();
|
||||||
case NETHERITE -> settings.getNetheriteSalvageCost();
|
case NETHERITE -> settings.getNetheriteSalvageCost();
|
||||||
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
|
case ARMOR_TRIM -> settings.getArmorTrimSalvageCost();
|
||||||
|
case ENCHANTED_BOOK -> getEnchantedBookSalvageCost(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StringReplacer replacer = new StringReplacer(settings.getSalvageCostIncrease());
|
||||||
|
replacer.add("{cost}", String.valueOf(baseCost));
|
||||||
|
replacer.add("{timesUsed}", String.valueOf(PlayerUsageManager.getUsages(player,
|
||||||
|
System.currentTimeMillis() - 3600000)));
|
||||||
|
Expression expression = new ExpressionBuilder(replacer.replace()).build();
|
||||||
|
return Math.max(expression.evaluate(), baseCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,12 +159,26 @@ public class EconomyManager {
|
|||||||
* @param salvageMethod <p>The salvage method to withdraw for</p>
|
* @param salvageMethod <p>The salvage method to withdraw for</p>
|
||||||
*/
|
*/
|
||||||
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) {
|
||||||
double cost = getSalvageCost(salvageMethod);
|
double cost = getSalvageCost(salvageMethod, player.getInventory().getItemInMainHand(), player);
|
||||||
if (cost > 0) {
|
if (cost > 0) {
|
||||||
economy.withdrawPlayer(player, cost);
|
economy.withdrawPlayer(player, cost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraws money from a player
|
||||||
|
*
|
||||||
|
* @param player <p>The player to withdraw from</p>
|
||||||
|
* @param monetaryCost <p>The cost to withdraw</p>
|
||||||
|
* @throws IllegalArgumentException <p>If a negative cost is given</p>
|
||||||
|
*/
|
||||||
|
public static void withdraw(@NotNull Player player, double monetaryCost) {
|
||||||
|
if (monetaryCost < 0) {
|
||||||
|
throw new IllegalArgumentException("Cannot withdraw a negative amount");
|
||||||
|
}
|
||||||
|
economy.withdrawPlayer(player, monetaryCost);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the cost of the item in the given player's main hand
|
* Gets the cost of the item in the given player's main hand
|
||||||
*
|
*
|
||||||
@ -183,6 +237,24 @@ public class EconomyManager {
|
|||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cost of scrapping an enchanted book
|
||||||
|
*
|
||||||
|
* @param item <p>The enchanted book to calculate cost for</p>
|
||||||
|
* @return <p>The cost of scrapping the enchanted book</p>
|
||||||
|
*/
|
||||||
|
private static double getEnchantedBookSalvageCost(@NotNull ItemStack item) {
|
||||||
|
// TODO: Properly implement this
|
||||||
|
/*GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
|
||||||
|
double cost = settings.getEnchantedBookSalvageCost();
|
||||||
|
if (settings.multiplyEnchantedBookSalvageCost()) {
|
||||||
|
cost *= SalvageHelper.getEnchantmentCount(item) - 1;
|
||||||
|
}
|
||||||
|
return SalvageHelper.getEnchantmentCount(item) * cost;*/
|
||||||
|
return 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up Vault for economy
|
* Sets up Vault for economy
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package net.knarcraft.blacksmith.manager;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for keeping track of players using scrappers
|
||||||
|
*/
|
||||||
|
public class PlayerUsageManager {
|
||||||
|
|
||||||
|
private static final Map<Player, Set<Long>> playerUsages = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register that a player has used a scrapper
|
||||||
|
*
|
||||||
|
* @param player <p>The player using a scrapper</p>
|
||||||
|
*/
|
||||||
|
public static void registerUsage(@NotNull Player player) {
|
||||||
|
playerUsages.putIfAbsent(player, new HashSet<>());
|
||||||
|
Set<Long> usages = playerUsages.get(player);
|
||||||
|
usages.add(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets how many times the given player has used a scrapper after the given timestamp
|
||||||
|
*
|
||||||
|
* @param player <p>The player to check usages for</p>
|
||||||
|
* @param afterTimestamp <p>The timestamp of when to start looking for usages</p>
|
||||||
|
* @return <p>The number of scrapper uses for the given player</p>
|
||||||
|
*/
|
||||||
|
public static int getUsages(@NotNull Player player, @NotNull Long afterTimestamp) {
|
||||||
|
Set<Long> usages = playerUsages.get(player);
|
||||||
|
if (usages == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uses = 0;
|
||||||
|
Set<Long> expired = new HashSet<>();
|
||||||
|
for (Long usageTime : usages) {
|
||||||
|
if (usageTime < afterTimestamp) {
|
||||||
|
expired.add(usageTime);
|
||||||
|
} else {
|
||||||
|
uses++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expired data
|
||||||
|
usages.removeAll(expired);
|
||||||
|
|
||||||
|
return uses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all expired timestamps
|
||||||
|
*
|
||||||
|
* @param afterTimestamp <p>The timestamp for the earliest time of valid timestamps</p>
|
||||||
|
*/
|
||||||
|
public static void removeExpiredData(@NotNull Long afterTimestamp) {
|
||||||
|
for (Set<Long> usageSet : playerUsages.values()) {
|
||||||
|
Set<Long> expired = new HashSet<>();
|
||||||
|
for (Long item : usageSet) {
|
||||||
|
if (item < afterTimestamp) {
|
||||||
|
expired.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usageSet.removeAll(expired);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package net.knarcraft.blacksmith.property;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of costs applicable to an advanced cost configuration
|
||||||
|
*/
|
||||||
|
public enum CostType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A monetary cost from an economy plugin
|
||||||
|
*/
|
||||||
|
ECONOMY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A permission requirement, rather than a cost
|
||||||
|
*/
|
||||||
|
PERMISSION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-game experience levels
|
||||||
|
*/
|
||||||
|
EXP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specific item is consumed
|
||||||
|
*/
|
||||||
|
ITEM,
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a text string denoting a cost type
|
||||||
|
*
|
||||||
|
* @param input <p>The input to parse</p>
|
||||||
|
* @return <p>The parsed cost type, or null if not matched</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static CostType parse(@NotNull String input) {
|
||||||
|
String normalized = input.trim().toUpperCase();
|
||||||
|
for (CostType costType : CostType.values()) {
|
||||||
|
if (normalized.equals(costType.name())) {
|
||||||
|
return costType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,6 +10,11 @@ public enum SalvageMethod {
|
|||||||
*/
|
*/
|
||||||
SALVAGE,
|
SALVAGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salvaging unrepairable items normally by returning the item's crafting recipe, but with unrestricted
|
||||||
|
*/
|
||||||
|
EXTENDED_SALVAGE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removing the armor trim from an item
|
* Removing the armor trim from an item
|
||||||
*/
|
*/
|
||||||
@ -20,4 +25,9 @@ public enum SalvageMethod {
|
|||||||
*/
|
*/
|
||||||
NETHERITE,
|
NETHERITE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splitting enchantments of an enchanted book
|
||||||
|
*/
|
||||||
|
ENCHANTED_BOOK,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,11 @@ public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
|
|||||||
@Override
|
@Override
|
||||||
public void startSession(@NotNull Player player) {
|
public void startSession(@NotNull Player player) {
|
||||||
ItemStack hand = player.getInventory().getItemInMainHand();
|
ItemStack hand = player.getInventory().getItemInMainHand();
|
||||||
|
if (hand.getType().isAir()) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getNoItemMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
|
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
|
||||||
List<Material> reforgeAbleItems = config.getReforgeAbleItems();
|
List<Material> reforgeAbleItems = config.getReforgeAbleItems();
|
||||||
|
|
||||||
@ -89,7 +94,12 @@ public class BlacksmithTrait extends CustomTrait<BlacksmithSetting> {
|
|||||||
|
|
||||||
//Start a new reforge session for the player
|
//Start a new reforge session for the player
|
||||||
currentSessionStartTime = System.currentTimeMillis();
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
session = new ReforgeSession(this, player, npc, config);
|
session = new ReforgeSession(this, player, npc, config);
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
BlacksmithPlugin.error(exception.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Tell the player the cost of repairing the item
|
//Tell the player the cost of repairing the item
|
||||||
String cost = EconomyManager.formatBlacksmithCost(player);
|
String cost = EconomyManager.formatBlacksmithCost(player);
|
||||||
|
@ -2,14 +2,17 @@ package net.knarcraft.blacksmith.trait;
|
|||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
import net.citizensnpcs.api.trait.Trait;
|
import net.citizensnpcs.api.trait.Trait;
|
||||||
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.Setting;
|
import net.knarcraft.blacksmith.config.Setting;
|
||||||
import net.knarcraft.blacksmith.config.Settings;
|
import net.knarcraft.blacksmith.config.Settings;
|
||||||
import net.knarcraft.blacksmith.config.TraitSettings;
|
import net.knarcraft.blacksmith.config.TraitSettings;
|
||||||
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
import net.knarcraft.knarlib.formatting.StringFormatter;
|
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -18,7 +21,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -153,8 +155,13 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
||||||
|
Entity entity = npc.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
BlacksmithPlugin.error("NPC session could not be started, as the NPC does not have a valid entity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
|
if (session != null && !session.isRunning() && (System.currentTimeMillis() > currentSessionStartTime + 10 * 1000 ||
|
||||||
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
entity.getLocation().distance(session.getPlayer().getLocation()) > 20)) {
|
||||||
session = null;
|
session = null;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -183,16 +190,21 @@ public abstract class CustomTrait<K extends Setting> extends Trait {
|
|||||||
} else if (this.session instanceof SalvageSession salvageSession) {
|
} else if (this.session instanceof SalvageSession salvageSession) {
|
||||||
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
|
EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.scheduleAction();
|
|
||||||
PlayerInventory playerInventory = player.getInventory();
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
||||||
|
session.scheduleAction();
|
||||||
|
|
||||||
//Display the item in the NPC's hand
|
//Display the item in the NPC's hand
|
||||||
if (npc.getEntity() instanceof Player) {
|
Entity entity = npc.getEntity();
|
||||||
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
|
if (entity instanceof Player playerNPC) {
|
||||||
|
playerNPC.getInventory().setItemInMainHand(heldItem);
|
||||||
|
} else if (entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
((LivingEntity) entity).getEquipment().setItemInMainHand(heldItem);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
|
BlacksmithPlugin.warn("Failed to update NPC item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//Remove the item from the player's inventory
|
//Remove the item from the player's inventory
|
||||||
if (this.session instanceof SalvageSession salvageSession) {
|
if (this.session instanceof SalvageSession salvageSession) {
|
||||||
|
@ -15,13 +15,13 @@ import org.bukkit.Sound;
|
|||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -92,6 +92,11 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull Material getCraftingStation() {
|
||||||
|
return Material.ANVIL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the actual reforge which fixes the item and gives it back to the player
|
* Runs the actual reforge which fixes the item and gives it back to the player
|
||||||
*/
|
*/
|
||||||
@ -102,10 +107,15 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
||||||
|
|
||||||
//Stop the reforged item from displaying in the blacksmith's hand
|
//Stop the reforged item from displaying in the blacksmith's hand
|
||||||
if (this.npc.getEntity() instanceof Player) {
|
if (this.entity instanceof Player playerNPC) {
|
||||||
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
playerNPC.getInventory().setItemInMainHand(null);
|
||||||
|
} else if (this.entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) this.entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
equipment.setItemInMainHand(null);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
BlacksmithPlugin.warn("Failed to clear Blacksmith item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Give the item back to the player
|
//Give the item back to the player
|
||||||
@ -124,8 +134,7 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
* Gives the reforged item back to the player
|
* Gives the reforged item back to the player
|
||||||
*/
|
*/
|
||||||
private void giveReforgedItem() {
|
private void giveReforgedItem() {
|
||||||
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.npc,
|
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.itemToReforge);
|
||||||
this.itemToReforge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,11 +145,11 @@ public class ReforgeSession extends Session implements Runnable {
|
|||||||
private boolean reforgeItem() {
|
private boolean reforgeItem() {
|
||||||
if (random.nextInt(100) < this.config.getFailChance()) {
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
failReforge();
|
failReforge();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeFailEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeFailEvent(this.npc, this.entity, this.player));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
succeedReforge();
|
succeedReforge();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeSucceedEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeSucceedEvent(this.npc, this.entity, this.player));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,24 @@ import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
|||||||
import net.knarcraft.blacksmith.event.ScrapperSalvageFailEvent;
|
import net.knarcraft.blacksmith.event.ScrapperSalvageFailEvent;
|
||||||
import net.knarcraft.blacksmith.event.ScrapperSalvageSucceedEvent;
|
import net.knarcraft.blacksmith.event.ScrapperSalvageSucceedEvent;
|
||||||
import net.knarcraft.blacksmith.manager.EconomyManager;
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
||||||
|
import net.knarcraft.blacksmith.manager.PlayerUsageManager;
|
||||||
import net.knarcraft.blacksmith.property.SalvageMethod;
|
import net.knarcraft.blacksmith.property.SalvageMethod;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
import net.knarcraft.blacksmith.util.SalvageHelper;
|
import net.knarcraft.blacksmith.util.SalvageHelper;
|
||||||
|
import net.knarcraft.knarlib.formatting.StringReplacer;
|
||||||
|
import net.objecthunter.exp4j.Expression;
|
||||||
|
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.EntityEquipment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
||||||
@ -69,7 +74,9 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod)) {
|
// TODO: Check item cost. If
|
||||||
|
|
||||||
|
if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod, this.itemToSalvage)) {
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -87,6 +94,16 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull Material getCraftingStation() {
|
||||||
|
return switch (this.salvageMethod) {
|
||||||
|
case EXTENDED_SALVAGE -> Material.CRAFTING_TABLE;
|
||||||
|
case SALVAGE -> Material.ANVIL;
|
||||||
|
case NETHERITE, ARMOR_TRIM -> Material.SMITHING_TABLE;
|
||||||
|
case ENCHANTED_BOOK -> Material.ENCHANTING_TABLE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the actual salvage which fixes the item and gives it back to the player
|
* Runs the actual salvage which fixes the item and gives it back to the player
|
||||||
*/
|
*/
|
||||||
@ -95,10 +112,15 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
salvageItem();
|
salvageItem();
|
||||||
|
|
||||||
//Stop the reforged item from displaying in the scrapper's hand
|
//Stop the reforged item from displaying in the scrapper's hand
|
||||||
if (this.npc.getEntity() instanceof Player) {
|
if (this.entity instanceof Player playerNPC) {
|
||||||
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
playerNPC.getInventory().setItemInMainHand(null);
|
||||||
|
} else if (this.entity instanceof LivingEntity) {
|
||||||
|
EntityEquipment equipment = ((LivingEntity) this.entity).getEquipment();
|
||||||
|
if (equipment != null) {
|
||||||
|
equipment.setItemInMainHand(null);
|
||||||
} else {
|
} else {
|
||||||
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
BlacksmithPlugin.warn("Failed to clear Scrapper item, as its equipment was irretrievable.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mark this scrapper as available
|
//Mark this scrapper as available
|
||||||
@ -106,8 +128,14 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
|
|
||||||
// Start cool-down
|
// Start cool-down
|
||||||
Calendar wait = Calendar.getInstance();
|
Calendar wait = Calendar.getInstance();
|
||||||
wait.add(Calendar.SECOND, this.config.getSalvageCoolDown());
|
StringReplacer replacer = new StringReplacer(BlacksmithPlugin.getInstance().getGlobalScrapperSettings().getSalvageCooldownIncrease());
|
||||||
|
replacer.add("{cooldown}", String.valueOf(this.config.getSalvageCoolDown()));
|
||||||
|
replacer.add("{timesUsed}", String.valueOf(PlayerUsageManager.getUsages(player, System.currentTimeMillis() - 3600000)));
|
||||||
|
Expression expression = new ExpressionBuilder(replacer.replace()).build();
|
||||||
|
|
||||||
|
wait.add(Calendar.SECOND, Math.max((int) expression.evaluate(), this.config.getSalvageCoolDown()));
|
||||||
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
|
this.scrapperTrait.addCoolDown(this.player.getUniqueId(), wait);
|
||||||
|
PlayerUsageManager.registerUsage(this.player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,11 +154,11 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
if (random.nextInt(100) < this.config.getFailChance()) {
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
||||||
playSound(Sound.ENTITY_VILLAGER_NO);
|
playSound(Sound.ENTITY_VILLAGER_NO);
|
||||||
failSalvage();
|
failSalvage();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageFailEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageFailEvent(this.npc, this.entity, this.player));
|
||||||
} else {
|
} else {
|
||||||
playSound(Sound.BLOCK_ANVIL_USE);
|
playSound(Sound.BLOCK_ANVIL_USE);
|
||||||
giveSalvage();
|
giveSalvage();
|
||||||
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageSucceedEvent(this.npc, this.player));
|
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageSucceedEvent(this.npc, this.entity, this.player));
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getSuccessMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getSuccessMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,14 +173,13 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
if (ItemHelper.getMaxDurability(this.itemToSalvage) > 0) {
|
if (ItemHelper.getMaxDurability(this.itemToSalvage) > 0) {
|
||||||
//Damage the item if possible
|
//Damage the item if possible
|
||||||
damageItemRandomly(this.itemToSalvage);
|
damageItemRandomly(this.itemToSalvage);
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc,
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.itemToSalvage);
|
||||||
this.itemToSalvage);
|
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getFailSalvageMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getFailSalvageMessage());
|
||||||
} else {
|
} else {
|
||||||
// Give half the salvage
|
// Give half the salvage
|
||||||
List<ItemStack> halfSalvage = SalvageHelper.pickRandomSalvage(this.salvage, new ArrayList<>(), 0.5);
|
List<ItemStack> halfSalvage = SalvageHelper.pickRandomSalvage(this.salvage, new ArrayList<>(), 0.5);
|
||||||
for (ItemStack item : halfSalvage) {
|
for (ItemStack item : halfSalvage) {
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), item);
|
||||||
}
|
}
|
||||||
sendNPCMessage(this.npc, this.player, this.config.getFailExtendedSalvageMessage());
|
sendNPCMessage(this.npc, this.player, this.config.getFailExtendedSalvageMessage());
|
||||||
}
|
}
|
||||||
@ -167,7 +194,7 @@ public class SalvageSession extends Session implements Runnable {
|
|||||||
this.player.giveExpLevels(this.enchantmentLevels);
|
this.player.giveExpLevels(this.enchantmentLevels);
|
||||||
BlacksmithPlugin.debug("Giving salvage " + this.salvage);
|
BlacksmithPlugin.debug("Giving salvage " + this.salvage);
|
||||||
for (ItemStack item : this.salvage) {
|
for (ItemStack item : this.salvage) {
|
||||||
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), this.npc, item);
|
giveResultingItem(this.config.getMaxSalvageDelay() > 0, this.config.getDropItem(), item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import net.citizensnpcs.api.util.DataKey;
|
|||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.config.SmithPreset;
|
import net.knarcraft.blacksmith.config.SmithPreset;
|
||||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
import net.knarcraft.blacksmith.config.SmithPresetFilter;
|
||||||
|
import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings;
|
||||||
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings;
|
||||||
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting;
|
||||||
import net.knarcraft.blacksmith.container.RecipeResult;
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
@ -20,6 +21,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ArmorMeta;
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@ -85,6 +87,11 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
*/
|
*/
|
||||||
public void startSession(@NotNull Player player) {
|
public void startSession(@NotNull Player player) {
|
||||||
ItemStack itemInHand = player.getInventory().getItemInMainHand().clone();
|
ItemStack itemInHand = player.getInventory().getItemInMainHand().clone();
|
||||||
|
if (itemInHand.getType().isAir()) {
|
||||||
|
sendNPCMessage(this.npc, player, config.getNoItemMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<Material> salvageAbleItems = getSettings().getSalvageAbleItems();
|
List<Material> salvageAbleItems = getSettings().getSalvageAbleItems();
|
||||||
boolean extended = getSettings().extendedSalvageEnabled();
|
boolean extended = getSettings().extendedSalvageEnabled();
|
||||||
|
|
||||||
@ -104,10 +111,15 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
|
|
||||||
//Start a new scrapper session for the player
|
//Start a new scrapper session for the player
|
||||||
currentSessionStartTime = System.currentTimeMillis();
|
currentSessionStartTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
session = new SalvageSession(this, player, npc, getSettings(), result.salvage(),
|
session = new SalvageSession(this, player, npc, getSettings(), result.salvage(),
|
||||||
result.salvageMethod(), result.requiredAmount());
|
result.salvageMethod(), result.requiredAmount());
|
||||||
|
} catch (IllegalArgumentException exception) {
|
||||||
|
BlacksmithPlugin.error(exception.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Print the cost to the player
|
// Print the cost to the player
|
||||||
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod()),
|
printCostMessage(player, itemInHand, EconomyManager.formatSalvageCost(result.salvageMethod(), itemInHand, player),
|
||||||
result.salvageMethod());
|
result.salvageMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +147,13 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = isEnchantedBookSalvage(player, itemInHand);
|
||||||
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
|
return null;
|
||||||
|
} else if (result.salvageState() == SalvageState.FOUND_SALVAGE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result = isNormalSalvage(player, itemInHand, extended);
|
result = isNormalSalvage(player, itemInHand, extended);
|
||||||
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
if (result.salvageState() == SalvageState.NO_SALVAGE) {
|
||||||
return null;
|
return null;
|
||||||
@ -164,7 +183,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the item is enchanted, and whether this blacksmith can salvage it
|
// Check if the item is enchanted, and whether this scrapper can salvage it
|
||||||
if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) {
|
if (!itemInHand.getEnchantments().isEmpty() && !getSettings().salvageEnchanted()) {
|
||||||
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage());
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedMessage());
|
||||||
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
@ -172,16 +191,48 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
|
|
||||||
// Check if any salvage will be produced
|
// Check if any salvage will be produced
|
||||||
RecipeResult recipeResult = getSalvage(itemInHand, extended);
|
RecipeResult recipeResult = getSalvage(itemInHand, extended);
|
||||||
|
SalvageMethod method = ItemHelper.isRepairable(itemInHand) ? SalvageMethod.SALVAGE : SalvageMethod.EXTENDED_SALVAGE;
|
||||||
boolean noUsefulSalvage = recipeResult == null || recipeResult.salvage().isEmpty();
|
boolean noUsefulSalvage = recipeResult == null || recipeResult.salvage().isEmpty();
|
||||||
if (noUsefulSalvage) {
|
if (noUsefulSalvage) {
|
||||||
sendNPCMessage(this.npc, player, getSettings().getTooDamagedMessage());
|
sendNPCMessage(this.npc, player, getSettings().getTooDamagedMessage());
|
||||||
return new SalvageResult(SalvageMethod.SALVAGE, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
return new SalvageResult(method, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
} else {
|
} else {
|
||||||
return new SalvageResult(SalvageMethod.SALVAGE, recipeResult.salvage(), SalvageState.FOUND_SALVAGE,
|
return new SalvageResult(method, recipeResult.salvage(), SalvageState.FOUND_SALVAGE,
|
||||||
recipeResult.recipe().getResult().getAmount());
|
recipeResult.recipe().getResult().getAmount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result of trying to salvage the item as an enchanted book
|
||||||
|
*
|
||||||
|
* @param player <p>The player trying to salvage the item</p>
|
||||||
|
* @param itemInHand <p>The item to be salvaged</p>
|
||||||
|
* @return <p>The result of attempting the salvage</p>
|
||||||
|
*/
|
||||||
|
private SalvageResult isEnchantedBookSalvage(@NotNull Player player, @NotNull ItemStack itemInHand) {
|
||||||
|
if (itemInHand.getType() != Material.ENCHANTED_BOOK ||
|
||||||
|
!(itemInHand.getItemMeta() instanceof EnchantmentStorageMeta)) {
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.INCORRECT_METHOD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getSettings().splitEnchantedBook()) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSalvageEnchantedBookMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SalvageHelper.getEnchantmentCount(itemInHand) <= 1) {
|
||||||
|
sendNPCMessage(this.npc, player, getSettings().getCannotSplitEnchantedBookFurtherMessage());
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ItemStack> salvage = SalvageHelper.getEnchantedBookSalvage(itemInHand);
|
||||||
|
boolean noUsefulSalvage = salvage == null || salvage.isEmpty();
|
||||||
|
if (noUsefulSalvage) {
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, new ArrayList<>(), SalvageState.NO_SALVAGE, 0);
|
||||||
|
}
|
||||||
|
return new SalvageResult(SalvageMethod.ENCHANTED_BOOK, salvage, SalvageState.FOUND_SALVAGE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the result of trying to salvage the item as a netherite applied item
|
* Gets the result of trying to salvage the item as a netherite applied item
|
||||||
*
|
*
|
||||||
@ -250,7 +301,7 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
replacer.add("{item}", itemInHand.getType().name().toLowerCase().replace('_', ' '));
|
replacer.add("{item}", itemInHand.getType().name().toLowerCase().replace('_', ' '));
|
||||||
if (salvageMethod == SalvageMethod.ARMOR_TRIM) {
|
if (salvageMethod == SalvageMethod.ARMOR_TRIM) {
|
||||||
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getArmorTrimCostMessage()));
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getArmorTrimCostMessage()));
|
||||||
} else if (salvageMethod == SalvageMethod.SALVAGE) {
|
} else if (salvageMethod == SalvageMethod.SALVAGE || salvageMethod == SalvageMethod.EXTENDED_SALVAGE) {
|
||||||
String expectedYield;
|
String expectedYield;
|
||||||
if (ItemHelper.getDamage(itemInHand) <= 0) {
|
if (ItemHelper.getDamage(itemInHand) <= 0) {
|
||||||
expectedYield = getSettings().getFullSalvageMessage();
|
expectedYield = getSettings().getFullSalvageMessage();
|
||||||
@ -261,9 +312,32 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getCostMessage()));
|
||||||
} else if (salvageMethod == SalvageMethod.NETHERITE) {
|
} else if (salvageMethod == SalvageMethod.NETHERITE) {
|
||||||
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
|
sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage()));
|
||||||
|
} else if (salvageMethod == SalvageMethod.ENCHANTED_BOOK) {
|
||||||
|
StringReplacer replacer2 = new StringReplacer();
|
||||||
|
replacer2.add("{cost}", getEnchantedBookCost());
|
||||||
|
sendNPCMessage(this.npc, player, replacer2.replace(getSettings().getEnchantedBookCostMessage()));
|
||||||
|
} else {
|
||||||
|
BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getEnchantedBookCost() {
|
||||||
|
// TODO: If both an item and money is required, print both requirements
|
||||||
|
// TODO: If only money is required, print the money requirement
|
||||||
|
// TODO: If an item requirement is set, print the item requirement
|
||||||
|
|
||||||
|
GlobalScrapperSettings scrapperSettings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings();
|
||||||
|
/*String moneyCost = EconomyManager.format(scrapperSettings.getEnchantedBookSalvageCost());
|
||||||
|
//ItemStack itemCost = scrapperSettings.
|
||||||
|
if (scrapperSettings.requireMoneyAndItemForEnchantedBookSalvage()) {
|
||||||
|
// TODO: Print both with a + between them (if item has a special name, use that instead of the material name)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: If the item is not null, print it, otherwise print the monetary cost
|
||||||
|
}*/
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean showExactTime() {
|
protected boolean showExactTime() {
|
||||||
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
|
return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime();
|
||||||
@ -278,8 +352,8 @@ public class ScrapperTrait extends CustomTrait<ScrapperSetting> {
|
|||||||
* @return <p>True if the item can be theoretically salvaged</p>
|
* @return <p>True if the item can be theoretically salvaged</p>
|
||||||
*/
|
*/
|
||||||
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
|
private boolean canBeSalvaged(@NotNull ItemStack item, @NotNull List<Material> salvageAbleItems, boolean extended) {
|
||||||
return (extended || ItemHelper.isRepairable(item)) &&
|
return item.getType() == Material.ENCHANTED_BOOK || ((extended || ItemHelper.isRepairable(item)) &&
|
||||||
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType()));
|
(salvageAbleItems.isEmpty() || salvageAbleItems.contains(item.getType())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ import net.knarcraft.blacksmith.event.BlacksmithReforgeStartEvent;
|
|||||||
import net.knarcraft.blacksmith.event.NPCSoundEvent;
|
import net.knarcraft.blacksmith.event.NPCSoundEvent;
|
||||||
import net.knarcraft.blacksmith.event.ScrapperSalvageStartEvent;
|
import net.knarcraft.blacksmith.event.ScrapperSalvageStartEvent;
|
||||||
import net.knarcraft.blacksmith.util.ItemHelper;
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.SoundCategory;
|
import org.bukkit.SoundCategory;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -25,6 +26,7 @@ public abstract class Session implements Runnable {
|
|||||||
protected static final Random random = new Random();
|
protected static final Random random = new Random();
|
||||||
protected final Player player;
|
protected final Player player;
|
||||||
protected final NPC npc;
|
protected final NPC npc;
|
||||||
|
protected final Entity entity;
|
||||||
protected long finishTime;
|
protected long finishTime;
|
||||||
protected int taskId;
|
protected int taskId;
|
||||||
|
|
||||||
@ -37,6 +39,10 @@ public abstract class Session implements Runnable {
|
|||||||
public Session(@NotNull Player player, @NotNull NPC npc) {
|
public Session(@NotNull Player player, @NotNull NPC npc) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.npc = npc;
|
this.npc = npc;
|
||||||
|
this.entity = npc.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
throw new IllegalArgumentException("Tried to start session for an NPC without an assigned entity.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,10 +106,11 @@ public abstract class Session implements Runnable {
|
|||||||
this.finishTime = System.currentTimeMillis() + (actionDelay * 1000L);
|
this.finishTime = System.currentTimeMillis() + (actionDelay * 1000L);
|
||||||
long actionDelayTicks = actionDelay * 20L;
|
long actionDelayTicks = actionDelay * 20L;
|
||||||
|
|
||||||
|
BlacksmithPlugin instance = BlacksmithPlugin.getInstance();
|
||||||
if (this instanceof ReforgeSession) {
|
if (this instanceof ReforgeSession) {
|
||||||
BlacksmithPlugin.getInstance().callEvent(new BlacksmithReforgeStartEvent(npc, player, actionDelayTicks));
|
instance.callEvent(new BlacksmithReforgeStartEvent(this.npc, this.entity, this.player, actionDelayTicks, getCraftingStation()));
|
||||||
} else if (this instanceof SalvageSession) {
|
} else if (this instanceof SalvageSession) {
|
||||||
BlacksmithPlugin.getInstance().callEvent(new ScrapperSalvageStartEvent(npc, player, actionDelayTicks));
|
instance.callEvent(new ScrapperSalvageStartEvent(this.npc, this.entity, this.player, actionDelayTicks, getCraftingStation()));
|
||||||
}
|
}
|
||||||
|
|
||||||
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelayTicks);
|
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, actionDelayTicks);
|
||||||
@ -114,14 +121,13 @@ public abstract class Session implements Runnable {
|
|||||||
*
|
*
|
||||||
* @param hasDelay <p>Whether the session was delayed, or if the item was processed instantly</p>
|
* @param hasDelay <p>Whether the session was delayed, or if the item was processed instantly</p>
|
||||||
* @param dropItem <p>Whether the item should be dropped on the ground</p>
|
* @param dropItem <p>Whether the item should be dropped on the ground</p>
|
||||||
* @param npc <p>The NPC holding the item</p>
|
|
||||||
* @param itemToReturn <p>The item to return to the player</p>
|
* @param itemToReturn <p>The item to return to the player</p>
|
||||||
*/
|
*/
|
||||||
protected void giveResultingItem(boolean hasDelay, boolean dropItem, @NotNull NPC npc, @NotNull ItemStack itemToReturn) {
|
protected void giveResultingItem(boolean hasDelay, boolean dropItem, @NotNull ItemStack itemToReturn) {
|
||||||
if (hasDelay) {
|
if (hasDelay) {
|
||||||
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
|
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
|
||||||
if (dropItem || !this.player.isOnline() || !ItemHelper.canFitItem(this.player.getInventory(), itemToReturn)) {
|
if (dropItem || !this.player.isOnline() || !ItemHelper.canFitItem(this.player.getInventory(), itemToReturn)) {
|
||||||
this.player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReturn);
|
this.player.getWorld().dropItemNaturally(this.entity.getLocation(), itemToReturn);
|
||||||
} else {
|
} else {
|
||||||
this.player.getInventory().addItem(itemToReturn);
|
this.player.getInventory().addItem(itemToReturn);
|
||||||
}
|
}
|
||||||
@ -157,13 +163,20 @@ public abstract class Session implements Runnable {
|
|||||||
*/
|
*/
|
||||||
protected abstract int getActionDelay();
|
protected abstract int getActionDelay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the appropriate crafting station for this session
|
||||||
|
*
|
||||||
|
* @return <p>The appropriate crafting station</p>
|
||||||
|
*/
|
||||||
|
protected abstract @NotNull Material getCraftingStation();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plays an NPC sound
|
* Plays an NPC sound
|
||||||
*
|
*
|
||||||
* @param sound <p>The sound to play</p>
|
* @param sound <p>The sound to play</p>
|
||||||
*/
|
*/
|
||||||
protected void playSound(Sound sound) {
|
protected void playSound(Sound sound) {
|
||||||
playSound(this.npc.getEntity(), sound);
|
playSound(this.entity, sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,14 +191,13 @@ public abstract class Session implements Runnable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPCSoundEvent event = new NPCSoundEvent(this.npc, this.player, SoundCategory.AMBIENT, sound, 0.5f, 1.0f);
|
NPCSoundEvent event = new NPCSoundEvent(this.npc, this.entity, this.player, SoundCategory.AMBIENT, sound, 0.5f, 1.0f);
|
||||||
BlacksmithPlugin.getInstance().callEvent(event);
|
BlacksmithPlugin.getInstance().callEvent(event);
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
world.playSound(event.getNpc().getEntity(), event.getSound(), event.getSoundCategory(), event.getVolume(),
|
world.playSound(event.getEntity(), event.getSound(), event.getSoundCategory(), event.getVolume(), event.getPitch());
|
||||||
event.getPitch());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.util;
|
|||||||
|
|
||||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
||||||
import net.knarcraft.blacksmith.container.RecipeResult;
|
import net.knarcraft.blacksmith.container.RecipeResult;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
@ -10,6 +11,8 @@ import org.bukkit.inventory.Recipe;
|
|||||||
import org.bukkit.inventory.ShapedRecipe;
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
import org.bukkit.inventory.ShapelessRecipe;
|
import org.bukkit.inventory.ShapelessRecipe;
|
||||||
import org.bukkit.inventory.meta.ArmorMeta;
|
import org.bukkit.inventory.meta.ArmorMeta;
|
||||||
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
import org.bukkit.inventory.meta.trim.ArmorTrim;
|
||||||
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
import org.bukkit.inventory.meta.trim.TrimMaterial;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -44,6 +47,51 @@ public final class SalvageHelper {
|
|||||||
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
|
trimMaterialToMaterial.put(TrimMaterial.REDSTONE, Material.REDSTONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets salvage for an enchanted book
|
||||||
|
*
|
||||||
|
* @param itemStack <p>The enchanted book(s) to salvage</p>
|
||||||
|
* @return <p>The resulting salvage</p>
|
||||||
|
* @throws RuntimeException <p>If generated enchanted book metadata is null</p>
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static List<ItemStack> getEnchantedBookSalvage(@NotNull ItemStack itemStack) {
|
||||||
|
ItemMeta meta = itemStack.getItemMeta();
|
||||||
|
List<ItemStack> output = new ArrayList<>();
|
||||||
|
|
||||||
|
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Enchantment, Integer> enchantmentMap = enchantmentStorageMeta.getStoredEnchants();
|
||||||
|
for (Map.Entry<Enchantment, Integer> enchantmentEntry : enchantmentMap.entrySet()) {
|
||||||
|
EnchantmentStorageMeta enchantmentMeta = (EnchantmentStorageMeta) Bukkit.getServer().getItemFactory().getItemMeta(Material.ENCHANTED_BOOK);
|
||||||
|
if (enchantmentMeta == null) {
|
||||||
|
throw new RuntimeException("Unable to create enchanted book metadata.");
|
||||||
|
}
|
||||||
|
enchantmentMeta.addStoredEnchant(enchantmentEntry.getKey(), enchantmentEntry.getValue(), true);
|
||||||
|
ItemStack newBook = new ItemStack(Material.ENCHANTED_BOOK, 1);
|
||||||
|
newBook.setItemMeta(enchantmentMeta);
|
||||||
|
output.add(newBook);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of enchantments applied to an enchanted book
|
||||||
|
*
|
||||||
|
* @param itemStack <p>The enchanted book to check</p>
|
||||||
|
* @return <p>The number of enchantments, or -1 if not an enchanted book</p>
|
||||||
|
*/
|
||||||
|
public static int getEnchantmentCount(@NotNull ItemStack itemStack) {
|
||||||
|
ItemMeta meta = itemStack.getItemMeta();
|
||||||
|
if (!(meta instanceof EnchantmentStorageMeta enchantmentStorageMeta)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return enchantmentStorageMeta.getStoredEnchants().size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets salvage for a given netherite item
|
* Gets salvage for a given netherite item
|
||||||
*
|
*
|
||||||
|
@ -38,6 +38,8 @@ public final class TabCompleteValuesHelper {
|
|||||||
case MATERIAL -> getAllReforgeAbleMaterialNames();
|
case MATERIAL -> getAllReforgeAbleMaterialNames();
|
||||||
case ENCHANTMENT, ENCHANTMENT_LIST -> getAllEnchantments();
|
case ENCHANTMENT, ENCHANTMENT_LIST -> getAllEnchantments();
|
||||||
case STRING_LIST -> List.of("*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK,SMITHING_TABLE:*_PLANKS");
|
case STRING_LIST -> List.of("*_SHOVEL,*_PICKAXE,*_AXE,*_HOE,*_SWORD:STICK,SMITHING_TABLE:*_PLANKS");
|
||||||
|
// TODO: Change this to something that makes sense
|
||||||
|
case ADVANCED_COST -> List.of();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ public final class TypeValidationHelper {
|
|||||||
case STRING -> isNonEmptyString(value, sender);
|
case STRING -> isNonEmptyString(value, sender);
|
||||||
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
|
||||||
case PERCENTAGE -> isPercentage(value, sender);
|
case PERCENTAGE -> isPercentage(value, sender);
|
||||||
case BOOLEAN -> true;
|
// TODO: Implement proper advanced cost checking
|
||||||
|
case BOOLEAN, ADVANCED_COST -> true;
|
||||||
case REFORGE_ABLE_ITEMS, STRING_LIST -> isStringList(value, sender);
|
case REFORGE_ABLE_ITEMS, STRING_LIST -> isStringList(value, sender);
|
||||||
case MATERIAL -> isMaterial(value, sender);
|
case MATERIAL -> isMaterial(value, sender);
|
||||||
case ENCHANTMENT -> isEnchantment(value, sender);
|
case ENCHANTMENT -> isEnchantment(value, sender);
|
||||||
|
@ -112,6 +112,9 @@ blacksmith:
|
|||||||
# The message to display if a player is trying to reforge an item with full durability
|
# The message to display if a player is trying to reforge an item with full durability
|
||||||
notDamagedMessage: "&cThat item is not in need of repair"
|
notDamagedMessage: "&cThat item is not in need of repair"
|
||||||
|
|
||||||
|
# The message to display when a blacksmith is clicked with an empty hand
|
||||||
|
noItemMessage: "Please present the item you want to reforge"
|
||||||
|
|
||||||
# Settings for the scrapper trait
|
# Settings for the scrapper trait
|
||||||
scrapper:
|
scrapper:
|
||||||
# The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command
|
# The settings which apply to all Scrapper NPCs. These can also be changed using the /scrapperConfig command
|
||||||
@ -139,6 +142,14 @@ scrapper:
|
|||||||
# The cost of using the scrapper to remove netherite from an item
|
# The cost of using the scrapper to remove netherite from an item
|
||||||
netheriteSalvagePrice: 15
|
netheriteSalvagePrice: 15
|
||||||
|
|
||||||
|
# The mathematical formula for salvage cost increase when continually used within the same hour. This is necessary
|
||||||
|
# for some servers where items can be easily farmed. Set to {cost} to disable behavior.
|
||||||
|
salvageCostIncrease: "{cost}*{timesUsed}"
|
||||||
|
|
||||||
|
# The mathematical formula for salvage cooldown increase when continually used within the same hour. This is
|
||||||
|
# necessary for some servers where items can be easily farmed. Set to {cooldown} to disable behavior.
|
||||||
|
salvageCooldownIncrease: "{cooldown}*{timesUsed}"
|
||||||
|
|
||||||
# The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must
|
# 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
|
# change the Citizens NPC file, or use the /scrapper command
|
||||||
defaults:
|
defaults:
|
||||||
@ -179,6 +190,9 @@ scrapper:
|
|||||||
# Whether to enable salvaging of netherite items
|
# Whether to enable salvaging of netherite items
|
||||||
salvageNetherite: true
|
salvageNetherite: true
|
||||||
|
|
||||||
|
# Whether to enable salvaging an enchanted books with several enchantments into several books with one enchantment
|
||||||
|
splitEnchantedBook: false
|
||||||
|
|
||||||
# Default values for messages used by NPCs
|
# Default values for messages used by NPCs
|
||||||
messages:
|
messages:
|
||||||
# The message to display when another player is using the scrapper
|
# The message to display when another player is using the scrapper
|
||||||
@ -223,6 +237,9 @@ scrapper:
|
|||||||
# The message to display when explaining the shown item's netherite salvage cost
|
# 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!"
|
costMessageNetherite: "&eIt will cost &a{cost}&e to salvage that &a{item}&e into diamond!"
|
||||||
|
|
||||||
|
# The message to display when explaining the shown enchanted book's salvage cost
|
||||||
|
costMessageEnchantedBook: "&eIt will cost &a{cost}&e to salvage that enchanted book!"
|
||||||
|
|
||||||
# The yield message to display if trying to salvage a non-damaged item
|
# 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"
|
fullSalvageMessage: "&aI should be able to extract all components from that pristine item.&r"
|
||||||
|
|
||||||
@ -240,3 +257,12 @@ scrapper:
|
|||||||
|
|
||||||
# The message to display when asked to salvage netherite items, and that option is disabled
|
# 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!"
|
cannotSalvageNetheriteMessage: "&cI'm sorry, but I'm unable to salvage netherite items!"
|
||||||
|
|
||||||
|
# The message displayed when explaining that enchanted book salvage is disabled
|
||||||
|
cannotSalvageEnchantedBookMessage: "&cI'm sorry, but I'm unable to salvage enchanted books!"
|
||||||
|
|
||||||
|
# The message displayed when a player attempts to salvage an enchanted book with a single enchantment
|
||||||
|
cannotSplitEnchantedBookFurtherMessage: "&cI'm sorry, but I cannot salvage that enchanted book any further"
|
||||||
|
|
||||||
|
# The message to display when a scrapper is clicked with an empty hand
|
||||||
|
noItemMessage: "Please present the item you want to salvage"
|
@ -43,7 +43,7 @@ en:
|
|||||||
# The format used when displaying any duration remaining
|
# The format used when displaying any duration remaining
|
||||||
DURATION_FORMAT: "in {time} {unit}"
|
DURATION_FORMAT: "in {time} {unit}"
|
||||||
# The format used when NPCs talk to players ({npc} = The NPC's name, {message} is the actual message contents)
|
# The format used when NPCs talk to players ({npc} = The NPC's name, {message} is the actual message contents)
|
||||||
NPC_TALK_FORMAT: "&a[{npc}] -> You:&r {message}"
|
NPC_TALK_FORMAT: "&a[{npc}&r&a] -> You:&r {message}"
|
||||||
# Translation of the duration of less than a second
|
# Translation of the duration of less than a second
|
||||||
UNIT_NOW: "imminently"
|
UNIT_NOW: "imminently"
|
||||||
# Translation of seconds in singular form
|
# Translation of seconds in singular form
|
||||||
@ -90,3 +90,5 @@ en:
|
|||||||
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
INTERVAL_MORE_THAN_5_MINUTES: "in quite a while"
|
||||||
# The marker shown when displaying values overridden for the selected NPC (not shown if the NPC inherits the default value)
|
# The marker shown when displaying values overridden for the selected NPC (not shown if the NPC inherits the default value)
|
||||||
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
SETTING_OVERRIDDEN_MARKER: " [NPC]"
|
||||||
|
# The translation of the text displayed when a cost is expected, but a non-number is provided
|
||||||
|
DOUBLE_COST_REQUIRED: "You must supply a numeric (double) cost"
|
Reference in New Issue
Block a user