From 1a1828bee80c3bf35984b72a2291be008b97cda5 Mon Sep 17 00:00:00 2001 From: DuckManZach <144298822+DuckManZach@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:03:07 -0600 Subject: [PATCH] Improved loot tables --- src/main/java/tk/shanebee/hg/HG.java | 35 +-- .../java/tk/shanebee/hg/data/ArenaConfig.java | 28 +- .../java/tk/shanebee/hg/data/RandomItems.java | 94 ++++--- .../tk/shanebee/hg/data/loot/LootEntry.java | 14 + .../tk/shanebee/hg/data/loot/LootItem.java | 40 +++ .../tk/shanebee/hg/data/loot/LootTable.java | 76 ++++++ .../tk/shanebee/hg/game/GameItemData.java | 107 ++------ .../java/tk/shanebee/hg/managers/Manager.java | 23 +- src/main/resources/items.yml | 252 +++++++++++++++--- 9 files changed, 445 insertions(+), 224 deletions(-) create mode 100644 src/main/java/tk/shanebee/hg/data/loot/LootEntry.java create mode 100644 src/main/java/tk/shanebee/hg/data/loot/LootItem.java create mode 100644 src/main/java/tk/shanebee/hg/data/loot/LootTable.java diff --git a/src/main/java/tk/shanebee/hg/HG.java b/src/main/java/tk/shanebee/hg/HG.java index 8426913..eda0d18 100755 --- a/src/main/java/tk/shanebee/hg/HG.java +++ b/src/main/java/tk/shanebee/hg/HG.java @@ -8,12 +8,12 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; -import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.java.JavaPlugin; import tk.shanebee.hg.commands.*; import tk.shanebee.hg.data.*; +import tk.shanebee.hg.data.loot.LootTable; import tk.shanebee.hg.game.Game; import tk.shanebee.hg.listeners.*; import tk.shanebee.hg.managers.*; @@ -30,13 +30,9 @@ public class HG extends JavaPlugin { private Map cmds; private Map playerSession; - private Map itemRarityMap; + private LootTable itemLootTable; - private Map itemCostMap; - - private Map bonusRarityMap; - - private Map bonusCostMap; + private LootTable bonusLootTable; //Lists private List games; @@ -84,10 +80,6 @@ public void loadPlugin(boolean load) { } games = new ArrayList<>(); playerSession = new HashMap<>(); - itemCostMap = new HashMap<>(); - itemRarityMap = new HashMap<>(); - bonusCostMap = new HashMap<>(); - bonusRarityMap = new HashMap<>(); config = new Config(this); Bukkit.getLogger().info("Loading HungerGames by JT122406"); @@ -191,8 +183,8 @@ private void unloadPlugin(boolean reload) { stopAll(); games = null; playerSession = null; - itemRarityMap = null; - itemCostMap = null; + itemLootTable = null; + bonusLootTable = null; plugin = null; config = null; nbtApi = null; @@ -421,19 +413,20 @@ public NBTApi getNbtApi() { public MobExecutor getMmMobManager() { return this.mmMobManager; } - public Map getItemRarityMap() { - return itemRarityMap; + public LootTable getItemLootTable() { + return itemLootTable; } - public Map getItemCostMap() { - return itemCostMap; + public void setItemLootTable(LootTable itemLootTable) { + this.itemLootTable = itemLootTable; } - public Map getBonusRarityMap() { - return bonusRarityMap; + + public LootTable getBonusLootTable() { + return bonusLootTable; } - public Map getBonusCostMap() { - return bonusCostMap; + public void setBonusLootTable(LootTable bonusLootTable) { + this.bonusLootTable = bonusLootTable; } } diff --git a/src/main/java/tk/shanebee/hg/data/ArenaConfig.java b/src/main/java/tk/shanebee/hg/data/ArenaConfig.java index e5a593b..ab763cc 100755 --- a/src/main/java/tk/shanebee/hg/data/ArenaConfig.java +++ b/src/main/java/tk/shanebee/hg/data/ArenaConfig.java @@ -9,8 +9,8 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.inventory.ItemStack; import tk.shanebee.hg.*; +import tk.shanebee.hg.data.loot.LootTable; import tk.shanebee.hg.game.Bound; import tk.shanebee.hg.game.Game; import tk.shanebee.hg.game.GameArenaData; @@ -174,23 +174,17 @@ public void load() { if (kit != null) game.setKitManager(kit); - if (!arenadat.getStringList(path + ".items").isEmpty()) { - List itemList = arenadat.getStringList(path + ".items"); - Map itemCostMap = HG.getPlugin().getItemCostMap(); - Map itemRarityMap = HG.getPlugin().getItemRarityMap(); - plugin.getRandomItems().loadItems(itemList, itemCostMap, itemRarityMap); - game.getGameItemData().setItemCostMap(itemCostMap); - game.getGameItemData().setItemRarityMap(itemRarityMap); - Util.log(itemCostMap.keySet().size() + " Random items have been loaded for arena: &b" + arenaName); + ConfigurationSection itemsSection = arenadat.getConfigurationSection(path + ".items"); + if (itemsSection != null) { + LootTable itemTable = plugin.getRandomItems().loadTable(itemsSection, 1); + game.getGameItemData().setItemLootTable(itemTable); + Util.log(itemTable.size() + " Random item entries have been loaded for arena: &b" + arenaName); } - if (!arenadat.getStringList(path + ".bonus").isEmpty()) { - List itemList = arenadat.getStringList(path + ".bonus"); - Map itemCostMap = HG.getPlugin().getBonusCostMap(); - Map itemRarityMap = HG.getPlugin().getBonusRarityMap(); - plugin.getRandomItems().loadItems(itemList, itemCostMap, itemRarityMap); - game.getGameItemData().setBonusCostMap(itemCostMap); - game.getGameItemData().setBonusRarityMap(itemRarityMap); - Util.log(itemCostMap.keySet().size() + " Random items have been loaded for arena: &b" + arenaName); + ConfigurationSection bonusSection = arenadat.getConfigurationSection(path + ".bonus"); + if (bonusSection != null) { + LootTable bonusTable = plugin.getRandomItems().loadTable(bonusSection, 1); + game.getGameItemData().setBonusLootTable(bonusTable); + Util.log(bonusTable.size() + " Random bonus item entries have been loaded for arena: &b" + arenaName); } if (arenadat.isSet(path + ".border.center")) { diff --git a/src/main/java/tk/shanebee/hg/data/RandomItems.java b/src/main/java/tk/shanebee/hg/data/RandomItems.java index d5168fa..70a14e0 100755 --- a/src/main/java/tk/shanebee/hg/data/RandomItems.java +++ b/src/main/java/tk/shanebee/hg/data/RandomItems.java @@ -1,13 +1,15 @@ package tk.shanebee.hg.data; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; import tk.shanebee.hg.HG; +import tk.shanebee.hg.data.loot.LootItem; +import tk.shanebee.hg.data.loot.LootTable; import tk.shanebee.hg.util.Util; import java.io.File; -import java.util.List; import java.util.Map; /** @@ -17,7 +19,6 @@ public class RandomItems { private FileConfiguration item = null; private File customConfigFile = null; - public int size = 0; private final HG plugin; public RandomItems(HG plugin) { @@ -39,48 +40,63 @@ private void reloadCustomConfig() { } public void load() { - loadItems(item.getStringList("items"), plugin.getItemCostMap(), plugin.getItemRarityMap()); - loadItems(item.getStringList("bonus"), plugin.getBonusCostMap(), plugin.getBonusRarityMap()); - Util.log(plugin.getItemRarityMap().keySet().size() + " Random items have been &aloaded!"); - Util.log(plugin.getBonusRarityMap().keySet().size() + " Random bonus items have been &aloaded!"); + ConfigurationSection itemsSection = item.getConfigurationSection("items"); + LootTable itemTable = itemsSection != null ? loadTable(itemsSection, 1) : new LootTable(1); + plugin.setItemLootTable(itemTable); + + ConfigurationSection bonusSection = item.getConfigurationSection("bonus"); + LootTable bonusTable = bonusSection != null ? loadTable(bonusSection, 1) : new LootTable(1); + plugin.setBonusLootTable(bonusTable); + + Util.log(itemTable.size() + " Random item entries have been &aloaded!"); + Util.log(bonusTable.size() + " Random bonus item entries have been &aloaded!"); } - void loadItems(List itemDefinitions, Map costMap, Map rarityMap) { - for (String s : itemDefinitions) { - int cost = 1; - int rarity = 1; - if (s.contains("cost:") && s.contains("rarity:")) { - int costStartIndex = s.indexOf("cost:") + 5; - int costEndIndex = s.indexOf(' ', costStartIndex) == -1 ? s.length() : s.indexOf(' ', costStartIndex); - String costStr = s.substring(costStartIndex, costEndIndex); - cost = Integer.parseInt(costStr); - int rarityStartIndex = s.indexOf("rarity:") + 7; - int rarityEndIndex = s.indexOf(' ', rarityStartIndex) == -1 ? s.length() : s.indexOf(' ', rarityStartIndex); - String rarityStr = s.substring(rarityStartIndex, rarityEndIndex); - rarity = Integer.parseInt(rarityStr); - } - else if (s.contains("cost:")) { - Util.log("Item definition %s doesn't contain a rarity! Defaulting to 1...", s); - int costStartIndex = s.indexOf("cost:") + 5; - int costEndIndex = s.indexOf(' ', costStartIndex) == -1 ? s.length() : s.indexOf(' ', costStartIndex); - String costStr = s.substring(costStartIndex, costEndIndex); - cost = Integer.parseInt(costStr); - } - else if (s.contains("rarity:")) { - Util.log("Item definition %s doesn't contain a cost! Defaulting to 1...", s); - int rarityStartIndex = s.indexOf("rarity:") + 7; - int rarityEndIndex = s.indexOf(' ', rarityStartIndex) == -1 ? s.length() : s.indexOf(' ', rarityStartIndex); - String rarityStr = s.substring(rarityStartIndex, rarityEndIndex); - rarity = Integer.parseInt(rarityStr); + /** + * Recursively build a {@link LootTable} from a configuration section. A section may contain an + * {@code items} list (rollable items) and/or a {@code tables} map of weighted sub-tables. + * + * @param section The section describing this table + * @param weight The weight of this table relative to its siblings + * @return The built loot table + */ + public LootTable loadTable(ConfigurationSection section, int weight) { + LootTable table = new LootTable(weight); + + for (Map map : section.getMapList("items")) { + Object itemSpec = map.get("item"); + if (itemSpec == null) { + Util.warning("Loot item is missing an 'item' field, skipping: &c%s", map); + continue; } - else { - Util.log("Item definition %s doesn't contain a cost or a rarity! Defaulting to 1...", s); + int quantity = getInt(map.get("quantity"), 1); + int itemWeight = getInt(map.get("weight"), 1); + int cost = getInt(map.get("cost"), 1); + ItemStack stack = plugin.getItemStackManager().getItem(String.valueOf(itemSpec), true); + if (stack == null) continue; // getItem already warns on invalid materials + stack.setAmount(quantity); + table.add(new LootItem(stack, itemWeight, cost)); + } + + ConfigurationSection tables = section.getConfigurationSection("tables"); + if (tables != null) { + for (String key : tables.getKeys(false)) { + ConfigurationSection sub = tables.getConfigurationSection(key); + if (sub == null) continue; + table.add(loadTable(sub, sub.getInt("weight", 1))); } - String itemStackStr = s.replaceAll("cost:", "").replaceAll("rarity:", ""); - ItemStack readItem = plugin.getItemStackManager().getItem(itemStackStr, true); - costMap.put(readItem, cost); - rarityMap.put(readItem, rarity); } + return table; + } + + private int getInt(Object value, int def) { + if (value instanceof Number number) { + return number.intValue(); + } + if (value != null && Util.isInt(value.toString())) { + return Integer.parseInt(value.toString()); + } + return def; } } diff --git a/src/main/java/tk/shanebee/hg/data/loot/LootEntry.java b/src/main/java/tk/shanebee/hg/data/loot/LootEntry.java new file mode 100644 index 0000000..849d809 --- /dev/null +++ b/src/main/java/tk/shanebee/hg/data/loot/LootEntry.java @@ -0,0 +1,14 @@ +package tk.shanebee.hg.data.loot; + +/** + * A weighted entry within a {@link LootTable}. Either a {@link LootItem} (a leaf) or a + * nested {@link LootTable}. + */ +public interface LootEntry { + + /** + * @return The weight of this entry relative to its siblings (higher = more likely) + */ + int getWeight(); + +} diff --git a/src/main/java/tk/shanebee/hg/data/loot/LootItem.java b/src/main/java/tk/shanebee/hg/data/loot/LootItem.java new file mode 100644 index 0000000..49ea6bc --- /dev/null +++ b/src/main/java/tk/shanebee/hg/data/loot/LootItem.java @@ -0,0 +1,40 @@ +package tk.shanebee.hg.data.loot; + +import org.bukkit.inventory.ItemStack; + +/** + * A single rollable item in a {@link LootTable}, with its own weight and chest cost. + * The quantity is baked into the {@link ItemStack}. + */ +public class LootItem implements LootEntry { + + private final ItemStack item; + private final int weight; + private final int cost; + + public LootItem(ItemStack item, int weight, int cost) { + this.item = item; + this.weight = weight; + this.cost = cost; + } + + /** + * @return The item stack (quantity included) this entry hands out + */ + public ItemStack getItem() { + return item; + } + + @Override + public int getWeight() { + return weight; + } + + /** + * @return How much of a chest's cost budget this item consumes + */ + public int getCost() { + return cost; + } + +} diff --git a/src/main/java/tk/shanebee/hg/data/loot/LootTable.java b/src/main/java/tk/shanebee/hg/data/loot/LootTable.java new file mode 100644 index 0000000..a0d0958 --- /dev/null +++ b/src/main/java/tk/shanebee/hg/data/loot/LootTable.java @@ -0,0 +1,76 @@ +package tk.shanebee.hg.data.loot; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * A weighted collection of {@link LootEntry LootEntries}. Children may be {@link LootItem items} + * or nested {@link LootTable tables}, allowing arbitrarily deep loot trees. Rolling picks a + * child weighted by its {@link LootEntry#getWeight() weight} and descends into sub-tables until + * it reaches a concrete {@link LootItem}. + */ +public class LootTable implements LootEntry { + + private final int weight; + private final List children = new ArrayList<>(); + + public LootTable(int weight) { + this.weight = weight; + } + + /** + * Add a child entry (item or sub-table) to this table. + * + * @param entry The entry to add + */ + public void add(LootEntry entry) { + children.add(entry); + } + + /** + * @return Whether this table has no entries + */ + public boolean isEmpty() { + return children.isEmpty(); + } + + /** + * @return The number of direct children in this table + */ + public int size() { + return children.size(); + } + + @Override + public int getWeight() { + return weight; + } + + /** + * Roll a single item from this table, descending into any nested tables. + * + * @param rand Random source to use + * @return A rolled {@link LootItem}, or null if this (sub)tree yields nothing + */ + public LootItem roll(Random rand) { + if (children.isEmpty()) return null; + int total = 0; + for (LootEntry e : children) { + total += e.getWeight(); + } + if (total <= 0) return null; + int r = rand.nextInt(total); + for (LootEntry e : children) { + r -= e.getWeight(); + if (r < 0) { + if (e instanceof LootItem li) { + return li; + } + return ((LootTable) e).roll(rand); + } + } + return null; + } + +} diff --git a/src/main/java/tk/shanebee/hg/game/GameItemData.java b/src/main/java/tk/shanebee/hg/game/GameItemData.java index e9f78ac..e006fd0 100644 --- a/src/main/java/tk/shanebee/hg/game/GameItemData.java +++ b/src/main/java/tk/shanebee/hg/game/GameItemData.java @@ -1,115 +1,38 @@ package tk.shanebee.hg.game; -import org.bukkit.inventory.ItemStack; -import tk.shanebee.hg.HG; - -import java.util.Map; +import tk.shanebee.hg.data.loot.LootTable; /** - * Data class for holding a {@link Game Game's} items + * Data class for holding a {@link Game Game's} loot tables */ @SuppressWarnings("unused") public class GameItemData extends Data { - private Map itemRarityMap; - - private Map itemCostMap; - private Map bonusRarityMap; + private LootTable itemLootTable; - private Map bonusCostMap; + private LootTable bonusLootTable; protected GameItemData(Game game) { super(game); - // Set default items from items.yml (if arenas.yml has items it will override this) - this.itemCostMap = game.plugin.getItemCostMap(); - this.itemRarityMap = game.plugin.getItemRarityMap(); - this.bonusCostMap = game.plugin.getBonusCostMap(); - this.bonusRarityMap = game.plugin.getBonusRarityMap(); - } - - /** - * Add an item to the items map for this game - * - * @param item ItemStack to add - */ - public void addToItems(ItemStack item, int cost, int rarity) { - this.itemRarityMap.put(item, rarity); - this.itemCostMap.put(item, rarity); - } - - /** - * Clear the items for this game - */ - public void clearItems() { - this.itemRarityMap.clear(); - this.itemCostMap.clear(); - } - - /** - * Reset the items for this game to the plugin's default items list - */ - public void resetItemsDefault() { - this.itemCostMap = HG.getPlugin().getItemCostMap(); - this.itemRarityMap = HG.getPlugin().getItemRarityMap(); - } - - - /** - * Add an item to this game's bonus items - * - * @param item ItemStack to add to bonus items - */ - public void addToBonusItems(ItemStack item, int cost, int rarity) { - this.bonusRarityMap.put(item, rarity); - this.bonusCostMap.put(item, cost); - } - - /** - * Clear this game's bonus items - */ - public void clearBonusItems() { - this.bonusCostMap.clear(); - this.bonusRarityMap.clear(); - } - - public Map getItemRarityMap() { - return itemRarityMap; - } - - public void setItemRarityMap(Map itemRarityMap) { - this.itemRarityMap = itemRarityMap; - } - - public Map getItemCostMap() { - return itemCostMap; - } - - public void setItemCostMap(Map itemCostMap) { - this.itemCostMap = itemCostMap; - } - - public Map getBonusRarityMap() { - return bonusRarityMap; + // Set default tables from items.yml (if arenas.yml has items it will override these) + this.itemLootTable = game.plugin.getItemLootTable(); + this.bonusLootTable = game.plugin.getBonusLootTable(); } - public void setBonusRarityMap(Map bonusRarityMap) { - this.bonusRarityMap = bonusRarityMap; + public LootTable getItemLootTable() { + return itemLootTable; } - public Map getBonusCostMap() { - return bonusCostMap; + public void setItemLootTable(LootTable itemLootTable) { + this.itemLootTable = itemLootTable; } - public void setBonusCostMap(Map bonusCostMap) { - this.bonusCostMap = bonusCostMap; + public LootTable getBonusLootTable() { + return bonusLootTable; } - /** - * Reset the bonus items for this game to the plugin's default bonus items list - */ - public void resetBonusItemsDefault() { - this.bonusCostMap = HG.getPlugin().getBonusCostMap(); - this.bonusRarityMap = HG.getPlugin().getBonusRarityMap(); + public void setBonusLootTable(LootTable bonusLootTable) { + this.bonusLootTable = bonusLootTable; } } diff --git a/src/main/java/tk/shanebee/hg/managers/Manager.java b/src/main/java/tk/shanebee/hg/managers/Manager.java index aacc414..5a8730c 100755 --- a/src/main/java/tk/shanebee/hg/managers/Manager.java +++ b/src/main/java/tk/shanebee/hg/managers/Manager.java @@ -12,6 +12,8 @@ import tk.shanebee.hg.Status; import tk.shanebee.hg.data.Config; import tk.shanebee.hg.data.Language; +import tk.shanebee.hg.data.loot.LootItem; +import tk.shanebee.hg.data.loot.LootTable; import tk.shanebee.hg.game.Bound; import tk.shanebee.hg.game.Game; import tk.shanebee.hg.game.GameArenaData; @@ -175,18 +177,11 @@ public void fillChest(Inventory inv, Game game, boolean bonus) { GameItemData gameItemData = game.getGameItemData(); inv.clear(); - Map itemRarityMap = bonus ? gameItemData.getBonusRarityMap() : gameItemData.getItemRarityMap(); - Map itemCostMap = bonus ? gameItemData.getBonusCostMap() : gameItemData.getItemCostMap(); + LootTable pool = bonus ? gameItemData.getBonusLootTable() : gameItemData.getItemLootTable(); int maxCost = bonus ? Config.maxbonuscontent : Config.maxchestcontent; int minCost = bonus ? Config.minbonuscontent : Config.minchestcontent; - ArrayList itemList = new ArrayList<>(); - for (Map.Entry e : itemRarityMap.entrySet()) { - for (int i = 0; i < e.getValue(); i++){ - itemList.add(e.getKey()); - } - } - Collections.shuffle(itemList); + if (pool == null || pool.isEmpty()) return; int costGoal = rg.nextInt(minCost, maxCost + 1); @@ -194,12 +189,10 @@ public void fillChest(Inventory inv, Game game, boolean bonus) { ArrayList chestContents = new ArrayList<>(); int numTries = 0; while (chestCost < costGoal && numTries < 10) { - int nextItemIndex = rg.nextInt(itemList.size()); - ItemStack nextItem = itemList.get(nextItemIndex); - int nextItemCost = itemCostMap.get(nextItem); - if (nextItemCost <= (costGoal - chestCost) && !chestContents.contains(nextItem)) { - chestCost += nextItemCost; - chestContents.add(nextItem); + LootItem rolled = pool.roll(rg); + if (rolled != null && rolled.getCost() <= (costGoal - chestCost) && !chestContents.contains(rolled.getItem())) { + chestCost += rolled.getCost(); + chestContents.add(rolled.getItem()); numTries = 0; } else { diff --git a/src/main/resources/items.yml b/src/main/resources/items.yml index 26bddf8..205441c 100755 --- a/src/main/resources/items.yml +++ b/src/main/resources/items.yml @@ -1,44 +1,216 @@ # This file stores items which will appear in chests/bonus chests in your arenas # For info on setup, check the wiki https://github.com/ShaneBeeStudios/HungerGames/wiki/Items.yml +# +# Loot is organized into weighted tables. When a chest is filled, a table is chosen at +# random (weighted by its 'weight'), then an item is rolled from within that table +# (weighted by the item's 'weight'). Tables may contain other tables, nested as deep as +# you like, letting you group loot by theme and tune how often each group appears. +# +# Each item has its own fields: +# item: the material, plus any extras (enchant:, name:, lore:, potion-type:, color:, ...) +# quantity: how many of the item to give (default 1) +# weight: how likely this item is within its table, higher = more common (default 1) +# cost: how much of the chest's value budget this item uses (default 1) items: - - STONE_SWORD 1 rarity:5 cost:1 - - GOLDEN_SWORD 1 rarity:1 cost:1 - - MUSHROOM_STEW 1 rarity:1 cost:1 - - STONE_HOE 1 rarity:1 cost:1 - - LEATHER_HELMET 1 rarity:2 cost:1 - - LEATHER_CHESTPLATE 1 rarity:2 cost:1 - - LEATHER_LEGGINGS 1 rarity:2 cost:1 - - IRON_HELMET 1 rarity:2 cost:1 - - IRON_CHESTPLATE 1 rarity:2 cost:1 - - IRON_LEGGINGS 1 rarity:2 cost:1 - - IRON_BOOTS 1 rarity:2 cost:1 - - BOW 1 rarity:3 cost:1 - - ARROW 20 rarity:2 cost:1 - - MILK_BUCKET 1 rarity:2 cost:1 - - FISHING_ROD 1 rarity:1 cost:1 - - COMPASS 1 rarity:1 cost:1 - - STICK 1 rarity:1 cost:1 name:&6TrackingStick_&aUses:_5 lore:&7Left_click_in_the_air:&7To_find_nearby_players - - GOLDEN_HELMET 1 rarity:1 cost:1 - - GOLDEN_CHESTPLATE 1 rarity:1 cost:1 - - BONE 1 rarity:2 cost:1 - - GOLDEN_LEGGINGS 1 rarity:1 cost:1 - - GOLDEN_BOOTS 1 rarity:1 cost:1 - - DIAMOND_SWORD 1 rarity:1 cost:1 enchant:sharpness:1 name:&6Death_Dealer - - GOLDEN_APPLE 1 rarity:1 cost:1 - - CHAINMAIL_CHESTPLATE 1 rarity:1 cost:1 - - CHAINMAIL_LEGGINGS 1 rarity:1 cost:1 - - COOKIE 2 rarity:3 cost:1 - - MELON_SLICE 1 rarity:4 cost:1 - - COOKED_BEEF 1 rarity:2 cost:1 - - ENDER_PEARL 1 rarity:2 cost:1 - - POTION potion-type:SPEED:3600:1 1 rarity:2 cost:1 name:&rPotion_of_Swiftness - - POTION potion-type:HEAL:1:1 1 rarity:2 cost:1 name:&rPotion_of_Healing - - SPLASH_POTION potion-type:POISON:320:2 1 rarity:1 cost:1 color:green name:&rSplash_Potion_of_Poison - - SPLASH_POTION potion-type:REGENERATION:660:1 1 rarity:2 cost:1 name:&rSplash_Potion_of_Regeneration - - TIPPED_ARROW potion-base:long_poison rarity:1 cost:1 - - TIPPED_ARROW potion-base:strong_slowness rarity:1 cost:1 - - LINGERING_POTION potion-base:harming:false:false rarity:1 cost:1 - - APPLE 2 rarity:5 cost:1 + tables: + food: + weight: 30 + items: + - item: MUSHROOM_STEW + quantity: 1 + weight: 1 + cost: 1 + - item: COOKIE + quantity: 2 + weight: 3 + cost: 1 + - item: MELON_SLICE + quantity: 1 + weight: 4 + cost: 1 + - item: COOKED_BEEF + quantity: 1 + weight: 2 + cost: 1 + - item: GOLDEN_APPLE + quantity: 1 + weight: 1 + cost: 1 + - item: APPLE + quantity: 2 + weight: 5 + cost: 1 + weapons: + weight: 25 + tables: + melee: + weight: 4 + items: + - item: STONE_SWORD + quantity: 1 + weight: 5 + cost: 1 + - item: GOLDEN_SWORD + quantity: 1 + weight: 1 + cost: 1 + - item: DIAMOND_SWORD enchant:sharpness:1 name:&6Death_Dealer + quantity: 1 + weight: 1 + cost: 1 + ranged: + weight: 3 + items: + - item: BOW + quantity: 1 + weight: 3 + cost: 1 + - item: ARROW + quantity: 20 + weight: 2 + cost: 1 + - item: TIPPED_ARROW potion-base:long_poison + quantity: 1 + weight: 1 + cost: 1 + - item: TIPPED_ARROW potion-base:strong_slowness + quantity: 1 + weight: 1 + cost: 1 + armor: + weight: 25 + tables: + leather: + weight: 4 + items: + - item: LEATHER_HELMET + quantity: 1 + weight: 2 + cost: 1 + - item: LEATHER_CHESTPLATE + quantity: 1 + weight: 2 + cost: 1 + - item: LEATHER_LEGGINGS + quantity: 1 + weight: 2 + cost: 1 + iron: + weight: 3 + items: + - item: IRON_HELMET + quantity: 1 + weight: 2 + cost: 1 + - item: IRON_CHESTPLATE + quantity: 1 + weight: 2 + cost: 1 + - item: IRON_LEGGINGS + quantity: 1 + weight: 2 + cost: 1 + - item: IRON_BOOTS + quantity: 1 + weight: 2 + cost: 1 + gold: + weight: 2 + items: + - item: GOLDEN_HELMET + quantity: 1 + weight: 1 + cost: 1 + - item: GOLDEN_CHESTPLATE + quantity: 1 + weight: 1 + cost: 1 + - item: GOLDEN_LEGGINGS + quantity: 1 + weight: 1 + cost: 1 + - item: GOLDEN_BOOTS + quantity: 1 + weight: 1 + cost: 1 + chainmail: + weight: 2 + items: + - item: CHAINMAIL_CHESTPLATE + quantity: 1 + weight: 1 + cost: 1 + - item: CHAINMAIL_LEGGINGS + quantity: 1 + weight: 1 + cost: 1 + utility: + weight: 20 + items: + - item: STONE_HOE + quantity: 1 + weight: 1 + cost: 1 + - item: MILK_BUCKET + quantity: 1 + weight: 2 + cost: 1 + - item: FISHING_ROD + quantity: 1 + weight: 1 + cost: 1 + - item: COMPASS + quantity: 1 + weight: 1 + cost: 1 + - item: STICK name:&6TrackingStick_&aUses:_5 lore:&7Left_click_in_the_air:&7To_find_nearby_players + quantity: 1 + weight: 1 + cost: 1 + - item: BONE + quantity: 1 + weight: 2 + cost: 1 + - item: ENDER_PEARL + quantity: 1 + weight: 2 + cost: 1 + potions: + weight: 15 + tables: + drinkable: + weight: 2 + items: + - item: POTION potion-type:SPEED:3600:1 name:&rPotion_of_Swiftness + quantity: 1 + weight: 2 + cost: 1 + - item: POTION potion-type:HEAL:1:1 name:&rPotion_of_Healing + quantity: 1 + weight: 2 + cost: 1 + thrown: + weight: 1 + items: + - item: SPLASH_POTION potion-type:POISON:320:2 color:green name:&rSplash_Potion_of_Poison + quantity: 1 + weight: 1 + cost: 1 + - item: SPLASH_POTION potion-type:REGENERATION:660:1 name:&rSplash_Potion_of_Regeneration + quantity: 1 + weight: 2 + cost: 1 + - item: LINGERING_POTION potion-base:harming:false:false + quantity: 1 + weight: 1 + cost: 1 bonus: - - DIAMOND_SWORD 1 rarity:1 cost:1 enchant:sharpness:5 name:&3Power_Sword - - DIAMOND_CHESTPLATE 1 rarity:1 cost:1 enchant:protection:3 name:&aLife_Saver + items: + - item: DIAMOND_SWORD enchant:sharpness:5 name:&3Power_Sword + quantity: 1 + weight: 1 + cost: 1 + - item: DIAMOND_CHESTPLATE enchant:protection:3 name:&aLife_Saver + quantity: 1 + weight: 1 + cost: 1