    001package net.minecraftforge.common;
    002
    003import java.util.*;
    004
    005import net.minecraft.item.Item;
    006import net.minecraft.item.ItemStack;
    007import net.minecraft.util.WeightedRandom;
    008import net.minecraft.util.WeightedRandomChestContent;
    009import net.minecraft.world.WorldServer;
    010import net.minecraft.world.gen.structure.*;
    011
    012public 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.enchantedBook, 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}