001package net.minecraftforge.common; 002 003import java.util.*; 004 005import net.minecraft.item.Item; 006import net.minecraft.item.ItemStack; 007import net.minecraft.util.WeightedRandom; 008import net.minecraft.util.WeightedRandomChestContent; 009import net.minecraft.world.WorldServer; 010import net.minecraft.world.gen.structure.*; 011import net.minecraftforge.oredict.OreDictionary; 012 013public class ChestGenHooks 014{ 015 //Currently implemented categories for chests/dispensers, Dungeon loot is still in DungeonHooks 016 public static final String MINESHAFT_CORRIDOR = "mineshaftCorridor"; 017 public static final String PYRAMID_DESERT_CHEST = "pyramidDesertyChest"; 018 public static final String PYRAMID_JUNGLE_CHEST = "pyramidJungleChest"; 019 public static final String PYRAMID_JUNGLE_DISPENSER = "pyramidJungleDispenser"; 020 public static final String STRONGHOLD_CORRIDOR = "strongholdCorridor"; 021 public static final String STRONGHOLD_LIBRARY = "strongholdLibrary"; 022 public static final String STRONGHOLD_CROSSING = "strongholdCrossing"; 023 public static final String VILLAGE_BLACKSMITH = "villageBlacksmith"; 024 public static final String BONUS_CHEST = "bonusChest"; 025 public static final String DUNGEON_CHEST = "dungeonChest"; 026 027 private static final HashMap<String, ChestGenHooks> chestInfo = new HashMap<String, ChestGenHooks>(); 028 private static boolean hasInit = false; 029 static 030 { 031 init(); 032 } 033 034 private static void init() 035 { 036 if (hasInit) 037 { 038 return; 039 } 040 041 hasInit = true; 042 043 addInfo(MINESHAFT_CORRIDOR, StructureMineshaftPieces.mineshaftChestContents, 3, 7); 044 addInfo(PYRAMID_DESERT_CHEST, ComponentScatteredFeatureDesertPyramid.itemsToGenerateInTemple, 2, 7); 045 addInfo(PYRAMID_JUNGLE_CHEST, ComponentScatteredFeatureJunglePyramid.junglePyramidsChestContents, 2, 7); 046 addInfo(PYRAMID_JUNGLE_DISPENSER, ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserContents, 2, 2); 047 addInfo(STRONGHOLD_CORRIDOR, ComponentStrongholdChestCorridor.strongholdChestContents, 2, 4); 048 addInfo(STRONGHOLD_LIBRARY, ComponentStrongholdLibrary.strongholdLibraryChestContents, 1, 5); 049 addInfo(STRONGHOLD_CROSSING, ComponentStrongholdRoomCrossing.strongholdRoomCrossingChestContents, 1, 5); 050 addInfo(VILLAGE_BLACKSMITH, ComponentVillageHouse2.villageBlacksmithChestContents, 3, 9); 051 addInfo(BONUS_CHEST, WorldServer.bonusChestContent, 10, 10); 052 053 ItemStack book = new ItemStack(Item.enchantedBook, 1, 0); 054 WeightedRandomChestContent tmp = new WeightedRandomChestContent(book, 1, 1, 1); 055 getInfo(MINESHAFT_CORRIDOR ).addItem(tmp); 056 getInfo(PYRAMID_DESERT_CHEST).addItem(tmp); 057 getInfo(PYRAMID_JUNGLE_CHEST).addItem(tmp); 058 getInfo(STRONGHOLD_CORRIDOR ).addItem(tmp); 059 getInfo(STRONGHOLD_LIBRARY ).addItem(new WeightedRandomChestContent(book, 1, 5, 2)); 060 getInfo(STRONGHOLD_CROSSING ).addItem(tmp); 061 062 //Wish Dungeons would get on the same wave length as other world gen... 063 ChestGenHooks d = new ChestGenHooks(DUNGEON_CHEST); 064 d.countMin = 8; 065 d.countMax = 8; 066 chestInfo.put(DUNGEON_CHEST, d); 067 addDungeonLoot(d, new ItemStack(Item.saddle), 100, 1, 1); 068 addDungeonLoot(d, new ItemStack(Item.ingotIron), 100, 1, 4); 069 addDungeonLoot(d, new ItemStack(Item.bread), 100, 1, 1); 070 addDungeonLoot(d, new ItemStack(Item.wheat), 100, 1, 4); 071 addDungeonLoot(d, new ItemStack(Item.gunpowder), 100, 1, 4); 072 addDungeonLoot(d, new ItemStack(Item.silk), 100, 1, 4); 073 addDungeonLoot(d, new ItemStack(Item.bucketEmpty), 100, 1, 1); 074 addDungeonLoot(d, new ItemStack(Item.appleGold), 1, 1, 1); 075 addDungeonLoot(d, new ItemStack(Item.redstone), 50, 1, 4); 076 addDungeonLoot(d, new ItemStack(Item.record13), 5, 1, 1); 077 addDungeonLoot(d, new ItemStack(Item.recordCat), 5, 1, 1); 078 addDungeonLoot(d, new ItemStack(Item.dyePowder, 1, 3), 100, 1, 1); 079 addDungeonLoot(d, book, 100, 1, 1); 080 } 081 082 static void addDungeonLoot(ChestGenHooks dungeon, ItemStack item, int weight, int min, int max) 083 { 084 dungeon.addItem(new WeightedRandomChestContent(item, min, max, weight)); 085 } 086 087 private static void addInfo(String category, WeightedRandomChestContent[] items, int min, int max) 088 { 089 chestInfo.put(category, new ChestGenHooks(category, items, min, max)); 090 } 091 092 /** 093 * Retrieves, or creates the info class for the specified category. 094 * 095 * @param category The category name 096 * @return A instance of ChestGenHooks for the specified category. 097 */ 098 public static ChestGenHooks getInfo(String category) 099 { 100 if (!chestInfo.containsKey(category)) 101 { 102 chestInfo.put(category, new ChestGenHooks(category)); 103 } 104 return chestInfo.get(category); 105 } 106 107 /** 108 * Generates an array of items based on the input min/max count. 109 * If the stack can not hold the total amount, it will be split into 110 * stacks of size 1. 111 * 112 * @param rand A random number generator 113 * @param source Source item stack 114 * @param min Minimum number of items 115 * @param max Maximum number of items 116 * @return An array containing the generated item stacks 117 */ 118 public static ItemStack[] generateStacks(Random rand, ItemStack source, int min, int max) 119 { 120 int count = min + (rand.nextInt(max - min + 1)); 121 122 ItemStack[] ret; 123 if (source.getItem() == null) 124 { 125 ret = new ItemStack[0]; 126 } 127 else if (count > source.getItem().getItemStackLimit()) 128 { 129 ret = new ItemStack[count]; 130 for (int x = 0; x < count; x++) 131 { 132 ret[x] = source.copy(); 133 ret[x].stackSize = 1; 134 } 135 } 136 else 137 { 138 ret = new ItemStack[1]; 139 ret[0] = source.copy(); 140 ret[0].stackSize = count; 141 } 142 return ret; 143 } 144 145 //shortcut functions, See the non-static versions below 146 public static WeightedRandomChestContent[] getItems(String category, Random rnd){ return getInfo(category).getItems(rnd); } 147 public static int getCount(String category, Random rand){ return getInfo(category).getCount(rand); } 148 public static void addItem(String category, WeightedRandomChestContent item){ getInfo(category).addItem(item); } 149 public static void removeItem(String category, ItemStack item){ getInfo(category).removeItem(item); } 150 public static ItemStack getOneItem(String category, Random rand){ return getInfo(category).getOneItem(rand); } 151 152 private String category; 153 private int countMin = 0; 154 private int countMax = 0; 155 //TO-DO: Privatize this once again when we remove the Deprecated stuff in DungeonHooks 156 ArrayList<WeightedRandomChestContent> contents = new ArrayList<WeightedRandomChestContent>(); 157 158 public ChestGenHooks(String category) 159 { 160 this.category = category; 161 } 162 163 public ChestGenHooks(String category, WeightedRandomChestContent[] items, int min, int max) 164 { 165 this(category); 166 for (WeightedRandomChestContent item : items) 167 { 168 contents.add(item); 169 } 170 countMin = min; 171 countMax = max; 172 } 173 174 /** 175 * Adds a new entry into the possible items to generate. 176 * 177 * @param item The item to add. 178 */ 179 public void addItem(WeightedRandomChestContent item) 180 { 181 contents.add(item); 182 } 183 184 /** 185 * Removes all items that match the input item stack, Only metadata and item ID are checked. 186 * If the input item has a metadata of -1, all metadatas will match. 187 * 188 * @param item The item to check 189 */ 190 public void removeItem(ItemStack item) 191 { 192 Iterator<WeightedRandomChestContent> itr = contents.iterator(); 193 while(itr.hasNext()) 194 { 195 WeightedRandomChestContent cont = itr.next(); 196 if (item.isItemEqual(cont.theItemId) || (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.itemID == cont.theItemId.itemID)) 197 { 198 itr.remove(); 199 } 200 } 201 } 202 203 /** 204 * Gets an array of all random objects that are associated with this category. 205 * 206 * @return The random objects 207 */ 208 public WeightedRandomChestContent[] getItems(Random rnd) 209 { 210 ArrayList<WeightedRandomChestContent> ret = new ArrayList<WeightedRandomChestContent>(); 211 212 for (WeightedRandomChestContent orig : contents) 213 { 214 Item item = orig.theItemId.getItem(); 215 216 if (item != null) 217 { 218 WeightedRandomChestContent n = item.getChestGenBase(this, rnd, orig); 219 if (n != null) 220 { 221 ret.add(n); 222 } 223 } 224 } 225 226 return ret.toArray(new WeightedRandomChestContent[ret.size()]); 227 } 228 229 /** 230 * Gets a random number between countMin and countMax. 231 * 232 * @param rand A RNG 233 * @return A random number where countMin <= num <= countMax 234 */ 235 public int getCount(Random rand) 236 { 237 return countMin < countMax ? countMin + rand.nextInt(countMax - countMin) : countMin; 238 } 239 240 /** 241 * Returns a single ItemStack from the possible items in this registry, 242 * Useful if you just want a quick and dirty random Item. 243 * 244 * @param rand A Random Number gen 245 * @return A single ItemStack, or null if it could not get one. 246 */ 247 public ItemStack getOneItem(Random rand) 248 { 249 WeightedRandomChestContent[] items = getItems(rand); 250 WeightedRandomChestContent item = (WeightedRandomChestContent)WeightedRandom.getRandomItem(rand, items); 251 ItemStack[] stacks = ChestGenHooks.generateStacks(rand, item.theItemId, item.theMinimumChanceToGenerateItem, item.theMaximumChanceToGenerateItem); 252 return (stacks.length > 0 ? stacks[0] : null); 253 } 254 255 //Accessors 256 public int getMin(){ return countMin; } 257 public int getMax(){ return countMax; } 258 public void setMin(int value){ countMin = value; } 259 public void setMax(int value){ countMax = value; } 260}