package net.knarcraft.blacksmith; import net.citizensnpcs.api.npc.NPC; import net.knarcraft.blacksmith.config.NPCSettings; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import java.util.Calendar; import java.util.Objects; import java.util.Random; import java.util.logging.Level; /** * A representation of the session between a player and a blacksmith */ public class ReforgeSession implements Runnable { private final BlacksmithTrait blacksmithTrait; private final Player player; private final NPC npc; private final ItemStack itemToReforge; private int taskId; private final NPCSettings config; private static final String[] enchantments = new String[Enchantment.values().length]; /** * Instantiates a new session * * @param blacksmithTrait

A reference to the blacksmith trait

* @param player

The player initiating the session

* @param npc

The Blacksmith NPC involved in the session

* @param config

The config to use for the session

*/ ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, NPCSettings config) { this.blacksmithTrait = blacksmithTrait; this.player = player; this.npc = npc; itemToReforge = player.getInventory().getItemInMainHand(); this.config = config; int i = 0; for (Enchantment enchantment : Enchantment.values()) { enchantments[i++] = enchantment.getKey().toString(); } } @Override public void run() { player.sendMessage(reforgeItemInHand() ? config.getSuccessMessage() : config.getFailMessage()); if (npc.getEntity() instanceof Player) { ((Player) npc.getEntity()).getInventory().setItemInMainHand(null); } else { Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null); } if (!config.getDisableDelay()) { if (config.getDropItem()) { player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge); } else { player.getInventory().addItem(itemToReforge); } } else { player.getInventory().setItemInMainHand(itemToReforge); } blacksmithTrait.unsetSession(); // Start cool down Calendar wait = Calendar.getInstance(); wait.add(Calendar.SECOND, config.getReforgeCoolDown()); blacksmithTrait.addCoolDown(player.getUniqueId(), wait); } private boolean reforgeItemInHand() { Random random = new Random(); if (random.nextInt(100) < config.getFailChance()) { for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) { // Remove or downgrade enchantments if (random.nextBoolean()) { itemToReforge.removeEnchantment(enchantment); } else { if (itemToReforge.getEnchantmentLevel(enchantment) > 1) { itemToReforge.removeEnchantment(enchantment); itemToReforge.addEnchantment(enchantment, 1); } } } // Damage the item short reforgeDurability = EconomyManager.getDurability(itemToReforge); short durability = (short) (reforgeDurability + reforgeDurability * random.nextInt(8)); short maxDurability = itemToReforge.getType().getMaxDurability(); if (durability <= 0) { durability = (short) (maxDurability / 3); } else if (reforgeDurability + durability > maxDurability) { durability = (short) (maxDurability - random.nextInt(maxDurability - 25)); } updateDamage(itemToReforge, maxDurability - durability); return false; } else { updateDamage(itemToReforge, 0); // Add random enchantments int roll = random.nextInt(100); if (roll < config.getExtraEnchantmentChance() && itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments()) { Enchantment enchantment = Enchantment.getByKey(NamespacedKey.fromString(enchantments[random.nextInt(enchantments.length)])); if (Objects.requireNonNull(enchantment).canEnchantItem(itemToReforge)) { int randomBound = enchantment.getMaxLevel() - enchantment.getStartLevel(); //A workaround for the random method's bound sometimes being negative if (randomBound >= 0) { itemToReforge.addEnchantment(enchantment, random.nextInt(randomBound) + enchantment.getStartLevel()); } } } return true; } } /** * Updates the damage done to an item * * @param item

The item to update damage for

* @param newDamage

The new damage done

*/ private void updateDamage(ItemStack item, int newDamage) { ItemMeta meta = item.getItemMeta(); Damageable damageable = (Damageable) meta; if (damageable != null) { damageable.setDamage(newDamage); } else { BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to change damage of " + item); } item.setItemMeta(meta); } /** * Gets whether to end the current session * *

If the player has switched their item, or the player cannot pay, this returns true.

* * @return

True if the current session should end

*/ public boolean endSession() { // Prevent player from switching items during session ItemStack itemInHand = player.getInventory().getItemInMainHand(); if (!itemToReforge.equals(itemInHand)) { player.sendMessage(config.getItemChangedMessage()); return true; } // The player is unable to pay if (!EconomyManager.canPay(player)) { player.sendMessage(config.getInsufficientFundsMessage()); return true; } return false; } /** * Gets whether the current session is still running * * @return

True if the current session is still running

*/ public boolean isRunning() { return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId); } /** * Gets whether the given player is currently in a re-forge session * * @param other

The player to check if is in session

* @return

True if the given player is in a re-forge session

*/ public boolean isInSession(Player other) { return player.getName().equals(other.getName()); } /** * Begins the actual item reforging */ public void beginReforge() { if (!config.getDisableCoolDown()) { //Finish the re-forge after a random delay between the max and min taskId = BlacksmithPlugin.getInstance().getServer().getScheduler().scheduleSyncDelayedTask( BlacksmithPlugin.getInstance(), this, (new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay()) * 20L); } else { //Finish the re-forge as soon as possible taskId = BlacksmithPlugin.getInstance().getServer().getScheduler().scheduleSyncDelayedTask( BlacksmithPlugin.getInstance(), this, 0); } } /** * Gets the player currently in this reforge session * * @return

The player currently in this reforge session

*/ public Player getPlayer() { return player; } }