2017-07-31 11:53:59 +02:00
|
|
|
package net.apunch.blacksmith;
|
|
|
|
|
2022-02-01 19:52:41 +01:00
|
|
|
import net.apunch.blacksmith.util.Settings.Setting;
|
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
|
|
|
import net.citizensnpcs.api.trait.Trait;
|
|
|
|
import net.citizensnpcs.api.util.DataKey;
|
2017-07-31 11:53:59 +02:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Material;
|
2022-02-01 19:52:41 +01:00
|
|
|
import org.bukkit.NamespacedKey;
|
2017-07-31 11:53:59 +02:00
|
|
|
import org.bukkit.enchantments.Enchantment;
|
|
|
|
import org.bukkit.entity.LivingEntity;
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
2022-02-01 19:52:41 +01:00
|
|
|
import org.bukkit.inventory.meta.Damageable;
|
2017-07-31 11:53:59 +02:00
|
|
|
|
2022-02-01 19:52:41 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Calendar;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
|
|
|
import java.util.Random;
|
2017-07-31 11:53:59 +02:00
|
|
|
|
|
|
|
public class BlacksmithTrait extends Trait {
|
2022-02-01 19:52:41 +01:00
|
|
|
private static final String[] enchantments = new String[Enchantment.values().length];
|
|
|
|
|
|
|
|
private final BlacksmithPlugin plugin;
|
|
|
|
private final List<Material> reforgeAbleItems = new ArrayList<>();
|
|
|
|
private final Map<String, Calendar> coolDowns = new HashMap<>();
|
|
|
|
private ReforgeSession session;
|
|
|
|
|
|
|
|
// Defaults
|
|
|
|
private String busyWithPlayerMsg = Setting.BUSY_WITH_PLAYER_MESSAGE.asString();
|
|
|
|
private String busyReforgingMsg = Setting.BUSY_WITH_REFORGE_MESSAGE.asString();
|
|
|
|
private String costMsg = Setting.COST_MESSAGE.asString();
|
|
|
|
private String invalidItemMsg = Setting.INVALID_ITEM_MESSAGE.asString();
|
|
|
|
private String startReforgeMsg = Setting.START_REFORGE_MESSAGE.asString();
|
|
|
|
private String successMsg = Setting.SUCCESS_MESSAGE.asString();
|
|
|
|
private String failMsg = Setting.FAIL_MESSAGE.asString();
|
|
|
|
private String insufficientFundsMsg = Setting.INSUFFICIENT_FUNDS_MESSAGE.asString();
|
|
|
|
private String coolDownUnexpiredMessage = Setting.COOLDOWN_UNEXPIRED_MESSAGE.asString();
|
|
|
|
private String itemChangedMsg = Setting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE.asString();
|
|
|
|
private int minReforgeDelay = Setting.MIN_REFORGE_DELAY.asInt();
|
|
|
|
private int maxReforgeDelay = Setting.MAX_REFORGE_DELAY.asInt();
|
|
|
|
private int reforgeCoolDown = Setting.REFORGE_COOLDOWN.asInt();
|
|
|
|
private int failChance = Setting.FAIL_CHANCE.asInt();
|
|
|
|
private int extraEnchantmentChance = Setting.EXTRA_ENCHANTMENT_CHANCE.asInt();
|
|
|
|
private int maxEnchantments = Setting.MAX_ENCHANTMENTS.asInt();
|
|
|
|
private boolean dropItem = Setting.DROP_ITEM.asBoolean();
|
|
|
|
private boolean disableCoolDown = Setting.DISABLE_COOLDOWN.asBoolean();
|
|
|
|
private boolean disableDelay = Setting.DISABLE_DELAY.asBoolean();
|
|
|
|
|
|
|
|
public BlacksmithTrait() {
|
|
|
|
super("blacksmith");
|
|
|
|
plugin = (BlacksmithPlugin) Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
|
|
|
|
int i = 0;
|
|
|
|
for (Enchantment enchantment : Enchantment.values()) {
|
|
|
|
enchantments[i++] = enchantment.getKey().asString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void load(DataKey key) {
|
|
|
|
for (DataKey sub : key.getRelative("reforgeable-items").getIntegerSubKeys()) {
|
|
|
|
if (Material.getMaterial(sub.getString("").toUpperCase().replace('-', '_')) != null) {
|
|
|
|
reforgeAbleItems.add(Material.getMaterial(sub.getString("").toUpperCase().replace('-', '_')));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override defaults if they exist
|
|
|
|
if (key.keyExists("messages.busy-with-player")) {
|
|
|
|
busyWithPlayerMsg = key.getString("messages.busy-with-player");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.busy-with-reforge")) {
|
|
|
|
busyReforgingMsg = key.getString("messages.busy-with-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.cost")) {
|
|
|
|
costMsg = key.getString("messages.cost");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.invalid-item")) {
|
|
|
|
invalidItemMsg = key.getString("messages.invalid-item");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.start-reforge")) {
|
|
|
|
startReforgeMsg = key.getString("messages.start-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.successful-reforge")) {
|
|
|
|
successMsg = key.getString("messages.successful-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.fail-reforge")) {
|
|
|
|
failMsg = key.getString("messages.fail-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.insufficient-funds")) {
|
|
|
|
insufficientFundsMsg = key.getString("messages.insufficient-funds");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.cooldown-not-expired")) {
|
|
|
|
coolDownUnexpiredMessage = key.getString("messages.cooldown-not-expired");
|
|
|
|
}
|
|
|
|
if (key.keyExists("messages.item-changed-during-reforge")) {
|
|
|
|
itemChangedMsg = key.getString("messages.item-changed-during-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("delays-in-seconds.minimum")) {
|
|
|
|
minReforgeDelay = key.getInt("delays-in-seconds.minimum");
|
|
|
|
}
|
|
|
|
if (key.keyExists("delays-in-seconds.maximum")) {
|
|
|
|
maxReforgeDelay = key.getInt("delays-in-seconds.maximum");
|
|
|
|
}
|
|
|
|
if (key.keyExists("delays-in-seconds.reforge-cooldown")) {
|
|
|
|
reforgeCoolDown = key.getInt("delays-in-seconds.reforge-cooldown");
|
|
|
|
}
|
|
|
|
if (key.keyExists("percent-chance-to-fail-reforge")) {
|
|
|
|
failChance = key.getInt("percent-chance-to-fail-reforge");
|
|
|
|
}
|
|
|
|
if (key.keyExists("maximum-enchantments")) {
|
|
|
|
maxEnchantments = key.getInt("maximum-enchantments");
|
|
|
|
}
|
|
|
|
if (key.keyExists("extra-enchantments-chance")) {
|
|
|
|
extraEnchantmentChance = key.getInt("extra-enchantment-chance");
|
|
|
|
}
|
|
|
|
if (key.keyExists("dropitem")) {
|
|
|
|
dropItem = key.getBoolean("dropitem");
|
|
|
|
}
|
|
|
|
if (key.keyExists("disable-cooldown")) {
|
|
|
|
disableCoolDown = key.getBoolean("disable-cooldown");
|
|
|
|
}
|
|
|
|
if (key.keyExists("disable-delay")) {
|
|
|
|
disableDelay = key.getBoolean("disable-delay");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
public void onRightClick(net.citizensnpcs.api.event.NPCRightClickEvent event) {
|
|
|
|
if (this.npc != event.getNPC()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Player player = event.getClicker();
|
|
|
|
if ((disableCoolDown & (coolDowns.get(player.getName()) != (null)))) {
|
|
|
|
coolDowns.remove(player.getName());
|
|
|
|
}
|
|
|
|
if (!player.hasPermission("blacksmith.reforge")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (coolDowns.get(player.getName()) != null) {
|
|
|
|
if (!Calendar.getInstance().after(coolDowns.get(player.getName()))) {
|
|
|
|
player.sendMessage(coolDownUnexpiredMessage);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
coolDowns.remove(player.getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ItemStack hand = player.getInventory().getItemInMainHand();
|
|
|
|
|
|
|
|
if (session != null) {
|
|
|
|
//timeout
|
|
|
|
if (System.currentTimeMillis() > _sessionstart + 10 * 1000 || this.npc.getEntity().getLocation().distance(session.player.getLocation()) > 20) {
|
|
|
|
session = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (session != null) {
|
|
|
|
if (!session.isInSession(player)) {
|
|
|
|
|
|
|
|
player.sendMessage(busyWithPlayerMsg);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session.isRunning()) {
|
|
|
|
player.sendMessage(busyReforgingMsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (session.handleClick()) {
|
|
|
|
session = null;
|
|
|
|
} else {
|
|
|
|
reforge(npc, player);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((!plugin.isTool(hand) && !plugin.isArmor(hand))
|
|
|
|
|| (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()))) {
|
|
|
|
player.sendMessage(invalidItemMsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
String cost = plugin.formatCost(player);
|
|
|
|
|
|
|
|
_sessionstart = System.currentTimeMillis();
|
|
|
|
session = new ReforgeSession(player, npc);
|
|
|
|
player.sendMessage(costMsg.replace("<price>", cost).replace("<item>",
|
|
|
|
hand.getType().name().toLowerCase().replace('_', ' ')));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private long _sessionstart = System.currentTimeMillis();
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void save(DataKey key) {
|
|
|
|
for (int i = 0; i < reforgeAbleItems.size(); i++) {
|
|
|
|
key.getRelative("reforgeable-items").setString(String.valueOf(i),
|
|
|
|
reforgeAbleItems.get(i).name().toLowerCase().replace('_', '-'));
|
|
|
|
}
|
|
|
|
|
|
|
|
key.setString("messages.busy-with-player", busyWithPlayerMsg);
|
|
|
|
key.setString("messages.busy-with-reforge", busyReforgingMsg);
|
|
|
|
key.setString("messages.cost", costMsg);
|
|
|
|
key.setString("messages.invalid-item", invalidItemMsg);
|
|
|
|
key.setString("messages.start-reforge", startReforgeMsg);
|
|
|
|
key.setString("messages.successful-reforge", successMsg);
|
|
|
|
key.setString("messages.fail-reforge", failMsg);
|
|
|
|
key.setString("messages.insufficient-funds", insufficientFundsMsg);
|
|
|
|
key.setString("messages.cooldown-not-expired", coolDownUnexpiredMessage);
|
|
|
|
key.setString("messages.item-changed-during-reforge", itemChangedMsg);
|
|
|
|
key.setInt("delays-in-seconds.minimum", minReforgeDelay);
|
|
|
|
key.setInt("delays-in-seconds.maximum", maxReforgeDelay);
|
|
|
|
key.setInt("delays-in-seconds.reforge-cooldown", reforgeCoolDown);
|
|
|
|
key.setInt("percent-chance-to-fail-reforge", failChance);
|
|
|
|
key.setInt("percent-chance-for-extra-enchantment", extraEnchantmentChance);
|
|
|
|
key.setInt("maximum-enchantments", maxEnchantments);
|
|
|
|
key.setBoolean("drop-item", dropItem);
|
|
|
|
key.setBoolean("disable-delay", disableDelay);
|
|
|
|
key.setBoolean("disable-cooldown", disableCoolDown);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void reforge(NPC npc, Player player) {
|
|
|
|
player.sendMessage(startReforgeMsg);
|
|
|
|
|
|
|
|
//plugin.deposit(npc, player); // CitiTrader dependency outdated and broken
|
|
|
|
|
|
|
|
plugin.withdraw(player);
|
|
|
|
session.beginReforge();
|
|
|
|
if (npc.getEntity() instanceof Player) {
|
|
|
|
((Player) npc.getEntity()).getInventory().setItemInMainHand(player.getInventory().getItemInMainHand());
|
|
|
|
} else {
|
|
|
|
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(player.getInventory().getItemInMainHand());
|
|
|
|
}
|
|
|
|
player.getInventory().setItemInMainHand(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ReforgeSession implements Runnable {
|
|
|
|
private final Player player;
|
|
|
|
private final NPC npc;
|
|
|
|
private final ItemStack reforge;
|
|
|
|
private int taskId;
|
|
|
|
|
|
|
|
private ReforgeSession(Player player, NPC npc) {
|
|
|
|
this.player = player;
|
|
|
|
this.npc = npc;
|
|
|
|
reforge = player.getInventory().getItemInMainHand();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
player.sendMessage(reforgeItemInHand() ? successMsg : failMsg);
|
|
|
|
if (npc.getEntity() instanceof Player) {
|
|
|
|
((Player) npc.getEntity()).getInventory().setItemInMainHand(null);
|
|
|
|
} else {
|
|
|
|
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(null);
|
|
|
|
}
|
|
|
|
if (!disableDelay) {
|
|
|
|
if (dropItem) {
|
|
|
|
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), reforge);
|
|
|
|
} else {
|
|
|
|
player.getInventory().addItem(reforge);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
player.getInventory().setItemInMainHand(reforge);
|
|
|
|
}
|
|
|
|
session = null;
|
|
|
|
// Start cooldown
|
|
|
|
Calendar wait = Calendar.getInstance();
|
|
|
|
wait.add(Calendar.SECOND, reforgeCoolDown);
|
|
|
|
coolDowns.put(player.getName(), wait);
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean reforgeItemInHand() {
|
|
|
|
Random random = new Random();
|
|
|
|
if (random.nextInt(100) < failChance) {
|
|
|
|
for (Enchantment enchantment : reforge.getEnchantments().keySet()) {
|
|
|
|
// Remove or downgrade enchantments
|
|
|
|
if (random.nextBoolean()) {
|
|
|
|
reforge.removeEnchantment(enchantment);
|
|
|
|
} else {
|
|
|
|
if (reforge.getEnchantmentLevel(enchantment) > 1) {
|
|
|
|
reforge.removeEnchantment(enchantment);
|
|
|
|
reforge.addEnchantment(enchantment, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Damage the item
|
|
|
|
short durability = (short) (((Damageable) reforge).getDamage() + ((Damageable) reforge).getDamage() *
|
|
|
|
random.nextInt(8));
|
|
|
|
short maxDurability = reforge.getType().getMaxDurability();
|
|
|
|
if (durability <= 0) {
|
|
|
|
durability = (short) (maxDurability / 3);
|
|
|
|
} else if (((Damageable) reforge).getDamage() + durability > maxDurability) {
|
|
|
|
durability = (short) (maxDurability - random.nextInt(maxDurability - 25));
|
|
|
|
}
|
|
|
|
((Damageable) reforge).setDamage(durability);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
((Damageable) reforge).setDamage((short) 0);
|
|
|
|
|
|
|
|
// Add random enchantments
|
|
|
|
|
|
|
|
|
|
|
|
// If durability is full, chance is multiplied by 4. Seems unbalanced, so disabled for now.
|
2017-07-31 11:53:59 +02:00
|
|
|
/*if (reforge.getDurability() == 0)
|
|
|
|
chance *= 4;
|
|
|
|
else */
|
|
|
|
|
2022-02-01 19:52:41 +01:00
|
|
|
int roll = random.nextInt(100);
|
|
|
|
if (roll < extraEnchantmentChance && reforge.getEnchantments().keySet().size() < maxEnchantments) {
|
|
|
|
|
|
|
|
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.fromString(enchantments[random.nextInt(enchantments.length)]));
|
|
|
|
if (Objects.requireNonNull(enchantment).canEnchantItem(reforge)) {
|
|
|
|
reforge.addEnchantment(enchantment, random.nextInt(enchantment.getMaxLevel() - enchantment.getStartLevel()) + enchantment.getStartLevel());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return if the session should end
|
|
|
|
private boolean handleClick() {
|
|
|
|
// Prevent player from switching items during session
|
|
|
|
if (!reforge.equals(player.getInventory().getItemInMainHand())) {
|
|
|
|
player.sendMessage(itemChangedMsg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!plugin.doesPlayerHaveEnough(player)) {
|
|
|
|
player.sendMessage(insufficientFundsMsg);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isRunning() {
|
|
|
|
return plugin.getServer().getScheduler().isQueued(taskId);
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isInSession(Player other) {
|
|
|
|
return player.getName().equals(other.getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void beginReforge() {
|
|
|
|
if (!disableCoolDown) {
|
|
|
|
taskId = plugin
|
|
|
|
.getServer()
|
|
|
|
.getScheduler()
|
|
|
|
.scheduleSyncDelayedTask(plugin, this,
|
|
|
|
(new Random().nextInt(maxReforgeDelay) + minReforgeDelay) * 20L);
|
|
|
|
} else {
|
|
|
|
taskId = plugin
|
|
|
|
.getServer()
|
|
|
|
.getScheduler()
|
|
|
|
.scheduleSyncDelayedTask(plugin, this, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-31 11:53:59 +02:00
|
|
|
}
|