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 }