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