001    package cpw.mods.fml.common.registry;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.Map;
006    import java.util.Random;
007    
008    import net.minecraft.src.ComponentVillageStartPiece;
009    import net.minecraft.src.EntityVillager;
010    import net.minecraft.src.Item;
011    import net.minecraft.src.MapGenVillage;
012    import net.minecraft.src.MerchantRecipeList;
013    import net.minecraft.src.StructureVillagePieceWeight;
014    import net.minecraft.src.StructureVillagePieces;
015    import net.minecraft.src.Tuple;
016    
017    import com.google.common.collect.ArrayListMultimap;
018    import com.google.common.collect.Lists;
019    import com.google.common.collect.Maps;
020    import com.google.common.collect.Multimap;
021    
022    import cpw.mods.fml.common.FMLLog;
023    
024    /**
025     * Registry for villager trading control
026     *
027     * @author cpw
028     *
029     */
030    public 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         * Callback to handle trade setup for villagers
156         *
157         * @param recipeList
158         * @param villager
159         * @param villagerType
160         * @param random
161         */
162        public static void manageVillagerTrades(MerchantRecipeList recipeList, EntityVillager villager, int villagerType, Random random)
163        {
164            for (IVillageTradeHandler handler : instance().tradeHandlers.get(villagerType))
165            {
166                handler.manipulateTradesForVillager(villager, recipeList, random);
167            }
168        }
169    
170        public static void addExtraVillageComponents(ArrayList components, Random random, int i)
171        {
172            List<StructureVillagePieceWeight> parts = components;
173            for (IVillageCreationHandler handler : instance().villageCreationHandlers.values())
174            {
175                parts.add(handler.getVillagePieceWeight(random, i));
176            }
177        }
178    
179        public static Object getVillageComponent(StructureVillagePieceWeight villagePiece, ComponentVillageStartPiece startPiece, List pieces, Random random,
180                int p1, int p2, int p3, int p4, int p5)
181        {
182            return instance().villageCreationHandlers.get(villagePiece.villagePieceClass).buildComponent(villagePiece, startPiece, pieces, random, p1, p2, p3, p4, p5);
183        }
184    
185    
186        public static void addEmeraldBuyRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
187        {
188            if (min > 0 && max > 0)
189            {
190                EntityVillager.villagerStockList.put(item.shiftedIndex, new Tuple(min, max));
191            }
192            villager.addMerchantItem(list, item.getMaxDamage(), random, chance);
193        }
194    
195        public static void addEmeraldSellRecipe(EntityVillager villager, MerchantRecipeList list, Random random, Item item, float chance, int min, int max)
196        {
197            if (min > 0 && max > 0)
198            {
199                EntityVillager.blacksmithSellingList.put(item.shiftedIndex, new Tuple(min, max));
200            }
201            villager.addBlacksmithItem(list, item.getMaxDamage(), random, chance);
202        }
203    
204        public static void applyRandomTrade(EntityVillager villager, Random rand)
205        {
206            int extra = instance().newVillagerIds.size();
207            int trade = rand.nextInt(5 + extra);
208            villager.setProfession(trade < 5 ? trade : instance().newVillagerIds.get(trade - 5));
209        }
210    }