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.WeightedRandomChestContent;
008    import net.minecraft.world.WorldServer;
009    import net.minecraft.world.gen.structure.*;
010    
011    public class ChestGenHooks
012    {
013        //Currently implemented categories for chests/dispensers, Dungeon loot is still in DungeonHooks
014        public static final String MINESHAFT_CORRIDOR       = "mineshaftCorridor";
015        public static final String PYRAMID_DESERT_CHEST     = "pyramidDesertyChest";
016        public static final String PYRAMID_JUNGLE_CHEST     = "pyramidJungleChest";
017        public static final String PYRAMID_JUNGLE_DISPENSER = "pyramidJungleDispenser";
018        public static final String STRONGHOLD_CORRIDOR      = "strongholdCorridor";
019        public static final String STRONGHOLD_LIBRARY       = "strongholdLibrary";
020        public static final String STRONGHOLD_CROSSING      = "strongholdCrossing";
021        public static final String VILLAGE_BLACKSMITH       = "villageBlacksmith";
022        public static final String BONUS_CHEST              = "bonusChest";
023    
024        private static final HashMap<String, ChestGenHooks> chestInfo = new HashMap<String, ChestGenHooks>();
025        private static boolean hasInit = false;
026        static 
027        {
028            init();
029        }
030    
031        private static void init()
032        {
033            if (hasInit)
034            {
035                return;
036            }
037            addInfo(MINESHAFT_CORRIDOR,       StructureMineshaftPieces.mineshaftChestContents,                         3,  7);
038            addInfo(PYRAMID_DESERT_CHEST,     ComponentScatteredFeatureDesertPyramid.itemsToGenerateInTemple,          2,  7);
039            addInfo(PYRAMID_JUNGLE_CHEST,     ComponentScatteredFeatureJunglePyramid.junglePyramidsChestContents,      2,  7);
040            addInfo(PYRAMID_JUNGLE_DISPENSER, ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserContents,  2,  2);
041            addInfo(STRONGHOLD_CORRIDOR,      ComponentStrongholdChestCorridor.strongholdChestContents,                2,  4);
042            addInfo(STRONGHOLD_LIBRARY,       ComponentStrongholdLibrary.strongholdLibraryChestContents,               1,  5);
043            addInfo(STRONGHOLD_CROSSING,      ComponentStrongholdRoomCrossing.strongholdRoomCrossingChestContents,     1,  5);
044            addInfo(VILLAGE_BLACKSMITH,       ComponentVillageHouse2.villageBlacksmithChestContents,                   3,  9);
045            addInfo(BONUS_CHEST,              WorldServer.bonusChestContent,                                          10, 10);
046    
047            ItemStack book = new ItemStack(Item.field_92053_bW, 1, 0);
048            WeightedRandomChestContent tmp = new WeightedRandomChestContent(book, 1, 1, 1);
049            getInfo(MINESHAFT_CORRIDOR  ).addItem(tmp);
050            getInfo(PYRAMID_DESERT_CHEST).addItem(tmp);        
051            getInfo(PYRAMID_JUNGLE_CHEST).addItem(tmp);
052            getInfo(STRONGHOLD_CORRIDOR ).addItem(tmp);
053            getInfo(STRONGHOLD_LIBRARY  ).addItem(new WeightedRandomChestContent(book, 1, 5, 2));
054            getInfo(STRONGHOLD_CROSSING ).addItem(tmp);
055        }
056    
057        private static void addInfo(String category, WeightedRandomChestContent[] items, int min, int max)
058        {
059            chestInfo.put(category, new ChestGenHooks(category, items, min, max));
060        }
061    
062        /**
063         * Retrieves, or creates the info class for the specified category.
064         * 
065         * @param category The category name
066         * @return A instance of ChestGenHooks for the specified category.
067         */
068        public static ChestGenHooks getInfo(String category)
069        {
070            if (!chestInfo.containsKey(category))
071            {
072                chestInfo.put(category, new ChestGenHooks(category));
073            }
074            return chestInfo.get(category);
075        }
076    
077        /**
078         * Generates an array of items based on the input min/max count.
079         * If the stack can not hold the total amount, it will be split into 
080         * stacks of size 1.
081         * 
082         * @param rand A random number generator
083         * @param source Source item stack
084         * @param min Minimum number of items
085         * @param max Maximum number of items
086         * @return An array containing the generated item stacks 
087         */
088        public static ItemStack[] generateStacks(Random rand, ItemStack source, int min, int max)
089        {
090            int count = min + (rand.nextInt(max - min + 1));
091    
092            ItemStack[] ret;
093            if (source.getItem() == null)
094            {
095                ret = new ItemStack[0];
096            }
097            else if (count > source.getItem().getItemStackLimit())
098            {
099                ret = new ItemStack[count];
100                for (int x = 0; x < count; x++)
101                {
102                    ret[x] = source.copy();
103                    ret[x].stackSize = 1;
104                }
105            }
106            else
107            {
108                ret = new ItemStack[1];
109                ret[0] = source.copy();
110                ret[0].stackSize = count;
111            }
112            return ret;
113        }
114    
115        //shortcut functions, See the non-static versions below
116        public static WeightedRandomChestContent[] getItems(String category, Random rnd){ return getInfo(category).getItems(rnd); }
117        public static int getCount(String category, Random rand){ return getInfo(category).getCount(rand); }
118        public static void addItem(String category, WeightedRandomChestContent item){ getInfo(category).addItem(item); }
119        public static void removeItem(String category, ItemStack item){ getInfo(category).removeItem(item); }
120    
121        private String category;
122        private int countMin = 0;
123        private int countMax = 0;
124        private ArrayList<WeightedRandomChestContent> contents = new ArrayList<WeightedRandomChestContent>();
125    
126        public ChestGenHooks(String category)
127        {
128            this.category = category;
129        }
130        
131        public ChestGenHooks(String category, WeightedRandomChestContent[] items, int min, int max)
132        {
133            this(category);
134            for (WeightedRandomChestContent item : items)
135            {
136                contents.add(item);
137            }
138            countMin = min;
139            countMax = max;
140        }
141        
142        /**
143         * Adds a new entry into the possible items to generate.
144         * 
145         * @param item The item to add.
146         */
147        public void addItem(WeightedRandomChestContent item)
148        {
149            contents.add(item);
150        }
151        
152        /**
153         * Removes all items that match the input item stack, Only metadata and item ID are checked.
154         * If the input item has a metadata of -1, all metadatas will match.
155         * 
156         * @param item The item to check
157         */
158        public void removeItem(ItemStack item)
159        {
160            Iterator<WeightedRandomChestContent> itr = contents.iterator();
161            while(itr.hasNext())
162            {
163                WeightedRandomChestContent cont = itr.next();
164                if (item.isItemEqual(cont.theItemId) || (item.getItemDamage() == -1 && item.itemID == cont.theItemId.itemID))
165                {
166                    itr.remove();
167                }
168            }
169        }
170    
171        /**
172         * Gets an array of all random objects that are associated with this category.
173         * 
174         * @return The random objects
175         */
176        public WeightedRandomChestContent[] getItems(Random rnd)
177        {
178            ArrayList<WeightedRandomChestContent> ret = new ArrayList<WeightedRandomChestContent>();
179            
180            for (WeightedRandomChestContent orig : contents)
181            {
182                Item item = orig.theItemId.getItem();
183    
184                if (item != null)
185                {
186                    WeightedRandomChestContent n = item.getChestGenBase(this, rnd, orig);
187                    if (n != null)
188                    {
189                        ret.add(n);
190                    }
191                }
192            }
193    
194            return ret.toArray(new WeightedRandomChestContent[ret.size()]);
195        }
196    
197        /**
198         * Gets a random number between countMin and countMax.
199         * 
200         * @param rand A RNG
201         * @return A random number where countMin <= num <= countMax
202         */
203        public int getCount(Random rand)
204        {
205            return countMin < countMax ? countMin + rand.nextInt(countMax - countMin) : countMin;
206        }
207    
208        //Accessors
209        public int getMin(){ return countMin; }
210        public int getMax(){ return countMax; }
211        public void setMin(int value){ countMin = value; }
212        public void setMax(int value){ countMax = value; }
213    }