    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    }