001    package net.minecraft.entity.passive;
002    
003    import cpw.mods.fml.common.Side;
004    import cpw.mods.fml.common.asm.SideOnly;
005    import cpw.mods.fml.common.registry.VillagerRegistry;
006    
007    import java.util.Collections;
008    import java.util.HashMap;
009    import java.util.Iterator;
010    import java.util.Map;
011    import java.util.Random;
012    import net.minecraft.block.Block;
013    import net.minecraft.enchantment.EnchantmentHelper;
014    import net.minecraft.entity.Entity;
015    import net.minecraft.entity.EntityAgeable;
016    import net.minecraft.entity.EntityLiving;
017    import net.minecraft.entity.IMerchant;
018    import net.minecraft.entity.INpc;
019    import net.minecraft.entity.ai.EntityAIAvoidEntity;
020    import net.minecraft.entity.ai.EntityAIFollowGolem;
021    import net.minecraft.entity.ai.EntityAILookAtTradePlayer;
022    import net.minecraft.entity.ai.EntityAIMoveIndoors;
023    import net.minecraft.entity.ai.EntityAIMoveTwardsRestriction;
024    import net.minecraft.entity.ai.EntityAIOpenDoor;
025    import net.minecraft.entity.ai.EntityAIPlay;
026    import net.minecraft.entity.ai.EntityAIRestrictOpenDoor;
027    import net.minecraft.entity.ai.EntityAISwimming;
028    import net.minecraft.entity.ai.EntityAITradePlayer;
029    import net.minecraft.entity.ai.EntityAIVillagerMate;
030    import net.minecraft.entity.ai.EntityAIWander;
031    import net.minecraft.entity.ai.EntityAIWatchClosest;
032    import net.minecraft.entity.ai.EntityAIWatchClosest2;
033    import net.minecraft.entity.monster.EntityZombie;
034    import net.minecraft.entity.monster.IMob;
035    import net.minecraft.entity.player.EntityPlayer;
036    import net.minecraft.item.Item;
037    import net.minecraft.item.ItemStack;
038    import net.minecraft.nbt.NBTTagCompound;
039    import net.minecraft.potion.Potion;
040    import net.minecraft.potion.PotionEffect;
041    import net.minecraft.util.ChunkCoordinates;
042    import net.minecraft.util.DamageSource;
043    import net.minecraft.util.MathHelper;
044    import net.minecraft.util.Tuple;
045    import net.minecraft.village.MerchantRecipe;
046    import net.minecraft.village.MerchantRecipeList;
047    import net.minecraft.village.Village;
048    import net.minecraft.world.World;
049    
050    public class EntityVillager extends EntityAgeable implements INpc, IMerchant
051    {
052        private int randomTickDivider;
053        private boolean isMating;
054        private boolean isPlaying;
055        Village villageObj;
056    
057        /** This villager's current customer. */
058        private EntityPlayer buyingPlayer;
059    
060        /** Initialises the MerchantRecipeList.java */
061        private MerchantRecipeList buyingList;
062        private int timeUntilReset;
063    
064        /** addDefaultEquipmentAndRecipies is called if this is true */
065        private boolean needsInitilization;
066        private int wealth;
067    
068        /** Last player to trade with this villager, used for aggressivity. */
069        private String lastBuyingPlayer;
070        private boolean field_82190_bM;
071        private float field_82191_bN;
072    
073        /**
074         * a villagers recipe list is intialized off this list ; the 2 params are min/max amount they will trade for 1
075         * emerald
076         */
077        public static final Map villagerStockList = new HashMap();
078    
079        /**
080         * Selling list of Blacksmith items. negative numbers mean 1 emerald for n items, positive numbers are n emeralds
081         * for 1 item
082         */
083        public static final Map blacksmithSellingList = new HashMap();
084    
085        public EntityVillager(World par1World)
086        {
087            this(par1World, 0);
088        }
089    
090        public EntityVillager(World par1World, int par2)
091        {
092            super(par1World);
093            this.randomTickDivider = 0;
094            this.isMating = false;
095            this.isPlaying = false;
096            this.villageObj = null;
097            this.setProfession(par2);
098            this.texture = "/mob/villager/villager.png";
099            this.moveSpeed = 0.5F;
100            this.getNavigator().setBreakDoors(true);
101            this.getNavigator().setAvoidsWater(true);
102            this.tasks.addTask(0, new EntityAISwimming(this));
103            this.tasks.addTask(1, new EntityAIAvoidEntity(this, EntityZombie.class, 8.0F, 0.3F, 0.35F));
104            this.tasks.addTask(1, new EntityAITradePlayer(this));
105            this.tasks.addTask(1, new EntityAILookAtTradePlayer(this));
106            this.tasks.addTask(2, new EntityAIMoveIndoors(this));
107            this.tasks.addTask(3, new EntityAIRestrictOpenDoor(this));
108            this.tasks.addTask(4, new EntityAIOpenDoor(this, true));
109            this.tasks.addTask(5, new EntityAIMoveTwardsRestriction(this, 0.3F));
110            this.tasks.addTask(6, new EntityAIVillagerMate(this));
111            this.tasks.addTask(7, new EntityAIFollowGolem(this));
112            this.tasks.addTask(8, new EntityAIPlay(this, 0.32F));
113            this.tasks.addTask(9, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
114            this.tasks.addTask(9, new EntityAIWatchClosest2(this, EntityVillager.class, 5.0F, 0.02F));
115            this.tasks.addTask(9, new EntityAIWander(this, 0.3F));
116            this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
117        }
118    
119        /**
120         * Returns true if the newer Entity AI code should be run
121         */
122        public boolean isAIEnabled()
123        {
124            return true;
125        }
126    
127        /**
128         * main AI tick function, replaces updateEntityActionState
129         */
130        protected void updateAITick()
131        {
132            if (--this.randomTickDivider <= 0)
133            {
134                this.worldObj.villageCollectionObj.addVillagerPosition(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ));
135                this.randomTickDivider = 70 + this.rand.nextInt(50);
136                this.villageObj = this.worldObj.villageCollectionObj.findNearestVillage(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ), 32);
137    
138                if (this.villageObj == null)
139                {
140                    this.detachHome();
141                }
142                else
143                {
144                    ChunkCoordinates var1 = this.villageObj.getCenter();
145                    this.setHomeArea(var1.posX, var1.posY, var1.posZ, (int)((float)this.villageObj.getVillageRadius() * 0.6F));
146    
147                    if (this.field_82190_bM)
148                    {
149                        this.field_82190_bM = false;
150                        this.villageObj.func_82683_b(5);
151                    }
152                }
153            }
154    
155            if (!this.isTrading() && this.timeUntilReset > 0)
156            {
157                --this.timeUntilReset;
158    
159                if (this.timeUntilReset <= 0)
160                {
161                    if (this.needsInitilization)
162                    {
163                        if (this.buyingList.size() > 1)
164                        {
165                            Iterator var3 = this.buyingList.iterator();
166    
167                            while (var3.hasNext())
168                            {
169                                MerchantRecipe var2 = (MerchantRecipe)var3.next();
170    
171                                if (var2.func_82784_g())
172                                {
173                                    var2.func_82783_a(this.rand.nextInt(6) + this.rand.nextInt(6) + 2);
174                                }
175                            }
176                        }
177    
178                        this.addDefaultEquipmentAndRecipies(1);
179                        this.needsInitilization = false;
180    
181                        if (this.villageObj != null && this.lastBuyingPlayer != null)
182                        {
183                            this.worldObj.setEntityState(this, (byte)14);
184                            this.villageObj.setReputationForPlayer(this.lastBuyingPlayer, 1);
185                        }
186                    }
187    
188                    this.addPotionEffect(new PotionEffect(Potion.regeneration.id, 200, 0));
189                }
190            }
191    
192            super.updateAITick();
193        }
194    
195        /**
196         * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig.
197         */
198        public boolean interact(EntityPlayer par1EntityPlayer)
199        {
200            ItemStack var2 = par1EntityPlayer.inventory.getCurrentItem();
201            boolean var3 = var2 != null && var2.itemID == Item.monsterPlacer.shiftedIndex;
202    
203            if (!var3 && this.isEntityAlive() && !this.isTrading() && !this.isChild())
204            {
205                if (!this.worldObj.isRemote)
206                {
207                    this.setCustomer(par1EntityPlayer);
208                    par1EntityPlayer.displayGUIMerchant(this);
209                }
210    
211                return true;
212            }
213            else
214            {
215                return super.interact(par1EntityPlayer);
216            }
217        }
218    
219        protected void entityInit()
220        {
221            super.entityInit();
222            this.dataWatcher.addObject(16, Integer.valueOf(0));
223        }
224    
225        public int getMaxHealth()
226        {
227            return 20;
228        }
229    
230        /**
231         * (abstract) Protected helper method to write subclass entity data to NBT.
232         */
233        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
234        {
235            super.writeEntityToNBT(par1NBTTagCompound);
236            par1NBTTagCompound.setInteger("Profession", this.getProfession());
237            par1NBTTagCompound.setInteger("Riches", this.wealth);
238    
239            if (this.buyingList != null)
240            {
241                par1NBTTagCompound.setCompoundTag("Offers", this.buyingList.getRecipiesAsTags());
242            }
243        }
244    
245        /**
246         * (abstract) Protected helper method to read subclass entity data from NBT.
247         */
248        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
249        {
250            super.readEntityFromNBT(par1NBTTagCompound);
251            this.setProfession(par1NBTTagCompound.getInteger("Profession"));
252            this.wealth = par1NBTTagCompound.getInteger("Riches");
253    
254            if (par1NBTTagCompound.hasKey("Offers"))
255            {
256                NBTTagCompound var2 = par1NBTTagCompound.getCompoundTag("Offers");
257                this.buyingList = new MerchantRecipeList(var2);
258            }
259        }
260    
261        @SideOnly(Side.CLIENT)
262    
263        /**
264         * Returns the texture's file path as a String.
265         */
266        public String getTexture()
267        {
268            switch (this.getProfession())
269            {
270                case 0:
271                    return "/mob/villager/farmer.png";
272                case 1:
273                    return "/mob/villager/librarian.png";
274                case 2:
275                    return "/mob/villager/priest.png";
276                case 3:
277                    return "/mob/villager/smith.png";
278                case 4:
279                    return "/mob/villager/butcher.png";
280                default:
281                    return VillagerRegistry.getVillagerSkin(this.getProfession(), super.getTexture());
282            }
283        }
284    
285        /**
286         * Determines if an entity can be despawned, used on idle far away entities
287         */
288        protected boolean canDespawn()
289        {
290            return false;
291        }
292    
293        /**
294         * Returns the sound this mob makes while it's alive.
295         */
296        protected String getLivingSound()
297        {
298            return "mob.villager.default";
299        }
300    
301        /**
302         * Returns the sound this mob makes when it is hurt.
303         */
304        protected String getHurtSound()
305        {
306            return "mob.villager.defaulthurt";
307        }
308    
309        /**
310         * Returns the sound this mob makes on death.
311         */
312        protected String getDeathSound()
313        {
314            return "mob.villager.defaultdeath";
315        }
316    
317        public void setProfession(int par1)
318        {
319            this.dataWatcher.updateObject(16, Integer.valueOf(par1));
320        }
321    
322        public int getProfession()
323        {
324            return this.dataWatcher.getWatchableObjectInt(16);
325        }
326    
327        public boolean isMating()
328        {
329            return this.isMating;
330        }
331    
332        public void setMating(boolean par1)
333        {
334            this.isMating = par1;
335        }
336    
337        public void setPlaying(boolean par1)
338        {
339            this.isPlaying = par1;
340        }
341    
342        public boolean isPlaying()
343        {
344            return this.isPlaying;
345        }
346    
347        public void setRevengeTarget(EntityLiving par1EntityLiving)
348        {
349            super.setRevengeTarget(par1EntityLiving);
350    
351            if (this.villageObj != null && par1EntityLiving != null)
352            {
353                this.villageObj.addOrRenewAgressor(par1EntityLiving);
354    
355                if (par1EntityLiving instanceof EntityPlayer)
356                {
357                    byte var2 = -1;
358    
359                    if (this.isChild())
360                    {
361                        var2 = -3;
362                    }
363    
364                    this.villageObj.setReputationForPlayer(((EntityPlayer)par1EntityLiving).getCommandSenderName(), var2);
365    
366                    if (this.isEntityAlive())
367                    {
368                        this.worldObj.setEntityState(this, (byte)13);
369                    }
370                }
371            }
372        }
373    
374        /**
375         * Called when the mob's health reaches 0.
376         */
377        public void onDeath(DamageSource par1DamageSource)
378        {
379            if (this.villageObj != null)
380            {
381                Entity var2 = par1DamageSource.getEntity();
382    
383                if (var2 != null)
384                {
385                    if (var2 instanceof EntityPlayer)
386                    {
387                        this.villageObj.setReputationForPlayer(((EntityPlayer)var2).getCommandSenderName(), -2);
388                    }
389                    else if (var2 instanceof IMob)
390                    {
391                        this.villageObj.func_82692_h();
392                    }
393                }
394                else if (var2 == null)
395                {
396                    EntityPlayer var3 = this.worldObj.getClosestPlayerToEntity(this, 16.0D);
397    
398                    if (var3 != null)
399                    {
400                        this.villageObj.func_82692_h();
401                    }
402                }
403            }
404    
405            super.onDeath(par1DamageSource);
406        }
407    
408        public void setCustomer(EntityPlayer par1EntityPlayer)
409        {
410            this.buyingPlayer = par1EntityPlayer;
411        }
412    
413        public EntityPlayer getCustomer()
414        {
415            return this.buyingPlayer;
416        }
417    
418        public boolean isTrading()
419        {
420            return this.buyingPlayer != null;
421        }
422    
423        public void useRecipe(MerchantRecipe par1MerchantRecipe)
424        {
425            par1MerchantRecipe.incrementToolUses();
426    
427            if (par1MerchantRecipe.hasSameIDsAs((MerchantRecipe)this.buyingList.get(this.buyingList.size() - 1)))
428            {
429                this.timeUntilReset = 40;
430                this.needsInitilization = true;
431    
432                if (this.buyingPlayer != null)
433                {
434                    this.lastBuyingPlayer = this.buyingPlayer.getCommandSenderName();
435                }
436                else
437                {
438                    this.lastBuyingPlayer = null;
439                }
440            }
441    
442            if (par1MerchantRecipe.getItemToBuy().itemID == Item.emerald.shiftedIndex)
443            {
444                this.wealth += par1MerchantRecipe.getItemToBuy().stackSize;
445            }
446        }
447    
448        public MerchantRecipeList getRecipes(EntityPlayer par1EntityPlayer)
449        {
450            if (this.buyingList == null)
451            {
452                this.addDefaultEquipmentAndRecipies(1);
453            }
454    
455            return this.buyingList;
456        }
457    
458        private float func_82188_j(float par1)
459        {
460            float var2 = par1 + this.field_82191_bN;
461            return var2 > 0.9F ? 0.9F - (var2 - 0.9F) : var2;
462        }
463    
464        /**
465         * based on the villagers profession add items, equipment, and recipies adds par1 random items to the list of things
466         * that the villager wants to buy. (at most 1 of each wanted type is added)
467         */
468        private void addDefaultEquipmentAndRecipies(int par1)
469        {
470            if (this.buyingList != null)
471            {
472                this.field_82191_bN = MathHelper.sqrt_float((float)this.buyingList.size()) * 0.2F;
473            }
474            else
475            {
476                this.field_82191_bN = 0.0F;
477            }
478    
479            MerchantRecipeList var2;
480            var2 = new MerchantRecipeList();
481            VillagerRegistry.manageVillagerTrades(var2, this, this.getProfession(), this.rand);
482            label48:
483    
484            switch (this.getProfession())
485            {
486                case 0:
487                    addMerchantItem(var2, Item.wheat.shiftedIndex, this.rand, this.func_82188_j(0.9F));
488                    addMerchantItem(var2, Block.cloth.blockID, this.rand, this.func_82188_j(0.5F));
489                    addMerchantItem(var2, Item.chickenRaw.shiftedIndex, this.rand, this.func_82188_j(0.5F));
490                    addMerchantItem(var2, Item.fishCooked.shiftedIndex, this.rand, this.func_82188_j(0.4F));
491                    addBlacksmithItem(var2, Item.bread.shiftedIndex, this.rand, this.func_82188_j(0.9F));
492                    addBlacksmithItem(var2, Item.melon.shiftedIndex, this.rand, this.func_82188_j(0.3F));
493                    addBlacksmithItem(var2, Item.appleRed.shiftedIndex, this.rand, this.func_82188_j(0.3F));
494                    addBlacksmithItem(var2, Item.cookie.shiftedIndex, this.rand, this.func_82188_j(0.3F));
495                    addBlacksmithItem(var2, Item.shears.shiftedIndex, this.rand, this.func_82188_j(0.3F));
496                    addBlacksmithItem(var2, Item.flintAndSteel.shiftedIndex, this.rand, this.func_82188_j(0.3F));
497                    addBlacksmithItem(var2, Item.chickenCooked.shiftedIndex, this.rand, this.func_82188_j(0.3F));
498                    addBlacksmithItem(var2, Item.arrow.shiftedIndex, this.rand, this.func_82188_j(0.5F));
499    
500                    if (this.rand.nextFloat() < this.func_82188_j(0.5F))
501                    {
502                        var2.add(new MerchantRecipe(new ItemStack(Block.gravel, 10), new ItemStack(Item.emerald), new ItemStack(Item.flint.shiftedIndex, 4 + this.rand.nextInt(2), 0)));
503                    }
504    
505                    break;
506                case 1:
507                    addMerchantItem(var2, Item.paper.shiftedIndex, this.rand, this.func_82188_j(0.8F));
508                    addMerchantItem(var2, Item.book.shiftedIndex, this.rand, this.func_82188_j(0.8F));
509                    addMerchantItem(var2, Item.writtenBook.shiftedIndex, this.rand, this.func_82188_j(0.3F));
510                    addBlacksmithItem(var2, Block.bookShelf.blockID, this.rand, this.func_82188_j(0.8F));
511                    addBlacksmithItem(var2, Block.glass.blockID, this.rand, this.func_82188_j(0.2F));
512                    addBlacksmithItem(var2, Item.compass.shiftedIndex, this.rand, this.func_82188_j(0.2F));
513                    addBlacksmithItem(var2, Item.pocketSundial.shiftedIndex, this.rand, this.func_82188_j(0.2F));
514                    break;
515                case 2:
516                    addBlacksmithItem(var2, Item.eyeOfEnder.shiftedIndex, this.rand, this.func_82188_j(0.3F));
517                    addBlacksmithItem(var2, Item.expBottle.shiftedIndex, this.rand, this.func_82188_j(0.2F));
518                    addBlacksmithItem(var2, Item.redstone.shiftedIndex, this.rand, this.func_82188_j(0.4F));
519                    addBlacksmithItem(var2, Block.glowStone.blockID, this.rand, this.func_82188_j(0.3F));
520                    int[] var3 = new int[] {Item.swordSteel.shiftedIndex, Item.swordDiamond.shiftedIndex, Item.plateSteel.shiftedIndex, Item.plateDiamond.shiftedIndex, Item.axeSteel.shiftedIndex, Item.axeDiamond.shiftedIndex, Item.pickaxeSteel.shiftedIndex, Item.pickaxeDiamond.shiftedIndex};
521                    int[] var4 = var3;
522                    int var5 = var3.length;
523                    int var6 = 0;
524    
525                    while (true)
526                    {
527                        if (var6 >= var5)
528                        {
529                            break label48;
530                        }
531    
532                        int var7 = var4[var6];
533    
534                        if (this.rand.nextFloat() < this.func_82188_j(0.05F))
535                        {
536                            var2.add(new MerchantRecipe(new ItemStack(var7, 1, 0), new ItemStack(Item.emerald, 2 + this.rand.nextInt(3), 0), EnchantmentHelper.addRandomEnchantment(this.rand, new ItemStack(var7, 1, 0), 5 + this.rand.nextInt(15))));
537                        }
538    
539                        ++var6;
540                    }
541                case 3:
542                    addMerchantItem(var2, Item.coal.shiftedIndex, this.rand, this.func_82188_j(0.7F));
543                    addMerchantItem(var2, Item.ingotIron.shiftedIndex, this.rand, this.func_82188_j(0.5F));
544                    addMerchantItem(var2, Item.ingotGold.shiftedIndex, this.rand, this.func_82188_j(0.5F));
545                    addMerchantItem(var2, Item.diamond.shiftedIndex, this.rand, this.func_82188_j(0.5F));
546                    addBlacksmithItem(var2, Item.swordSteel.shiftedIndex, this.rand, this.func_82188_j(0.5F));
547                    addBlacksmithItem(var2, Item.swordDiamond.shiftedIndex, this.rand, this.func_82188_j(0.5F));
548                    addBlacksmithItem(var2, Item.axeSteel.shiftedIndex, this.rand, this.func_82188_j(0.3F));
549                    addBlacksmithItem(var2, Item.axeDiamond.shiftedIndex, this.rand, this.func_82188_j(0.3F));
550                    addBlacksmithItem(var2, Item.pickaxeSteel.shiftedIndex, this.rand, this.func_82188_j(0.5F));
551                    addBlacksmithItem(var2, Item.pickaxeDiamond.shiftedIndex, this.rand, this.func_82188_j(0.5F));
552                    addBlacksmithItem(var2, Item.shovelSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
553                    addBlacksmithItem(var2, Item.shovelDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
554                    addBlacksmithItem(var2, Item.hoeSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
555                    addBlacksmithItem(var2, Item.hoeDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
556                    addBlacksmithItem(var2, Item.bootsSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
557                    addBlacksmithItem(var2, Item.bootsDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
558                    addBlacksmithItem(var2, Item.helmetSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
559                    addBlacksmithItem(var2, Item.helmetDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
560                    addBlacksmithItem(var2, Item.plateSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
561                    addBlacksmithItem(var2, Item.plateDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
562                    addBlacksmithItem(var2, Item.legsSteel.shiftedIndex, this.rand, this.func_82188_j(0.2F));
563                    addBlacksmithItem(var2, Item.legsDiamond.shiftedIndex, this.rand, this.func_82188_j(0.2F));
564                    addBlacksmithItem(var2, Item.bootsChain.shiftedIndex, this.rand, this.func_82188_j(0.1F));
565                    addBlacksmithItem(var2, Item.helmetChain.shiftedIndex, this.rand, this.func_82188_j(0.1F));
566                    addBlacksmithItem(var2, Item.plateChain.shiftedIndex, this.rand, this.func_82188_j(0.1F));
567                    addBlacksmithItem(var2, Item.legsChain.shiftedIndex, this.rand, this.func_82188_j(0.1F));
568                    break;
569                case 4:
570                    addMerchantItem(var2, Item.coal.shiftedIndex, this.rand, this.func_82188_j(0.7F));
571                    addMerchantItem(var2, Item.porkRaw.shiftedIndex, this.rand, this.func_82188_j(0.5F));
572                    addMerchantItem(var2, Item.beefRaw.shiftedIndex, this.rand, this.func_82188_j(0.5F));
573                    addBlacksmithItem(var2, Item.saddle.shiftedIndex, this.rand, this.func_82188_j(0.1F));
574                    addBlacksmithItem(var2, Item.plateLeather.shiftedIndex, this.rand, this.func_82188_j(0.3F));
575                    addBlacksmithItem(var2, Item.bootsLeather.shiftedIndex, this.rand, this.func_82188_j(0.3F));
576                    addBlacksmithItem(var2, Item.helmetLeather.shiftedIndex, this.rand, this.func_82188_j(0.3F));
577                    addBlacksmithItem(var2, Item.legsLeather.shiftedIndex, this.rand, this.func_82188_j(0.3F));
578                    addBlacksmithItem(var2, Item.porkCooked.shiftedIndex, this.rand, this.func_82188_j(0.3F));
579                    addBlacksmithItem(var2, Item.beefCooked.shiftedIndex, this.rand, this.func_82188_j(0.3F));
580            }
581    
582            if (var2.isEmpty())
583            {
584                addMerchantItem(var2, Item.ingotGold.shiftedIndex, this.rand, 1.0F);
585            }
586    
587            Collections.shuffle(var2);
588    
589            if (this.buyingList == null)
590            {
591                this.buyingList = new MerchantRecipeList();
592            }
593    
594            for (int var8 = 0; var8 < par1 && var8 < var2.size(); ++var8)
595            {
596                this.buyingList.addToListWithCheck((MerchantRecipe)var2.get(var8));
597            }
598        }
599    
600        @SideOnly(Side.CLIENT)
601        public void setRecipes(MerchantRecipeList par1MerchantRecipeList) {}
602    
603        /**
604         * each recipie takes a random stack from villagerStockList and offers it for 1 emerald
605         */
606        public static void addMerchantItem(MerchantRecipeList par0MerchantRecipeList, int par1, Random par2Random, float par3)
607        {
608            if (par2Random.nextFloat() < par3)
609            {
610                par0MerchantRecipeList.add(new MerchantRecipe(getRandomSizedStack(par1, par2Random), Item.emerald));
611            }
612        }
613    
614        private static ItemStack getRandomSizedStack(int par0, Random par1Random)
615        {
616            return new ItemStack(par0, getRandomCountForItem(par0, par1Random), 0);
617        }
618    
619        /**
620         * default to 1, and villagerStockList contains a min/max amount for each index
621         */
622        private static int getRandomCountForItem(int par0, Random par1Random)
623        {
624            Tuple var2 = (Tuple)villagerStockList.get(Integer.valueOf(par0));
625            return var2 == null ? 1 : (((Integer)var2.getFirst()).intValue() >= ((Integer)var2.getSecond()).intValue() ? ((Integer)var2.getFirst()).intValue() : ((Integer)var2.getFirst()).intValue() + par1Random.nextInt(((Integer)var2.getSecond()).intValue() - ((Integer)var2.getFirst()).intValue()));
626        }
627    
628        public static void addBlacksmithItem(MerchantRecipeList par0MerchantRecipeList, int par1, Random par2Random, float par3)
629        {
630            if (par2Random.nextFloat() < par3)
631            {
632                int var4 = getRandomCountForBlacksmithItem(par1, par2Random);
633                ItemStack var5;
634                ItemStack var6;
635    
636                if (var4 < 0)
637                {
638                    var5 = new ItemStack(Item.emerald.shiftedIndex, 1, 0);
639                    var6 = new ItemStack(par1, -var4, 0);
640                }
641                else
642                {
643                    var5 = new ItemStack(Item.emerald.shiftedIndex, var4, 0);
644                    var6 = new ItemStack(par1, 1, 0);
645                }
646    
647                par0MerchantRecipeList.add(new MerchantRecipe(var5, var6));
648            }
649        }
650    
651        private static int getRandomCountForBlacksmithItem(int par0, Random par1Random)
652        {
653            Tuple var2 = (Tuple)blacksmithSellingList.get(Integer.valueOf(par0));
654            return var2 == null ? 1 : (((Integer)var2.getFirst()).intValue() >= ((Integer)var2.getSecond()).intValue() ? ((Integer)var2.getFirst()).intValue() : ((Integer)var2.getFirst()).intValue() + par1Random.nextInt(((Integer)var2.getSecond()).intValue() - ((Integer)var2.getFirst()).intValue()));
655        }
656    
657        @SideOnly(Side.CLIENT)
658        public void handleHealthUpdate(byte par1)
659        {
660            if (par1 == 12)
661            {
662                this.generateRandomParticles("heart");
663            }
664            else if (par1 == 13)
665            {
666                this.generateRandomParticles("angryVillager");
667            }
668            else if (par1 == 14)
669            {
670                this.generateRandomParticles("happyVillager");
671            }
672            else
673            {
674                super.handleHealthUpdate(par1);
675            }
676        }
677    
678        @SideOnly(Side.CLIENT)
679    
680        /**
681         * par1 is the particleName
682         */
683        private void generateRandomParticles(String par1Str)
684        {
685            for (int var2 = 0; var2 < 5; ++var2)
686            {
687                double var3 = this.rand.nextGaussian() * 0.02D;
688                double var5 = this.rand.nextGaussian() * 0.02D;
689                double var7 = this.rand.nextGaussian() * 0.02D;
690                this.worldObj.spawnParticle(par1Str, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 1.0D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, var3, var5, var7);
691            }
692        }
693    
694        /**
695         * Initialize this creature.
696         */
697        public void initCreature()
698        {
699            VillagerRegistry.applyRandomTrade(this, worldObj.rand);
700        }
701    
702        public void func_82187_q()
703        {
704            this.field_82190_bM = true;
705        }
706    
707        public EntityVillager func_90012_b(EntityAgeable par1EntityAgeable)
708        {
709            EntityVillager var2 = new EntityVillager(this.worldObj);
710            var2.initCreature();
711            return var2;
712        }
713    
714        public EntityAgeable func_90011_a(EntityAgeable par1EntityAgeable)
715        {
716            return this.func_90012_b(par1EntityAgeable);
717        }
718    
719        static
720        {
721            villagerStockList.put(Integer.valueOf(Item.coal.shiftedIndex), new Tuple(Integer.valueOf(16), Integer.valueOf(24)));
722            villagerStockList.put(Integer.valueOf(Item.ingotIron.shiftedIndex), new Tuple(Integer.valueOf(8), Integer.valueOf(10)));
723            villagerStockList.put(Integer.valueOf(Item.ingotGold.shiftedIndex), new Tuple(Integer.valueOf(8), Integer.valueOf(10)));
724            villagerStockList.put(Integer.valueOf(Item.diamond.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(6)));
725            villagerStockList.put(Integer.valueOf(Item.paper.shiftedIndex), new Tuple(Integer.valueOf(24), Integer.valueOf(36)));
726            villagerStockList.put(Integer.valueOf(Item.book.shiftedIndex), new Tuple(Integer.valueOf(11), Integer.valueOf(13)));
727            villagerStockList.put(Integer.valueOf(Item.writtenBook.shiftedIndex), new Tuple(Integer.valueOf(1), Integer.valueOf(1)));
728            villagerStockList.put(Integer.valueOf(Item.enderPearl.shiftedIndex), new Tuple(Integer.valueOf(3), Integer.valueOf(4)));
729            villagerStockList.put(Integer.valueOf(Item.eyeOfEnder.shiftedIndex), new Tuple(Integer.valueOf(2), Integer.valueOf(3)));
730            villagerStockList.put(Integer.valueOf(Item.porkRaw.shiftedIndex), new Tuple(Integer.valueOf(14), Integer.valueOf(18)));
731            villagerStockList.put(Integer.valueOf(Item.beefRaw.shiftedIndex), new Tuple(Integer.valueOf(14), Integer.valueOf(18)));
732            villagerStockList.put(Integer.valueOf(Item.chickenRaw.shiftedIndex), new Tuple(Integer.valueOf(14), Integer.valueOf(18)));
733            villagerStockList.put(Integer.valueOf(Item.fishCooked.shiftedIndex), new Tuple(Integer.valueOf(9), Integer.valueOf(13)));
734            villagerStockList.put(Integer.valueOf(Item.seeds.shiftedIndex), new Tuple(Integer.valueOf(34), Integer.valueOf(48)));
735            villagerStockList.put(Integer.valueOf(Item.melonSeeds.shiftedIndex), new Tuple(Integer.valueOf(30), Integer.valueOf(38)));
736            villagerStockList.put(Integer.valueOf(Item.pumpkinSeeds.shiftedIndex), new Tuple(Integer.valueOf(30), Integer.valueOf(38)));
737            villagerStockList.put(Integer.valueOf(Item.wheat.shiftedIndex), new Tuple(Integer.valueOf(18), Integer.valueOf(22)));
738            villagerStockList.put(Integer.valueOf(Block.cloth.blockID), new Tuple(Integer.valueOf(14), Integer.valueOf(22)));
739            villagerStockList.put(Integer.valueOf(Item.rottenFlesh.shiftedIndex), new Tuple(Integer.valueOf(36), Integer.valueOf(64)));
740            blacksmithSellingList.put(Integer.valueOf(Item.flintAndSteel.shiftedIndex), new Tuple(Integer.valueOf(3), Integer.valueOf(4)));
741            blacksmithSellingList.put(Integer.valueOf(Item.shears.shiftedIndex), new Tuple(Integer.valueOf(3), Integer.valueOf(4)));
742            blacksmithSellingList.put(Integer.valueOf(Item.swordSteel.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(11)));
743            blacksmithSellingList.put(Integer.valueOf(Item.swordDiamond.shiftedIndex), new Tuple(Integer.valueOf(12), Integer.valueOf(14)));
744            blacksmithSellingList.put(Integer.valueOf(Item.axeSteel.shiftedIndex), new Tuple(Integer.valueOf(6), Integer.valueOf(8)));
745            blacksmithSellingList.put(Integer.valueOf(Item.axeDiamond.shiftedIndex), new Tuple(Integer.valueOf(9), Integer.valueOf(12)));
746            blacksmithSellingList.put(Integer.valueOf(Item.pickaxeSteel.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(9)));
747            blacksmithSellingList.put(Integer.valueOf(Item.pickaxeDiamond.shiftedIndex), new Tuple(Integer.valueOf(10), Integer.valueOf(12)));
748            blacksmithSellingList.put(Integer.valueOf(Item.shovelSteel.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(6)));
749            blacksmithSellingList.put(Integer.valueOf(Item.shovelDiamond.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(8)));
750            blacksmithSellingList.put(Integer.valueOf(Item.hoeSteel.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(6)));
751            blacksmithSellingList.put(Integer.valueOf(Item.hoeDiamond.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(8)));
752            blacksmithSellingList.put(Integer.valueOf(Item.bootsSteel.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(6)));
753            blacksmithSellingList.put(Integer.valueOf(Item.bootsDiamond.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(8)));
754            blacksmithSellingList.put(Integer.valueOf(Item.helmetSteel.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(6)));
755            blacksmithSellingList.put(Integer.valueOf(Item.helmetDiamond.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(8)));
756            blacksmithSellingList.put(Integer.valueOf(Item.plateSteel.shiftedIndex), new Tuple(Integer.valueOf(10), Integer.valueOf(14)));
757            blacksmithSellingList.put(Integer.valueOf(Item.plateDiamond.shiftedIndex), new Tuple(Integer.valueOf(16), Integer.valueOf(19)));
758            blacksmithSellingList.put(Integer.valueOf(Item.legsSteel.shiftedIndex), new Tuple(Integer.valueOf(8), Integer.valueOf(10)));
759            blacksmithSellingList.put(Integer.valueOf(Item.legsDiamond.shiftedIndex), new Tuple(Integer.valueOf(11), Integer.valueOf(14)));
760            blacksmithSellingList.put(Integer.valueOf(Item.bootsChain.shiftedIndex), new Tuple(Integer.valueOf(5), Integer.valueOf(7)));
761            blacksmithSellingList.put(Integer.valueOf(Item.helmetChain.shiftedIndex), new Tuple(Integer.valueOf(5), Integer.valueOf(7)));
762            blacksmithSellingList.put(Integer.valueOf(Item.plateChain.shiftedIndex), new Tuple(Integer.valueOf(11), Integer.valueOf(15)));
763            blacksmithSellingList.put(Integer.valueOf(Item.legsChain.shiftedIndex), new Tuple(Integer.valueOf(9), Integer.valueOf(11)));
764            blacksmithSellingList.put(Integer.valueOf(Item.bread.shiftedIndex), new Tuple(Integer.valueOf(-4), Integer.valueOf(-2)));
765            blacksmithSellingList.put(Integer.valueOf(Item.melon.shiftedIndex), new Tuple(Integer.valueOf(-8), Integer.valueOf(-4)));
766            blacksmithSellingList.put(Integer.valueOf(Item.appleRed.shiftedIndex), new Tuple(Integer.valueOf(-8), Integer.valueOf(-4)));
767            blacksmithSellingList.put(Integer.valueOf(Item.cookie.shiftedIndex), new Tuple(Integer.valueOf(-10), Integer.valueOf(-7)));
768            blacksmithSellingList.put(Integer.valueOf(Block.glass.blockID), new Tuple(Integer.valueOf(-5), Integer.valueOf(-3)));
769            blacksmithSellingList.put(Integer.valueOf(Block.bookShelf.blockID), new Tuple(Integer.valueOf(3), Integer.valueOf(4)));
770            blacksmithSellingList.put(Integer.valueOf(Item.plateLeather.shiftedIndex), new Tuple(Integer.valueOf(4), Integer.valueOf(5)));
771            blacksmithSellingList.put(Integer.valueOf(Item.bootsLeather.shiftedIndex), new Tuple(Integer.valueOf(2), Integer.valueOf(4)));
772            blacksmithSellingList.put(Integer.valueOf(Item.helmetLeather.shiftedIndex), new Tuple(Integer.valueOf(2), Integer.valueOf(4)));
773            blacksmithSellingList.put(Integer.valueOf(Item.legsLeather.shiftedIndex), new Tuple(Integer.valueOf(2), Integer.valueOf(4)));
774            blacksmithSellingList.put(Integer.valueOf(Item.saddle.shiftedIndex), new Tuple(Integer.valueOf(6), Integer.valueOf(8)));
775            blacksmithSellingList.put(Integer.valueOf(Item.expBottle.shiftedIndex), new Tuple(Integer.valueOf(-4), Integer.valueOf(-1)));
776            blacksmithSellingList.put(Integer.valueOf(Item.redstone.shiftedIndex), new Tuple(Integer.valueOf(-4), Integer.valueOf(-1)));
777            blacksmithSellingList.put(Integer.valueOf(Item.compass.shiftedIndex), new Tuple(Integer.valueOf(10), Integer.valueOf(12)));
778            blacksmithSellingList.put(Integer.valueOf(Item.pocketSundial.shiftedIndex), new Tuple(Integer.valueOf(10), Integer.valueOf(12)));
779            blacksmithSellingList.put(Integer.valueOf(Block.glowStone.blockID), new Tuple(Integer.valueOf(-3), Integer.valueOf(-1)));
780            blacksmithSellingList.put(Integer.valueOf(Item.porkCooked.shiftedIndex), new Tuple(Integer.valueOf(-7), Integer.valueOf(-5)));
781            blacksmithSellingList.put(Integer.valueOf(Item.beefCooked.shiftedIndex), new Tuple(Integer.valueOf(-7), Integer.valueOf(-5)));
782            blacksmithSellingList.put(Integer.valueOf(Item.chickenCooked.shiftedIndex), new Tuple(Integer.valueOf(-8), Integer.valueOf(-6)));
783            blacksmithSellingList.put(Integer.valueOf(Item.eyeOfEnder.shiftedIndex), new Tuple(Integer.valueOf(7), Integer.valueOf(11)));
784            blacksmithSellingList.put(Integer.valueOf(Item.arrow.shiftedIndex), new Tuple(Integer.valueOf(-12), Integer.valueOf(-8)));
785        }
786    }