2022-08-08 14:14:42 +02:00
|
|
|
package net.knarcraft.blacksmith.trait;
|
2017-07-31 11:53:59 +02:00
|
|
|
|
2022-02-01 19:52:41 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
|
|
|
import net.citizensnpcs.api.trait.Trait;
|
|
|
|
import net.citizensnpcs.api.util.DataKey;
|
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-10-14 21:45:57 +02:00
|
|
|
import net.knarcraft.blacksmith.formatting.TimeFormatter;
|
2022-08-08 14:14:42 +02:00
|
|
|
import net.knarcraft.blacksmith.manager.EconomyManager;
|
2022-10-03 13:03:21 +02:00
|
|
|
import net.knarcraft.blacksmith.util.ItemHelper;
|
2017-07-31 11:53:59 +02:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Material;
|
2022-08-08 19:27:54 +02:00
|
|
|
import org.bukkit.enchantments.EnchantmentTarget;
|
2017-07-31 11:53:59 +02:00
|
|
|
import org.bukkit.entity.LivingEntity;
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
2022-08-07 01:21:47 +02: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.Calendar;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Objects;
|
2022-02-01 22:24:39 +01:00
|
|
|
import java.util.UUID;
|
2017-07-31 11:53:59 +02:00
|
|
|
|
2022-10-14 21:45:57 +02:00
|
|
|
import static net.knarcraft.blacksmith.formatting.StringFormatter.replacePlaceholder;
|
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-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* The class representing the Blacksmith NPC trait
|
|
|
|
*/
|
2017-07-31 11:53:59 +02:00
|
|
|
public class BlacksmithTrait extends Trait {
|
2022-02-01 19:52:41 +01:00
|
|
|
|
2022-02-01 22:24:39 +01:00
|
|
|
private final Map<UUID, Calendar> coolDowns = new HashMap<>();
|
2022-02-01 19:52:41 +01:00
|
|
|
private ReforgeSession session;
|
2022-08-07 01:21:47 +02:00
|
|
|
private final NPCSettings config;
|
2022-07-16 14:56:29 +02:00
|
|
|
private long _sessionStart = System.currentTimeMillis();
|
2022-02-01 19:52:41 +01:00
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Instantiates a new blacksmith trait
|
|
|
|
*/
|
2022-02-01 19:52:41 +01:00
|
|
|
public BlacksmithTrait() {
|
|
|
|
super("blacksmith");
|
2022-08-07 01:21:47 +02:00
|
|
|
//This should crash if the blacksmith plugin hasn't been properly registered
|
|
|
|
Bukkit.getServer().getPluginManager().getPlugin("Blacksmith");
|
|
|
|
this.config = new NPCSettings(BlacksmithPlugin.getInstance().getSettings());
|
2022-02-01 22:24:39 +01:00
|
|
|
}
|
|
|
|
|
2022-08-08 14:14:42 +02:00
|
|
|
/**
|
|
|
|
* Gets the current settings for this NPC
|
|
|
|
*
|
|
|
|
* @return <p>The current settings for this NPC</p>
|
|
|
|
*/
|
|
|
|
public NPCSettings getSettings() {
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-10-03 12:39:15 +02:00
|
|
|
* Gets whether this blacksmith is already in a reforging session
|
2022-08-08 14:14:42 +02:00
|
|
|
*
|
2022-10-03 12:39:15 +02:00
|
|
|
* @return <p>Whether already in a reforge session</p>
|
2022-08-08 14:14:42 +02:00
|
|
|
*/
|
|
|
|
public boolean hasSession() {
|
|
|
|
return this.session != null;
|
|
|
|
}
|
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Adds a cool-down for the given player's next blacksmith reforge
|
|
|
|
*
|
|
|
|
* @param playerUUID <p>The ID of the player to add the cool-down for</p>
|
|
|
|
* @param waitUntil <p>The time when the player can interact again</p>
|
|
|
|
*/
|
2022-02-01 22:24:39 +01:00
|
|
|
public void addCoolDown(UUID playerUUID, Calendar waitUntil) {
|
|
|
|
coolDowns.put(playerUUID, waitUntil);
|
|
|
|
}
|
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Unsets the session of this blacksmith, making it ready for another round
|
|
|
|
*/
|
2022-02-01 22:24:39 +01:00
|
|
|
public void unsetSession() {
|
|
|
|
this.session = null;
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
|
2022-08-07 01:21:47 +02:00
|
|
|
/**
|
|
|
|
* Loads all config values stored in citizens' config file for this NPC
|
|
|
|
*
|
|
|
|
* @param key <p>The data key used for the config root</p>
|
|
|
|
*/
|
2022-02-01 19:52:41 +01:00
|
|
|
@Override
|
|
|
|
public void load(DataKey key) {
|
2022-02-01 22:24:39 +01:00
|
|
|
config.loadVariables(key);
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
|
2022-08-07 01:21:47 +02:00
|
|
|
/**
|
|
|
|
* Saves all config values for this NPC
|
|
|
|
*
|
|
|
|
* @param key <p>The data key used for the config root</p>
|
|
|
|
*/
|
2022-07-16 14:56:29 +02:00
|
|
|
@Override
|
|
|
|
public void save(DataKey key) {
|
|
|
|
config.saveVariables(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs necessary work before the session is started or continued
|
|
|
|
*
|
|
|
|
* @param player <p>The player to prepare the session for</p>
|
|
|
|
* @return <p>True if preparations were successful. False if a session shouldn't be started</p>
|
|
|
|
*/
|
2022-08-08 14:14:42 +02:00
|
|
|
public boolean prepareForSession(Player player) {
|
2022-10-14 21:45:57 +02:00
|
|
|
UUID playerId = player.getUniqueId();
|
2022-07-16 14:56:29 +02:00
|
|
|
//If cool-down has been disabled after it was set for this player, remove the cool-down
|
2022-10-14 21:45:57 +02:00
|
|
|
if (config.getDisableCoolDown() && coolDowns.get(playerId) != null) {
|
|
|
|
coolDowns.remove(playerId);
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
2022-07-16 14:56:29 +02:00
|
|
|
//Deny if permission is missing
|
2022-02-01 19:52:41 +01:00
|
|
|
if (!player.hasPermission("blacksmith.reforge")) {
|
2022-07-16 14:56:29 +02:00
|
|
|
return false;
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
2022-08-08 14:14:42 +02:00
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
//Deny if on cool-down, or remove cool-down if expired
|
2022-10-14 21:45:57 +02:00
|
|
|
if (coolDowns.get(playerId) != null) {
|
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
|
if (!calendar.after(coolDowns.get(playerId))) {
|
|
|
|
int secondDifference = (int) ((calendar.getTimeInMillis() - coolDowns.get(playerId).getTimeInMillis()) * 1000);
|
|
|
|
boolean exactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
|
|
|
|
sendNPCMessage(this.npc, player, replacePlaceholder(config.getCoolDownUnexpiredMessage(),
|
|
|
|
"{time}", TimeFormatter.formatTime(exactTime, secondDifference)));
|
2022-07-16 14:56:29 +02:00
|
|
|
return false;
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
2022-10-14 21:45:57 +02:00
|
|
|
coolDowns.remove(playerId);
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
|
2022-10-14 21:45:57 +02:00
|
|
|
//If already in a session, but the player has failed to interact, and left the blacksmith, allow a new session
|
2022-02-01 19:52:41 +01:00
|
|
|
if (session != null) {
|
2022-10-14 21:45:57 +02:00
|
|
|
if (System.currentTimeMillis() > _sessionStart + 10 * 1000 &&
|
2022-02-02 00:36:15 +01:00
|
|
|
this.npc.getEntity().getLocation().distance(session.getPlayer().getLocation()) > 20) {
|
2022-02-01 19:52:41 +01:00
|
|
|
session = null;
|
|
|
|
}
|
|
|
|
}
|
2022-07-16 14:56:29 +02:00
|
|
|
return true;
|
|
|
|
}
|
2022-02-01 19:52:41 +01:00
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Tries to continue the session for the given player
|
|
|
|
*
|
|
|
|
* @param player <p>The player to continue the session for</p>
|
|
|
|
*/
|
2022-08-08 14:14:42 +02:00
|
|
|
public void continueSession(Player player) {
|
2022-07-16 14:56:29 +02:00
|
|
|
//Another player is using the blacksmith
|
|
|
|
if (!session.isInSession(player)) {
|
2022-09-29 01:49:12 +02:00
|
|
|
sendNPCMessage(this.npc, player, config.getBusyWithPlayerMessage());
|
2022-07-16 14:56:29 +02:00
|
|
|
return;
|
|
|
|
}
|
2022-02-01 19:52:41 +01:00
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
//The blacksmith is already reforging for the player
|
|
|
|
if (session.isRunning()) {
|
2022-10-14 21:45:57 +02:00
|
|
|
int timeRemaining = (int) ((session.getFinishTime() - System.currentTimeMillis()) / 1000);
|
|
|
|
boolean showExactTime = BlacksmithPlugin.getInstance().getSettings().getShowExactTime();
|
|
|
|
sendNPCMessage(this.npc, player, replacePlaceholder(config.getBusyReforgingMessage(), "{time}",
|
|
|
|
TimeFormatter.formatTime(showExactTime, timeRemaining)));
|
2022-07-16 14:56:29 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (session.endSession()) {
|
|
|
|
//Quit if the player cannot afford, or has changed their item
|
|
|
|
session = null;
|
2022-02-01 19:52:41 +01:00
|
|
|
} else {
|
2022-07-16 14:56:29 +02:00
|
|
|
//Start reforging for the player
|
|
|
|
reforge(npc, player);
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Starts a new session, and prepares to repair the player's item
|
|
|
|
*
|
|
|
|
* @param player <p>The player to start the session for</p>
|
|
|
|
*/
|
2022-08-08 14:14:42 +02:00
|
|
|
public void startSession(Player player) {
|
2022-07-16 14:56:29 +02:00
|
|
|
ItemStack hand = player.getInventory().getItemInMainHand();
|
2022-08-07 01:21:47 +02:00
|
|
|
//Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item
|
|
|
|
List<Material> reforgeAbleItems = config.getReforgeAbleItems();
|
|
|
|
if (!isRepairable(hand) || (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()))) {
|
2022-10-14 21:45:57 +02:00
|
|
|
String invalidMessage = replacePlaceholder(config.getInvalidItemMessage(),
|
2022-10-14 11:28:00 +02:00
|
|
|
"{title}", config.getBlacksmithTitle());
|
|
|
|
sendNPCMessage(this.npc, player, invalidMessage);
|
2022-07-16 14:56:29 +02:00
|
|
|
return;
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
|
2022-10-03 13:03:21 +02:00
|
|
|
if (ItemHelper.getDamage(hand) == 0) {
|
|
|
|
sendNPCMessage(this.npc, player, config.getNotDamagedMessage());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
//Start a new reforge session for the player
|
|
|
|
_sessionStart = System.currentTimeMillis();
|
|
|
|
session = new ReforgeSession(this, player, npc, config);
|
|
|
|
|
|
|
|
//Tell the player the cost of repairing the item
|
2022-08-07 01:21:47 +02:00
|
|
|
String cost = EconomyManager.formatCost(player);
|
2022-07-16 14:56:29 +02:00
|
|
|
String itemName = hand.getType().name().toLowerCase().replace('_', ' ');
|
2022-10-14 21:45:57 +02:00
|
|
|
sendNPCMessage(this.npc, player, config.getCostMessage().replace("{cost}", cost).replace("{item}",
|
|
|
|
itemName));
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
|
|
|
|
2022-07-16 14:56:29 +02:00
|
|
|
/**
|
|
|
|
* Starts reforging the player's item
|
|
|
|
*
|
|
|
|
* @param npc <p>The NPC performing the reforge</p>
|
|
|
|
* @param player <p>The player that initiated the reforge</p>
|
|
|
|
*/
|
2022-02-01 19:52:41 +01:00
|
|
|
private void reforge(NPC npc, Player player) {
|
2022-09-29 01:49:12 +02:00
|
|
|
sendNPCMessage(this.npc, player, config.getStartReforgeMessage());
|
2022-08-07 01:21:47 +02:00
|
|
|
EconomyManager.withdraw(player);
|
2022-02-01 19:52:41 +01:00
|
|
|
session.beginReforge();
|
2022-07-16 14:56:29 +02:00
|
|
|
ItemStack heldItem = player.getInventory().getItemInMainHand();
|
|
|
|
|
|
|
|
//Display the item in the NPC's hand
|
2022-02-01 19:52:41 +01:00
|
|
|
if (npc.getEntity() instanceof Player) {
|
2022-07-16 14:56:29 +02:00
|
|
|
((Player) npc.getEntity()).getInventory().setItemInMainHand(heldItem);
|
2022-02-01 19:52:41 +01:00
|
|
|
} else {
|
2022-07-16 14:56:29 +02:00
|
|
|
Objects.requireNonNull(((LivingEntity) npc.getEntity()).getEquipment()).setItemInMainHand(heldItem);
|
2022-02-01 19:52:41 +01:00
|
|
|
}
|
2022-07-16 14:56:29 +02:00
|
|
|
//Remove the item from the player's inventory
|
2022-02-01 19:52:41 +01:00
|
|
|
player.getInventory().setItemInMainHand(null);
|
|
|
|
}
|
|
|
|
|
2022-08-07 01:21:47 +02:00
|
|
|
/**
|
|
|
|
* Gets whether the given item is repairable
|
|
|
|
*
|
|
|
|
* @param item <p>The item to check</p>
|
|
|
|
* @return <p>True if the item is repairable</p>
|
|
|
|
*/
|
2022-08-08 19:27:54 +02:00
|
|
|
public static boolean isRepairable(ItemStack item) {
|
|
|
|
return item.getItemMeta() instanceof Damageable && EnchantmentTarget.BREAKABLE.includes(item);
|
2022-08-07 01:21:47 +02:00
|
|
|
}
|
|
|
|
|
2017-07-31 11:53:59 +02:00
|
|
|
}
|