2022-08-08 14:14:42 +02:00
|
|
|
package net.knarcraft.blacksmith.trait;
|
2022-02-01 22:24:39 +01:00
|
|
|
|
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
2022-08-08 14:14:42 +02:00
|
|
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
2022-08-07 01:21:47 +02:00
|
|
|
import net.knarcraft.blacksmith.config.NPCSettings;
|
2022-08-08 14:14:42 +02:00
|
|
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
2022-10-24 13:57:58 +02:00
|
|
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
2022-10-03 13:03:21 +02:00
|
|
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
2022-02-01 22:24:39 +01:00
|
|
|
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;
|
2022-10-14 21:45:57 +02:00
|
|
|
import org.bukkit.scheduler.BukkitScheduler;
|
2022-02-01 22:24:39 +01:00
|
|
|
|
2022-10-02 23:50:07 +02:00
|
|
|
import java.util.ArrayList;
|
2022-02-01 22:24:39 +01:00
|
|
|
import java.util.Calendar;
|
2022-10-02 23:50:07 +02:00
|
|
|
import java.util.List;
|
2022-02-01 22:24:39 +01:00
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Random;
|
2022-08-05 17:07:16 +02:00
|
|
|
import java.util.logging.Level;
|
2022-02-01 22:24:39 +01:00
|
|
|
|
2022-10-03 18:15:38 +02:00
|
|
|
import static net.knarcraft.blacksmith.formatting.StringFormatter.sendNPCMessage;
|
2022-09-29 01:49:12 +02:00
|
|
|
|
2022-07-19 02:38:35 +02:00
|
|
|
/**
|
|
|
|
* A representation of the session between a player and a blacksmith
|
|
|
|
*/
|
|
|
|
public class ReforgeSession implements Runnable {
|
|
|
|
|
2022-02-01 22:24:39 +01:00
|
|
|
private final BlacksmithTrait blacksmithTrait;
|
|
|
|
private final Player player;
|
|
|
|
private final NPC npc;
|
|
|
|
private final ItemStack itemToReforge;
|
|
|
|
private int taskId;
|
2022-10-14 21:45:57 +02:00
|
|
|
private long finishTime = 0;
|
2022-08-07 01:21:47 +02:00
|
|
|
private final NPCSettings config;
|
2022-02-01 22:24:39 +01:00
|
|
|
private static final String[] enchantments = new String[Enchantment.values().length];
|
2022-08-08 14:14:42 +02:00
|
|
|
private static final Random random = new Random();
|
2022-02-01 22:24:39 +01:00
|
|
|
|
2022-07-19 02:38:35 +02:00
|
|
|
/**
|
|
|
|
* Instantiates a new session
|
|
|
|
*
|
|
|
|
* @param blacksmithTrait <p>A reference to the blacksmith trait</p>
|
|
|
|
* @param player <p>The player initiating the session</p>
|
|
|
|
* @param npc <p>The Blacksmith NPC involved in the session</p>
|
|
|
|
* @param config <p>The config to use for the session</p>
|
|
|
|
*/
|
2022-08-07 01:21:47 +02:00
|
|
|
ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, NPCSettings config) {
|
2022-02-01 22:24:39 +01:00
|
|
|
this.blacksmithTrait = blacksmithTrait;
|
|
|
|
this.player = player;
|
|
|
|
this.npc = npc;
|
2022-10-14 21:45:57 +02:00
|
|
|
this.itemToReforge = player.getInventory().getItemInMainHand();
|
2022-02-01 22:24:39 +01:00
|
|
|
this.config = config;
|
|
|
|
|
2022-10-14 21:45:57 +02:00
|
|
|
//Populate enchantments the first time this is run
|
|
|
|
if (enchantments[0] == null) {
|
|
|
|
int i = 0;
|
|
|
|
for (Enchantment enchantment : Enchantment.values()) {
|
2022-10-24 13:57:58 +02:00
|
|
|
enchantments[i++] = enchantment.getKey().getKey();
|
2022-10-14 21:45:57 +02:00
|
|
|
}
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-14 21:45:57 +02:00
|
|
|
/**
|
|
|
|
* Gets the time in milliseconds when this reforging session will finish
|
|
|
|
*
|
|
|
|
* @return <p>The time the reforging will finish</p>
|
|
|
|
*/
|
|
|
|
public long getFinishTime() {
|
|
|
|
return this.finishTime;
|
|
|
|
}
|
|
|
|
|
2022-08-08 14:14:42 +02:00
|
|
|
/**
|
2022-10-03 12:39:15 +02:00
|
|
|
* Runs the actual reforge which fixes the item and gives it back to the player
|
2022-08-08 14:14:42 +02:00
|
|
|
*/
|
2022-02-01 22:24:39 +01:00
|
|
|
@Override
|
|
|
|
public void run() {
|
2022-09-29 01:49:12 +02:00
|
|
|
sendNPCMessage(this.npc, player, reforgeItem() ? config.getSuccessMessage() : config.getFailMessage());
|
2022-08-08 14:14:42 +02:00
|
|
|
|
2022-10-03 12:39:15 +02:00
|
|
|
//Stop the reforged item from displaying in the blacksmith's hand
|
2022-02-01 22:24:39 +01:00
|
|
|
if (npc.getEntity() instanceof Player) {
|
|
|
|
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
|
|
|
|
} else {
|
|
|
|
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
|
|
|
}
|
2022-08-08 14:14:42 +02:00
|
|
|
|
|
|
|
//Give the item back to the player
|
2022-02-01 22:24:39 +01:00
|
|
|
if (!config.getDisableDelay()) {
|
2022-08-19 19:08:54 +02:00
|
|
|
//If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing
|
|
|
|
if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
|
2022-02-01 22:24:39 +01:00
|
|
|
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
|
|
|
|
} else {
|
|
|
|
player.getInventory().addItem(itemToReforge);
|
|
|
|
}
|
|
|
|
} else {
|
2022-08-19 19:08:54 +02:00
|
|
|
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected
|
2022-02-01 22:24:39 +01:00
|
|
|
player.getInventory().setItemInMainHand(itemToReforge);
|
|
|
|
}
|
2022-08-08 14:14:42 +02:00
|
|
|
|
|
|
|
//Mark this blacksmith as available
|
2022-02-01 22:24:39 +01:00
|
|
|
blacksmithTrait.unsetSession();
|
2022-08-08 14:14:42 +02:00
|
|
|
|
|
|
|
// Start cool-down
|
2022-02-01 22:24:39 +01:00
|
|
|
Calendar wait = Calendar.getInstance();
|
|
|
|
wait.add(Calendar.SECOND, config.getReforgeCoolDown());
|
|
|
|
blacksmithTrait.addCoolDown(player.getUniqueId(), wait);
|
|
|
|
}
|
|
|
|
|
2022-08-08 14:14:42 +02:00
|
|
|
/**
|
2022-10-03 12:39:15 +02:00
|
|
|
* Performs the actual reforge where the item's damage is reduced
|
2022-08-08 14:14:42 +02:00
|
|
|
*
|
2022-10-03 12:39:15 +02:00
|
|
|
* @return <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p>
|
2022-08-08 14:14:42 +02:00
|
|
|
*/
|
|
|
|
private boolean reforgeItem() {
|
2022-02-01 22:24:39 +01:00
|
|
|
if (random.nextInt(100) < config.getFailChance()) {
|
2022-08-08 14:14:42 +02:00
|
|
|
failReforge();
|
2022-02-01 22:24:39 +01:00
|
|
|
return false;
|
|
|
|
} else {
|
2022-08-08 14:14:42 +02:00
|
|
|
succeedReforge();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2022-02-01 22:24:39 +01:00
|
|
|
|
2022-08-08 14:14:42 +02:00
|
|
|
/**
|
2022-10-03 12:39:15 +02:00
|
|
|
* The method to run when a blacksmith successfully reforges an item
|
2022-08-08 14:14:42 +02:00
|
|
|
*/
|
|
|
|
private void succeedReforge() {
|
|
|
|
// Remove any damage done to the item
|
|
|
|
updateDamage(itemToReforge, 0);
|
|
|
|
|
|
|
|
// Add random enchantments
|
|
|
|
int roll = random.nextInt(100);
|
|
|
|
if (!(roll < config.getExtraEnchantmentChance() &&
|
|
|
|
itemToReforge.getEnchantments().keySet().size() < config.getMaxEnchantments())) {
|
|
|
|
// Abort if randomness isn't on our side, or if max enchantments has been reached
|
|
|
|
return;
|
|
|
|
}
|
2022-10-02 23:50:07 +02:00
|
|
|
|
|
|
|
//Find usable enchantments first
|
|
|
|
List<Enchantment> usableEnchantments = new ArrayList<>();
|
|
|
|
for (String enchantmentName : enchantments) {
|
2022-10-24 13:57:58 +02:00
|
|
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
2022-10-02 23:50:07 +02:00
|
|
|
if (enchantment != null && enchantment.canEnchantItem(itemToReforge)) {
|
|
|
|
usableEnchantments.add(enchantment);
|
|
|
|
}
|
|
|
|
}
|
2022-11-05 04:21:47 +01:00
|
|
|
//Remove any enchantments in the block list
|
|
|
|
usableEnchantments.removeAll(blacksmithTrait.getSettings().getEnchantmentBlocklist());
|
|
|
|
|
|
|
|
//In case all usable enchantments have been blocked, abort
|
|
|
|
if (usableEnchantments.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-10-02 23:50:07 +02:00
|
|
|
|
|
|
|
//Choose a random enchantment
|
|
|
|
Enchantment randomEnchantment = usableEnchantments.get(random.nextInt(usableEnchantments.size()));
|
|
|
|
if (randomEnchantment != null) {
|
|
|
|
int randomBound = randomEnchantment.getMaxLevel() + 1;
|
2022-08-08 14:14:42 +02:00
|
|
|
//A workaround for the random method's bound sometimes being negative
|
|
|
|
if (randomBound >= 0) {
|
2022-10-02 23:50:07 +02:00
|
|
|
int existingLevel = itemToReforge.getEnchantmentLevel(randomEnchantment);
|
|
|
|
/* Add a random enchantment whose level is no lower than the start level, and no lower than the
|
|
|
|
existing level (to prevent making the item worse) */
|
|
|
|
itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
|
|
|
|
randomEnchantment.getStartLevel()), existingLevel));
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 14:14:42 +02:00
|
|
|
/**
|
|
|
|
* The method to run when a blacksmith fails re-forging an item
|
|
|
|
*/
|
|
|
|
private void failReforge() {
|
|
|
|
// Remove or downgrade existing enchantments
|
|
|
|
for (Enchantment enchantment : itemToReforge.getEnchantments().keySet()) {
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
itemToReforge.removeEnchantment(enchantment);
|
|
|
|
} else {
|
|
|
|
if (itemToReforge.getEnchantmentLevel(enchantment) > 1) {
|
|
|
|
itemToReforge.removeEnchantment(enchantment);
|
|
|
|
itemToReforge.addEnchantment(enchantment, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Damage the item
|
2022-10-03 13:03:21 +02:00
|
|
|
short currentItemDurability = ItemHelper.getDurability(itemToReforge);
|
2022-08-08 14:14:42 +02:00
|
|
|
short newDurability = (short) (currentItemDurability + (currentItemDurability * random.nextInt(8)));
|
|
|
|
short maxDurability = itemToReforge.getType().getMaxDurability();
|
|
|
|
if (newDurability <= 0) {
|
|
|
|
newDurability = (short) (maxDurability / 3);
|
|
|
|
} else if (currentItemDurability + newDurability > maxDurability) {
|
|
|
|
newDurability = (short) (maxDurability - random.nextInt(maxDurability - 25));
|
|
|
|
}
|
|
|
|
updateDamage(itemToReforge, maxDurability - newDurability);
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
|
|
|
* Updates the damage done to an item
|
|
|
|
*
|
|
|
|
* @param item <p>The item to update damage for</p>
|
|
|
|
* @param newDamage <p>The new damage done</p>
|
|
|
|
*/
|
2022-02-01 22:24:39 +01:00
|
|
|
private void updateDamage(ItemStack item, int newDamage) {
|
|
|
|
ItemMeta meta = item.getItemMeta();
|
|
|
|
Damageable damageable = (Damageable) meta;
|
2022-08-05 17:07:16 +02:00
|
|
|
if (damageable != null) {
|
|
|
|
damageable.setDamage(newDamage);
|
|
|
|
} else {
|
|
|
|
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to change damage of " + item);
|
|
|
|
}
|
2022-02-01 22:24:39 +01:00
|
|
|
item.setItemMeta(meta);
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
|
|
|
* Gets whether to end the current session
|
|
|
|
*
|
|
|
|
* <p>If the player has switched their item, or the player cannot pay, this returns true.</p>
|
|
|
|
*
|
|
|
|
* @return <p>True if the current session should end</p>
|
|
|
|
*/
|
|
|
|
public boolean endSession() {
|
2022-02-01 22:24:39 +01:00
|
|
|
// Prevent player from switching items during session
|
2022-02-02 00:36:15 +01:00
|
|
|
ItemStack itemInHand = player.getInventory().getItemInMainHand();
|
|
|
|
if (!itemToReforge.equals(itemInHand)) {
|
2022-09-29 01:49:12 +02:00
|
|
|
sendNPCMessage(this.npc, player, config.getItemChangedMessage());
|
2022-02-01 22:24:39 +01:00
|
|
|
return true;
|
|
|
|
}
|
2022-08-05 17:07:16 +02:00
|
|
|
// The player is unable to pay
|
2022-08-07 01:21:47 +02:00
|
|
|
if (!EconomyManager.canPay(player)) {
|
2022-09-29 01:49:12 +02:00
|
|
|
sendNPCMessage(this.npc, player, config.getInsufficientFundsMessage());
|
2022-02-01 22:24:39 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
|
|
|
* Gets whether the current session is still running
|
|
|
|
*
|
|
|
|
* @return <p>True if the current session is still running</p>
|
|
|
|
*/
|
|
|
|
public boolean isRunning() {
|
2022-02-01 22:24:39 +01:00
|
|
|
return BlacksmithPlugin.getInstance().getServer().getScheduler().isQueued(taskId);
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
2022-10-03 12:39:15 +02:00
|
|
|
* Gets whether the given player is currently in a reforging session
|
2022-08-05 17:07:16 +02:00
|
|
|
*
|
|
|
|
* @param other <p>The player to check if is in session</p>
|
2022-10-03 12:39:15 +02:00
|
|
|
* @return <p>True if the given player is in a reforge session</p>
|
2022-08-05 17:07:16 +02:00
|
|
|
*/
|
|
|
|
public boolean isInSession(Player other) {
|
2022-02-01 22:24:39 +01:00
|
|
|
return player.getName().equals(other.getName());
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
|
|
|
* Begins the actual item reforging
|
|
|
|
*/
|
|
|
|
public void beginReforge() {
|
2022-10-14 21:45:57 +02:00
|
|
|
BukkitScheduler scheduler = BlacksmithPlugin.getInstance().getServer().getScheduler();
|
|
|
|
int reforgeDelay;
|
2022-02-01 22:24:39 +01:00
|
|
|
if (!config.getDisableCoolDown()) {
|
2022-10-03 12:39:15 +02:00
|
|
|
//Finish the reforging after a random delay between the max and min
|
2022-10-14 21:45:57 +02:00
|
|
|
reforgeDelay = new Random().nextInt(config.getMaxReforgeDelay()) + config.getMinReforgeDelay();
|
2022-02-01 22:24:39 +01:00
|
|
|
} else {
|
2022-10-03 12:39:15 +02:00
|
|
|
//Finish the reforging as soon as possible
|
2022-10-14 21:45:57 +02:00
|
|
|
reforgeDelay = 0;
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|
2022-10-14 21:45:57 +02:00
|
|
|
this.finishTime = System.currentTimeMillis() + (reforgeDelay * 1000L);
|
|
|
|
taskId = scheduler.scheduleSyncDelayedTask(BlacksmithPlugin.getInstance(), this, reforgeDelay * 20L);
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 17:07:16 +02:00
|
|
|
/**
|
|
|
|
* Gets the player currently in this reforge session
|
|
|
|
*
|
|
|
|
* @return <p>The player currently in this reforge session</p>
|
|
|
|
*/
|
2022-02-01 22:24:39 +01:00
|
|
|
public Player getPlayer() {
|
|
|
|
return player;
|
|
|
|
}
|
2022-07-19 02:38:35 +02:00
|
|
|
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|