233 lines
8.9 KiB
Java
233 lines
8.9 KiB
Java
package net.knarcraft.blacksmith.trait;
|
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
|
import net.knarcraft.blacksmith.BlacksmithPlugin;
|
|
import net.knarcraft.blacksmith.config.blacksmith.BlacksmithNPCSettings;
|
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
|
import net.knarcraft.blacksmith.util.InputParsingHelper;
|
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.Registry;
|
|
import org.bukkit.Sound;
|
|
import org.bukkit.enchantments.Enchantment;
|
|
import org.bukkit.entity.LivingEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Calendar;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Random;
|
|
import java.util.logging.Level;
|
|
|
|
import static net.knarcraft.blacksmith.formatting.BlacksmithStringFormatter.sendNPCMessage;
|
|
|
|
/**
|
|
* A representation of the session between a player and a blacksmith
|
|
*/
|
|
public class ReforgeSession extends Session implements Runnable {
|
|
|
|
private final BlacksmithTrait blacksmithTrait;
|
|
private final ItemStack itemToReforge;
|
|
private final BlacksmithNPCSettings config;
|
|
private static List<String> enchantments = null;
|
|
|
|
/**
|
|
* 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>
|
|
*/
|
|
ReforgeSession(@NotNull BlacksmithTrait blacksmithTrait, @NotNull Player player, @NotNull NPC npc,
|
|
@NotNull BlacksmithNPCSettings config) {
|
|
super(player, npc);
|
|
this.blacksmithTrait = blacksmithTrait;
|
|
this.itemToReforge = player.getInventory().getItemInMainHand();
|
|
this.config = config;
|
|
|
|
//Populate enchantments the first time this is run
|
|
if (enchantments == null) {
|
|
Registry<Enchantment> enchantmentRegistry = Bukkit.getRegistry(Enchantment.class);
|
|
if (enchantmentRegistry == null) {
|
|
throw new RuntimeException("Unable to get enchantment registry");
|
|
}
|
|
|
|
enchantments = new ArrayList<>();
|
|
for (Enchantment enchantment : enchantmentRegistry) {
|
|
enchantments.add(enchantment.getKey().getKey());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isSessionInvalid() {
|
|
// Prevent player from switching items during session
|
|
ItemStack itemInHand = this.player.getInventory().getItemInMainHand();
|
|
if (!itemToReforge.equals(itemInHand)) {
|
|
sendNPCMessage(this.npc, this.player, this.config.getItemChangedMessage());
|
|
return true;
|
|
}
|
|
// The player is unable to pay
|
|
if (EconomyManager.cannotPayForHeldItemReforge(this.player)) {
|
|
sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected int getActionDelay() {
|
|
if (this.config.getMaxReforgeDelay() > 0) {
|
|
//Finish the reforging after a random delay between the max and min
|
|
return new Random().nextInt(this.config.getMaxReforgeDelay()) + this.config.getMinReforgeDelay();
|
|
} else {
|
|
//Finish the salvaging as soon as possible
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Runs the actual reforge which fixes the item and gives it back to the player
|
|
*/
|
|
@Override
|
|
public void run() {
|
|
boolean success = reforgeItem();
|
|
sendNPCMessage(this.npc, this.player, success ? this.config.getSuccessMessage() : this.config.getFailMessage());
|
|
playSound(success ? Sound.BLOCK_ANVIL_USE : Sound.ENTITY_VILLAGER_NO);
|
|
|
|
//Stop the reforged item from displaying in the blacksmith's hand
|
|
if (this.npc.getEntity() instanceof Player) {
|
|
((Player) this.npc.getEntity()).getInventory().setItemInMainHand(null);
|
|
} else {
|
|
Objects.requireNonNull(((LivingEntity) this.npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
|
}
|
|
|
|
//Give the item back to the player
|
|
giveReforgedItem();
|
|
|
|
//Mark this blacksmith as available
|
|
this.blacksmithTrait.unsetSession();
|
|
|
|
// Start cool-down
|
|
Calendar wait = Calendar.getInstance();
|
|
wait.add(Calendar.SECOND, this.config.getReforgeCoolDown());
|
|
this.blacksmithTrait.addCoolDown(this.player.getUniqueId(), wait);
|
|
}
|
|
|
|
/**
|
|
* Gives the reforged item back to the player
|
|
*/
|
|
private void giveReforgedItem() {
|
|
giveResultingItem(this.config.getMaxReforgeDelay() > 0, this.config.getDropItem(), this.npc,
|
|
this.itemToReforge);
|
|
}
|
|
|
|
/**
|
|
* Performs the actual reforge where the item's damage is reduced
|
|
*
|
|
* @return <p>Whether the reforge was successful. False if the blacksmith failed to fully repair the item.</p>
|
|
*/
|
|
private boolean reforgeItem() {
|
|
if (random.nextInt(100) < this.config.getFailChance()) {
|
|
failReforge();
|
|
return false;
|
|
} else {
|
|
succeedReforge();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The method to run when a blacksmith successfully reforges an item
|
|
*/
|
|
private void succeedReforge() {
|
|
// Remove any damage done to the item
|
|
if (ItemHelper.updateDamage(this.itemToReforge, 0)) {
|
|
BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to update damage for " +
|
|
this.itemToReforge);
|
|
}
|
|
|
|
//Replace damaged anvils with a normal anvil
|
|
if (ItemHelper.isAnvil(this.itemToReforge.getType(), true)) {
|
|
this.itemToReforge.setType(Material.ANVIL);
|
|
}
|
|
|
|
//See if a random roll (0-99) is less than extraEnchantmentChance, and add a random enchantment
|
|
int roll = random.nextInt(100);
|
|
if (roll < this.config.getExtraEnchantmentChance() &&
|
|
this.itemToReforge.getEnchantments().keySet().size() < this.config.getMaxEnchantments() &&
|
|
!ItemHelper.isAnvil(this.itemToReforge.getType(), false)) {
|
|
addRandomEnchantment();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a random enchantment to the currently reforged item
|
|
*/
|
|
private void addRandomEnchantment() {
|
|
//Find usable enchantments first
|
|
List<Enchantment> usableEnchantments = new ArrayList<>();
|
|
for (String enchantmentName : enchantments) {
|
|
Enchantment enchantment = InputParsingHelper.matchEnchantment(enchantmentName);
|
|
if (enchantment != null && enchantment.canEnchantItem(this.itemToReforge)) {
|
|
usableEnchantments.add(enchantment);
|
|
}
|
|
}
|
|
//Remove any enchantments in the block list
|
|
usableEnchantments.removeAll(this.blacksmithTrait.getSettings().getEnchantmentBlockList());
|
|
|
|
//In case all usable enchantments have been blocked, abort
|
|
if (usableEnchantments.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
//Choose a random enchantment
|
|
Enchantment randomEnchantment = usableEnchantments.get(random.nextInt(usableEnchantments.size()));
|
|
if (randomEnchantment != null) {
|
|
int randomBound = randomEnchantment.getMaxLevel() + 1;
|
|
//A workaround for the random method's bound sometimes being negative
|
|
if (randomBound >= 0) {
|
|
int existingLevel = this.itemToReforge.getEnchantmentLevel(randomEnchantment);
|
|
/* Add a random enchantment whose level is no lower than the start level, and no lower than the
|
|
existing level (to prevent making the item worse) */
|
|
this.itemToReforge.addEnchantment(randomEnchantment, Math.max(Math.max(random.nextInt(randomBound),
|
|
randomEnchantment.getStartLevel()), existingLevel));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The method to run when a blacksmith fails re-forging an item
|
|
*/
|
|
private void failReforge() {
|
|
if (this.config.getFailRemovesEnchantments()) {
|
|
removeOrDowngradeEnchantments();
|
|
}
|
|
|
|
//Damage the item
|
|
damageItemRandomly(this.itemToReforge);
|
|
}
|
|
|
|
/**
|
|
* Removes or downgrades all enchantments for the currently reforged item
|
|
*/
|
|
private void removeOrDowngradeEnchantments() {
|
|
//Remove or downgrade existing enchantments
|
|
for (Enchantment enchantment : this.itemToReforge.getEnchantments().keySet()) {
|
|
//Completely remove the enchantment, downgrade it, or keep it if lucky and already level 1
|
|
if (random.nextBoolean()) {
|
|
this.itemToReforge.removeEnchantment(enchantment);
|
|
} else if (this.itemToReforge.getEnchantmentLevel(enchantment) > 1) {
|
|
this.itemToReforge.removeEnchantment(enchantment);
|
|
this.itemToReforge.addEnchantment(enchantment, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|