001package cpw.mods.fml.common.registry;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.Map;
006import java.util.Random;
007import java.util.Collection;
008import java.util.Collections;
009
010import net.minecraft.entity.passive.EntityVillager;
011import net.minecraft.item.Item;
012import net.minecraft.util.Tuple;
013import net.minecraft.village.MerchantRecipeList;
014import net.minecraft.world.gen.structure.ComponentVillageStartPiece;
015import net.minecraft.world.gen.structure.StructureVillagePieceWeight;
016
017import com.google.common.collect.ArrayListMultimap;
018import com.google.common.collect.Lists;
019import com.google.common.collect.Maps;
020import com.google.common.collect.Multimap;
021
022import cpw.mods.fml.common.FMLLog;
023
024/**
025 * Registry for villager trading control
026 *
027 * @author cpw
028 *
029 */
030public class VillagerRegistry
031{
032    private static final VillagerRegistry INSTANCE = new VillagerRegistry();
033
034    private Multimap<Integer, IVillageTradeHandler> tradeHandlers = ArrayListMultimap.create();
035    private Map<Class<?>, IVillageCreationHandler> villageCreationHandlers = Maps.newHashMap();
036    private Map<Integer, String> newVillagers = Maps.newHashMap();
037    private List<Integer> newVillagerIds = Lists.newArrayList();
038
039    /**
040     * Allow access to the {@link StructureVillagePieces} array controlling new village
041     * creation so you can insert your own new village pieces
042     *
043     * @author cpw
044     *
045     */
046    public interface IVillageCreationHandler
047    {
048        /**
049         * Called when {@link MapGenVillage} is creating a new village
050         *
051         * @param random
052         * @param i
053         */
054        StructureVillagePieceWeight getVillagePieceWeight(Random random, int i);
055
056        /**
057         * The class of the root structure component to add to the village
058         */
059        Class<?> getComponentClass();
060
061
062        /**
063         * Build an instance of the village component {@link StructureVillagePieces}
064         * @param villagePiece
065         * @param startPiece
066         * @param pieces
067         * @param random
068         * @param p1
069         * @param p2
070         * @param p3
071         * @param p4
072         * @param p5
073         */
074        Object buildComponent(StructureVillagePieceWeight villagePiece, ComponentVillageStartPiece startPiece, List pieces, Random random, int p1,
075                int p2, int p3, int p4, int p5);
076    }
077
078    /**
079     * Allow access to the {@link MerchantRecipeList} for a villager type for manipulation
080     *
081     * @author cpw
082     *
083     */
084    public interface IVillageTradeHandler
085    {
086        /**
087         * Called to allow changing the content of the {@link MerchantRecipeList} for the villager
088         * supplied during creation
089         *
090         * @param villager
091         * @param recipeList
092         */
093        void manipulateTradesForVillager(EntityVillager villager, MerchantRecipeList recipeList, Random random);
094    }
095
096    public static VillagerRegistry instance()
097    {
098        return INSTANCE;
099    }
100
101    /**
102     * Register a new skin for a villager type
103     *
104     * @param villagerId
105     * @param villagerSkin
106     */
107    public void registerVillagerType(int villagerId, String villagerSkin)
108    {
109        if (newVillagers.containsKey(villagerId))
110        {
111            FMLLog.severe("Attempt to register duplicate villager id %d", villagerId);
112            throw new RuntimeException();
113        }
114        newVillagers.put(villagerId, villagerSkin);
115        newVillagerIds.add(villagerId);
116    }
117
118    /**
119     * Register a new village creation handler
120     *
121     * @param handler
122     */
123    public void registerVillageCreationHandler(IVillageCreationHandler handler)
124    {
125        villageCreationHandlers.put(handler.getComponentClass(), handler);
126    }
127
128    /**
129     * Register a new villager trading handler for the specified villager type
130     *
131     * @param villagerId
132     * @param handler
133     */
134    public void registerVillageTradeHandler(int villagerId, IVillageTradeHandler handler)
135    {
136        tradeHandlers.put(villagerId, handler);
137    }
138
139    /**
140     * Callback to setup new villager types
141     *
142     * @param villagerType
143     * @param defaultSkin
144     */
145    public static String getVillagerSkin(int villagerType, String defaultSkin)
146    {
147        if (instance().newVillagers.containsKey(villagerType))
148        {
149            return instance().newVillagers.get(villagerType);
150        }
151        return defaultSkin;
152    }
153    
154    /**
155     * Returns a list of all added villager types
156     * 
157     * @return newVillagerIds
158     */
159    public static Collection<Integer> getRegisteredVillagers()
160    {
161        return Collections.unmodifiableCollection(instance().newVillagerIds);
162    }
163    /**
164     * Callback to handle trade setup for villagers
165     *
166     * @param recipeList
167     * @param villager
168     * @param villagerType
169     * @param random
170     */
171    public static void manageVillagerTrades(MerchantRecipeList recipeList, EntityVillager villager, int villagerType, Random random)
172    {
173        for (IVillageTradeHandler handler : instance().tradeHandlers.get(villagerType))
174        {
175            handler.manipulateTradesForVillager(villager, recipeList, random);
176        }
177    }
178
179    public static void addExtraVillageComponents(ArrayList components, Random random, int i)
180    {
181        List<StructureVillagePieceWeight> parts = components;
182        for (IVillageCreationHandler handler : instance().villageCreationHandlers.values())
183        {
184            parts.add(handler.getVillagePieceWeight(random, i));
185        }
186    }
187
188    public static Object getVillageComponent(StructureVillagePieceWeight villagePiece, ComponentVillageStartPiece startPiece, List pieces, Random random,
189            int p1, int p2, int p3, int p4, int p5)
190    {
191        return instance().villageCreationHandlers.get(villagePiece.villagePieceClass).buildComponent(villagePiece, startPiece, pieces, random, p1, p2, p3, p4, p5);
192    }
193
194
195    public static void addEmeraldBuyRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
196    {
197        if (min > 0 && max > 0)
198        {
199            EntityVillager.villagerStockList.put(item.itemID, new Tuple(min, max));
200        }
201        villager.addMerchantItem(list, item.getMaxDamage(), random, chance);
202    }
203
204    public static void addEmeraldSellRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
205    {
206        if (min > 0 && max > 0)
207        {
208            EntityVillager.blacksmithSellingList.put(item.itemID, new Tuple(min, max));
209        }
210        villager.addBlacksmithItem(list, item.getMaxDamage(), random, chance);
211    }
212
213    public static void applyRandomTrade(EntityVillager villager, Random rand)
214    {
215        int extra = instance().newVillagerIds.size();
216        int trade = rand.nextInt(5 + extra);
217        villager.setProfession(trade < 5 ? trade : instance().newVillagerIds.get(trade - 5));
218    }
219}