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