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