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