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 }