commit bca7427c1cf7ea392e05518c5974e548ebadfa8e Author: aPunch Date: Mon Feb 20 19:43:59 2012 -0600 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f46e6a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/bin +/build +/target +.classpath +.project +Blacksmith.jar +build.xml \ No newline at end of file diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..f931203 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Thu Feb 09 16:52:58 CST 2012 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/lib/CitizensAPI.jar b/lib/CitizensAPI.jar new file mode 100644 index 0000000..85ffa12 Binary files /dev/null and b/lib/CitizensAPI.jar differ diff --git a/lib/bukkit-1.1-R3.jar b/lib/bukkit-1.1-R3.jar new file mode 100644 index 0000000..aa26f4f Binary files /dev/null and b/lib/bukkit-1.1-R3.jar differ diff --git a/plugin.yml b/plugin.yml new file mode 100644 index 0000000..f09fbb0 --- /dev/null +++ b/plugin.yml @@ -0,0 +1,4 @@ +name: Blacksmith +author: aPunch +version: 1.0 +main: net.apunch.blacksmith.Blacksmith \ No newline at end of file diff --git a/src/net/apunch/blacksmith/Blacksmith.java b/src/net/apunch/blacksmith/Blacksmith.java new file mode 100644 index 0000000..16d2e80 --- /dev/null +++ b/src/net/apunch/blacksmith/Blacksmith.java @@ -0,0 +1,118 @@ +package net.apunch.blacksmith; + +import java.util.logging.Level; + +import net.apunch.blacksmith.util.Settings; +import net.apunch.blacksmith.util.Settings.Setting; + +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.util.DataKey; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +public class Blacksmith extends JavaPlugin { + private Settings config; + + @Override + public void onDisable() { + config.save(); + + getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " disabled."); + } + + @Override + public void onEnable() { + config = new Settings(this); + config.load(); + + CitizensAPI.getCharacterManager().register(BlacksmithCharacter.class); + + getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled."); + } + + public boolean isTool(ItemStack item) { + switch (item.getType()) { + case WOOD_PICKAXE: + case WOOD_SPADE: + case WOOD_HOE: + case WOOD_SWORD: + case WOOD_AXE: + case STONE_PICKAXE: + case STONE_SPADE: + case STONE_HOE: + case STONE_SWORD: + case STONE_AXE: + case GOLD_PICKAXE: + case GOLD_SPADE: + case GOLD_HOE: + case GOLD_SWORD: + case GOLD_AXE: + case IRON_PICKAXE: + case IRON_SPADE: + case IRON_HOE: + case IRON_SWORD: + case IRON_AXE: + case DIAMOND_PICKAXE: + case DIAMOND_SPADE: + case DIAMOND_HOE: + case DIAMOND_SWORD: + case DIAMOND_AXE: + case BOW: + case FLINT_AND_STEEL: + case FISHING_ROD: + case SHEARS: + return true; + default: + return false; + } + } + + public boolean isArmor(ItemStack item) { + switch (item.getType()) { + case LEATHER_HELMET: + case LEATHER_CHESTPLATE: + case LEATHER_LEGGINGS: + case LEATHER_BOOTS: + case CHAINMAIL_HELMET: + case CHAINMAIL_CHESTPLATE: + case CHAINMAIL_LEGGINGS: + case CHAINMAIL_BOOTS: + case GOLD_HELMET: + case GOLD_CHESTPLATE: + case GOLD_LEGGINGS: + case GOLD_BOOTS: + case IRON_HELMET: + case IRON_CHESTPLATE: + case IRON_LEGGINGS: + case IRON_BOOTS: + case DIAMOND_HELMET: + case DIAMOND_CHESTPLATE: + case DIAMOND_LEGGINGS: + case DIAMOND_BOOTS: + return true; + default: + return false; + } + } + + public double getCost(ItemStack item) { + DataKey root = config.getConfig().getKey(""); + double price = Setting.BASE_PRICE.asDouble(); + if (root.keyExists("base-prices." + item.getType().name().toLowerCase().replace('_', '-'))) + price = root.getDouble("base-prices." + item.getType().name().toLowerCase().replace('_', '-')); + + // Adjust price based on durability and enchantments + price += (item.getType().getMaxDurability() - item.getDurability()); + + double enchantmentModifier = Setting.ENCHANTMENT_MODIFIER.asDouble(); + for (Enchantment enchantment : item.getEnchantments().keySet()) { + if (root.keyExists("enchantment-modifiers." + enchantment.getName().toLowerCase().replace('_', '-'))) + enchantmentModifier = root.getDouble("enchantment-modifiers." + + enchantment.getName().toLowerCase().replace('_', '-')); + price += enchantmentModifier * item.getEnchantmentLevel(enchantment); + } + return price; + } +} \ No newline at end of file diff --git a/src/net/apunch/blacksmith/BlacksmithCharacter.java b/src/net/apunch/blacksmith/BlacksmithCharacter.java new file mode 100644 index 0000000..90ad265 --- /dev/null +++ b/src/net/apunch/blacksmith/BlacksmithCharacter.java @@ -0,0 +1,189 @@ +package net.apunch.blacksmith; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import net.apunch.blacksmith.util.Settings.Setting; + +import net.citizensnpcs.api.npc.NPC; +import net.citizensnpcs.api.npc.trait.Character; +import net.citizensnpcs.api.npc.trait.SaveId; +import net.citizensnpcs.api.util.DataKey; + +@SaveId("blacksmith") +public class BlacksmithCharacter extends Character { + private final Blacksmith plugin; + private final List reforgeableItems = new ArrayList(); + private RepairSession 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 int minReforgeDelay = Setting.MIN_REFORGE_DELAY.asInt(); + private int maxReforgeDelay = Setting.MAX_REFORGE_DELAY.asInt(); + private int failChance = Setting.FAIL_CHANCE.asInt(); + + public BlacksmithCharacter() { + plugin = (Blacksmith) Bukkit.getServer().getPluginManager().getPlugin("Blacksmith"); + } + + @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("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("percent-chance-to-fail-reforge")) + failChance = key.getInt("percent-chance-to-fail-reforge"); + } + + @Override + public void onRightClick(NPC npc, Player player) { + // TODO cooldowns + ItemStack hand = player.getItemInHand(); + if (session != null) { + if (!session.isInSession(player)) { + npc.chat(busyWithPlayerMsg); + return; + } + + if (session.isRunning()) { + npc.chat(player, 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()))) { + npc.chat(player, invalidItemMsg); + return; + } + session = new RepairSession(player, npc); + npc.chat(player, costMsg.replace("", String.valueOf(plugin.getCost(hand))).replace("", + hand.getType().name().toLowerCase().replace('_', ' '))); + } + } + + @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.setInt("delays-in-seconds.minimum", minReforgeDelay); + key.setInt("delays-in-seconds.maximum", maxReforgeDelay); + key.setInt("percent-chance-to-fail-reforge", failChance); + } + + public String getInsufficientFundsMessage() { + return insufficientFundsMsg; + } + + private void reforge(NPC npc, Player player) { + npc.chat(player, startReforgeMsg); + session.setTask(plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, + new ReforgeTask(npc, player), (new Random().nextInt(maxReforgeDelay) + minReforgeDelay) * 20)); + player.setItemInHand(null); + } + + private class ReforgeTask implements Runnable { + private final NPC npc; + private final Player player; + private final ItemStack reforge; + + private ReforgeTask(NPC npc, Player player) { + this.npc = npc; + this.player = player; + reforge = player.getItemInHand(); + } + + @Override + public void run() { + npc.chat(player, reforgeItemInHand() ? successMsg : failMsg); + player.getWorld().dropItemNaturally(npc.getBukkitEntity().getLocation(), reforge); + session = null; + } + + 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 + if (random.nextInt(3) == 0) { + reforge.setDurability(reforge.getDurability() + reforge.getDurability() * random.nextInt(3) < reforge + .getType().getMaxDurability() ? (short) (reforge.getDurability() + reforge.getDurability() + * random.nextInt(3)) : (short) (reforge.getType().getMaxDurability() - 10)); + } + return false; + } + int chance = 50; + if (reforge.getDurability() == 0) + chance *= 2; + else + reforge.setDurability((short) 0); + // Add random enchantments + for (int i = 0; i < chance; i++) { + int id = random.nextInt(100); + Enchantment enchantment = Enchantment.getById(id); + if (enchantment != null && enchantment.canEnchantItem(reforge)) + reforge.addEnchantment(Enchantment.getById(id), random.nextInt(enchantment.getMaxLevel()) + 1); + } + return true; + } + } +} \ No newline at end of file diff --git a/src/net/apunch/blacksmith/RepairSession.java b/src/net/apunch/blacksmith/RepairSession.java new file mode 100644 index 0000000..3341d24 --- /dev/null +++ b/src/net/apunch/blacksmith/RepairSession.java @@ -0,0 +1,48 @@ +package net.apunch.blacksmith; + +import net.citizensnpcs.api.npc.NPC; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class RepairSession { + private final Blacksmith plugin; + private final Player player; + private final ItemStack reforge; + private final NPC npc; + private int taskId; + + public RepairSession(Player player, NPC npc) { + this.player = player; + reforge = player.getItemInHand(); + this.npc = npc; + + plugin = (Blacksmith) player.getServer().getPluginManager().getPlugin("Blacksmith"); + } + + // Return is the session should end + public boolean handleClick() { + // Prevent player from switching items during session + if (!reforge.equals(player.getItemInHand())) { + npc.chat(player, "That's not the item you wanted to reforge before!"); + return true; + } + if (plugin.getCost(player.getItemInHand()) < 0 /* TODO hasEnough */) { + npc.chat(player, ((BlacksmithCharacter) npc.getCharacter()).getInsufficientFundsMessage()); + return true; + } + return false; + } + + public boolean isRunning() { + return plugin.getServer().getScheduler().isQueued(taskId); + } + + public boolean isInSession(Player other) { + return player.getName().equals(other.getName()); + } + + public void setTask(int taskId) { + this.taskId = taskId; + } +} \ No newline at end of file diff --git a/src/net/apunch/blacksmith/util/Settings.java b/src/net/apunch/blacksmith/util/Settings.java new file mode 100644 index 0000000..72c458c --- /dev/null +++ b/src/net/apunch/blacksmith/util/Settings.java @@ -0,0 +1,87 @@ +package net.apunch.blacksmith.util; + +import java.io.File; + +import net.apunch.blacksmith.Blacksmith; + +import net.citizensnpcs.api.util.DataKey; +import net.citizensnpcs.api.util.YamlStorage; + +public class Settings { + private final YamlStorage config; + + public Settings(Blacksmith plugin) { + config = new YamlStorage(plugin.getDataFolder() + File.separator + "config.yml", "Blacksmith Configuration"); + } + + public void load() { + DataKey root = config.getKey(""); + for (Setting setting : Setting.values()) + if (!root.keyExists(setting.path)) + root.setRaw(setting.path, setting.get()); + else + setting.set(root.getRaw(setting.path)); + + save(); + } + + public void save() { + config.save(); + } + + public YamlStorage getConfig() { + return config; + } + + public enum Setting { + BASE_PRICE("base-prices.default", 10), + BUSY_WITH_PLAYER_MESSAGE("defaults.messages.busy-with-player", "I'm busy at the moment. Come back later!"), + BUSY_WITH_REFORGE_MESSAGE("defaults.messages.busy-with-reforge", "I'm working on it. Be patient!"), + COST_MESSAGE("defaults.messages.cost", "It will cost to reforge that ! Click again to reforge!"), + ENCHANTMENT_MODIFIER("enchantment-modifiers.default", 5), + FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", 10), + FAIL_MESSAGE("defaults.messages.fail-reforge", "Whoops! Didn't mean to do that! Maybe next time?"), + INSUFFICIENT_FUNDS_MESSAGE("defaults.messages.insufficient-funds", "You don't have enough money to reforge that item!"), + INVALID_ITEM_MESSAGE("defaults.messages.invalid-item", "I'm sorry, but I don't know how to reforge that!"), + MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", 30), + MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", 5), + START_REFORGE_MESSAGE("defaults.messages.start-reforge", "Ok, let's see what I can do..."), + SUCCESS_MESSAGE("defaults.messages.successful-reforge", "There you go! All better!"); + + private String path; + private Object value; + + Setting(String path, Object value) { + this.path = path; + this.value = value; + } + + public boolean asBoolean() { + return (Boolean) value; + } + + public double asDouble() { + if (value instanceof String) + return Double.valueOf((String) value); + if (value instanceof Integer) + return (Integer) value; + return (Double) value; + } + + public int asInt() { + return (Integer) value; + } + + public String asString() { + return value.toString(); + } + + private Object get() { + return value; + } + + private void set(Object value) { + this.value = value; + } + } +} \ No newline at end of file