001    package net.minecraft.enchantment;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.Iterator;
006    import java.util.LinkedHashMap;
007    import java.util.List;
008    import java.util.Map;
009    import java.util.Random;
010    import net.minecraft.entity.EntityLiving;
011    import net.minecraft.item.Item;
012    import net.minecraft.item.ItemStack;
013    import net.minecraft.nbt.NBTTagCompound;
014    import net.minecraft.nbt.NBTTagList;
015    import net.minecraft.util.DamageSource;
016    import net.minecraft.util.WeightedRandom;
017    
018    public class EnchantmentHelper
019    {
020        /** Is the random seed of enchantment effects. */
021        private static final Random enchantmentRand = new Random();
022    
023        /**
024         * Used to calculate the extra armor of enchantments on armors equipped on player.
025         */
026        private static final EnchantmentModifierDamage enchantmentModifierDamage = new EnchantmentModifierDamage((Empty3)null);
027    
028        /**
029         * Used to calculate the (magic) extra damage done by enchantments on current equipped item of player.
030         */
031        private static final EnchantmentModifierLiving enchantmentModifierLiving = new EnchantmentModifierLiving((Empty3)null);
032    
033        /**
034         * Returns the level of enchantment on the ItemStack passed.
035         */
036        public static int getEnchantmentLevel(int par0, ItemStack par1ItemStack)
037        {
038            if (par1ItemStack == null)
039            {
040                return 0;
041            }
042            else
043            {
044                NBTTagList var2 = par1ItemStack.getEnchantmentTagList();
045    
046                if (var2 == null)
047                {
048                    return 0;
049                }
050                else
051                {
052                    for (int var3 = 0; var3 < var2.tagCount(); ++var3)
053                    {
054                        short var4 = ((NBTTagCompound)var2.tagAt(var3)).getShort("id");
055                        short var5 = ((NBTTagCompound)var2.tagAt(var3)).getShort("lvl");
056    
057                        if (var4 == par0)
058                        {
059                            return var5;
060                        }
061                    }
062    
063                    return 0;
064                }
065            }
066        }
067    
068        /**
069         * Return the enchantments for the specified stack.
070         */
071        public static Map getEnchantments(ItemStack par0ItemStack)
072        {
073            LinkedHashMap var1 = new LinkedHashMap();
074            NBTTagList var2 = par0ItemStack.itemID == Item.field_92053_bW.itemID ? Item.field_92053_bW.func_92056_g(par0ItemStack) : par0ItemStack.getEnchantmentTagList();
075    
076            if (var2 != null)
077            {
078                for (int var3 = 0; var3 < var2.tagCount(); ++var3)
079                {
080                    short var4 = ((NBTTagCompound)var2.tagAt(var3)).getShort("id");
081                    short var5 = ((NBTTagCompound)var2.tagAt(var3)).getShort("lvl");
082                    var1.put(Integer.valueOf(var4), Integer.valueOf(var5));
083                }
084            }
085    
086            return var1;
087        }
088    
089        /**
090         * Set the enchantments for the specified stack.
091         */
092        public static void setEnchantments(Map par0Map, ItemStack par1ItemStack)
093        {
094            NBTTagList var2 = new NBTTagList();
095            Iterator var3 = par0Map.keySet().iterator();
096    
097            while (var3.hasNext())
098            {
099                int var4 = ((Integer)var3.next()).intValue();
100                NBTTagCompound var5 = new NBTTagCompound();
101                var5.setShort("id", (short)var4);
102                var5.setShort("lvl", (short)((Integer)par0Map.get(Integer.valueOf(var4))).intValue());
103                var2.appendTag(var5);
104    
105                if (par1ItemStack.itemID == Item.field_92053_bW.itemID)
106                {
107                    Item.field_92053_bW.func_92060_a(par1ItemStack, new EnchantmentData(var4, ((Integer)par0Map.get(Integer.valueOf(var4))).intValue()));
108                }
109            }
110    
111            if (var2.tagCount() > 0)
112            {
113                if (par1ItemStack.itemID != Item.field_92053_bW.itemID)
114                {
115                    par1ItemStack.setTagInfo("ench", var2);
116                }
117            }
118            else if (par1ItemStack.hasTagCompound())
119            {
120                par1ItemStack.getTagCompound().removeTag("ench");
121            }
122        }
123    
124        /**
125         * Returns the biggest level of the enchantment on the array of ItemStack passed.
126         */
127        public static int getMaxEnchantmentLevel(int par0, ItemStack[] par1ArrayOfItemStack)
128        {
129            if (par1ArrayOfItemStack == null)
130            {
131                return 0;
132            }
133            else
134            {
135                int var2 = 0;
136                ItemStack[] var3 = par1ArrayOfItemStack;
137                int var4 = par1ArrayOfItemStack.length;
138    
139                for (int var5 = 0; var5 < var4; ++var5)
140                {
141                    ItemStack var6 = var3[var5];
142                    int var7 = getEnchantmentLevel(par0, var6);
143    
144                    if (var7 > var2)
145                    {
146                        var2 = var7;
147                    }
148                }
149    
150                return var2;
151            }
152        }
153    
154        /**
155         * Executes the enchantment modifier on the ItemStack passed.
156         */
157        private static void applyEnchantmentModifier(IEnchantmentModifier par0IEnchantmentModifier, ItemStack par1ItemStack)
158        {
159            if (par1ItemStack != null)
160            {
161                NBTTagList var2 = par1ItemStack.getEnchantmentTagList();
162    
163                if (var2 != null)
164                {
165                    for (int var3 = 0; var3 < var2.tagCount(); ++var3)
166                    {
167                        short var4 = ((NBTTagCompound)var2.tagAt(var3)).getShort("id");
168                        short var5 = ((NBTTagCompound)var2.tagAt(var3)).getShort("lvl");
169    
170                        if (Enchantment.enchantmentsList[var4] != null)
171                        {
172                            par0IEnchantmentModifier.calculateModifier(Enchantment.enchantmentsList[var4], var5);
173                        }
174                    }
175                }
176            }
177        }
178    
179        /**
180         * Executes the enchantment modifier on the array of ItemStack passed.
181         */
182        private static void applyEnchantmentModifierArray(IEnchantmentModifier par0IEnchantmentModifier, ItemStack[] par1ArrayOfItemStack)
183        {
184            ItemStack[] var2 = par1ArrayOfItemStack;
185            int var3 = par1ArrayOfItemStack.length;
186    
187            for (int var4 = 0; var4 < var3; ++var4)
188            {
189                ItemStack var5 = var2[var4];
190                applyEnchantmentModifier(par0IEnchantmentModifier, var5);
191            }
192        }
193    
194        /**
195         * Returns the modifier of protection enchantments on armors equipped on player.
196         */
197        public static int getEnchantmentModifierDamage(ItemStack[] par0ArrayOfItemStack, DamageSource par1DamageSource)
198        {
199            enchantmentModifierDamage.damageModifier = 0;
200            enchantmentModifierDamage.source = par1DamageSource;
201            applyEnchantmentModifierArray(enchantmentModifierDamage, par0ArrayOfItemStack);
202    
203            if (enchantmentModifierDamage.damageModifier > 25)
204            {
205                enchantmentModifierDamage.damageModifier = 25;
206            }
207    
208            return (enchantmentModifierDamage.damageModifier + 1 >> 1) + enchantmentRand.nextInt((enchantmentModifierDamage.damageModifier >> 1) + 1);
209        }
210    
211        /**
212         * Return the (magic) extra damage of the enchantments on player equipped item.
213         */
214        public static int getEnchantmentModifierLiving(EntityLiving par0EntityLiving, EntityLiving par1EntityLiving)
215        {
216            enchantmentModifierLiving.livingModifier = 0;
217            enchantmentModifierLiving.entityLiving = par1EntityLiving;
218            applyEnchantmentModifier(enchantmentModifierLiving, par0EntityLiving.getHeldItem());
219            return enchantmentModifierLiving.livingModifier > 0 ? 1 + enchantmentRand.nextInt(enchantmentModifierLiving.livingModifier) : 0;
220        }
221    
222        /**
223         * Returns the knockback value of enchantments on equipped player item.
224         */
225        public static int getKnockbackModifier(EntityLiving par0EntityLiving, EntityLiving par1EntityLiving)
226        {
227            return getEnchantmentLevel(Enchantment.knockback.effectId, par0EntityLiving.getHeldItem());
228        }
229    
230        public static int getFireAspectModifier(EntityLiving par0EntityLiving)
231        {
232            return getEnchantmentLevel(Enchantment.fireAspect.effectId, par0EntityLiving.getHeldItem());
233        }
234    
235        /**
236         * Returns the 'Water Breathing' modifier of enchantments on player equipped armors.
237         */
238        public static int getRespiration(EntityLiving par0EntityLiving)
239        {
240            return getMaxEnchantmentLevel(Enchantment.respiration.effectId, par0EntityLiving.getLastActiveItems());
241        }
242    
243        /**
244         * Return the extra efficiency of tools based on enchantments on equipped player item.
245         */
246        public static int getEfficiencyModifier(EntityLiving par0EntityLiving)
247        {
248            return getEnchantmentLevel(Enchantment.efficiency.effectId, par0EntityLiving.getHeldItem());
249        }
250    
251        /**
252         * Returns the silk touch status of enchantments on current equipped item of player.
253         */
254        public static boolean getSilkTouchModifier(EntityLiving par0EntityLiving)
255        {
256            return getEnchantmentLevel(Enchantment.silkTouch.effectId, par0EntityLiving.getHeldItem()) > 0;
257        }
258    
259        /**
260         * Returns the fortune enchantment modifier of the current equipped item of player.
261         */
262        public static int getFortuneModifier(EntityLiving par0EntityLiving)
263        {
264            return getEnchantmentLevel(Enchantment.fortune.effectId, par0EntityLiving.getHeldItem());
265        }
266    
267        /**
268         * Returns the looting enchantment modifier of the current equipped item of player.
269         */
270        public static int getLootingModifier(EntityLiving par0EntityLiving)
271        {
272            return getEnchantmentLevel(Enchantment.looting.effectId, par0EntityLiving.getHeldItem());
273        }
274    
275        /**
276         * Returns the aqua affinity status of enchantments on current equipped item of player.
277         */
278        public static boolean getAquaAffinityModifier(EntityLiving par0EntityLiving)
279        {
280            return getMaxEnchantmentLevel(Enchantment.aquaAffinity.effectId, par0EntityLiving.getLastActiveItems()) > 0;
281        }
282    
283        public static int func_92046_i(EntityLiving par0EntityLiving)
284        {
285            return getMaxEnchantmentLevel(Enchantment.field_92039_k.effectId, par0EntityLiving.getLastActiveItems());
286        }
287    
288        public static ItemStack func_92047_a(Enchantment par0Enchantment, EntityLiving par1EntityLiving)
289        {
290            ItemStack[] var2 = par1EntityLiving.getLastActiveItems();
291            int var3 = var2.length;
292    
293            for (int var4 = 0; var4 < var3; ++var4)
294            {
295                ItemStack var5 = var2[var4];
296    
297                if (var5 != null && getEnchantmentLevel(par0Enchantment.effectId, var5) > 0)
298                {
299                    return var5;
300                }
301            }
302    
303            return null;
304        }
305    
306        /**
307         * Returns the enchantability of itemstack, it's uses a singular formula for each index (2nd parameter: 0, 1 and 2),
308         * cutting to the max enchantability power of the table (3rd parameter)
309         */
310        public static int calcItemStackEnchantability(Random par0Random, int par1, int par2, ItemStack par3ItemStack)
311        {
312            Item var4 = par3ItemStack.getItem();
313            int var5 = var4.getItemEnchantability();
314    
315            if (var5 <= 0)
316            {
317                return 0;
318            }
319            else
320            {
321                if (par2 > 15)
322                {
323                    par2 = 15;
324                }
325    
326                int var6 = par0Random.nextInt(8) + 1 + (par2 >> 1) + par0Random.nextInt(par2 + 1);
327                return par1 == 0 ? Math.max(var6 / 3, 1) : (par1 == 1 ? var6 * 2 / 3 + 1 : Math.max(var6, par2 * 2));
328            }
329        }
330    
331        /**
332         * Adds a random enchantment to the specified item. Args: random, itemStack, enchantabilityLevel
333         */
334        public static ItemStack addRandomEnchantment(Random par0Random, ItemStack par1ItemStack, int par2)
335        {
336            List var3 = buildEnchantmentList(par0Random, par1ItemStack, par2);
337            boolean var4 = par1ItemStack.itemID == Item.book.itemID;
338    
339            if (var4)
340            {
341                par1ItemStack.itemID = Item.field_92053_bW.itemID;
342            }
343    
344            if (var3 != null)
345            {
346                Iterator var5 = var3.iterator();
347    
348                while (var5.hasNext())
349                {
350                    EnchantmentData var6 = (EnchantmentData)var5.next();
351    
352                    if (var4)
353                    {
354                        Item.field_92053_bW.func_92060_a(par1ItemStack, var6);
355                    }
356                    else
357                    {
358                        par1ItemStack.addEnchantment(var6.enchantmentobj, var6.enchantmentLevel);
359                    }
360                }
361            }
362    
363            return par1ItemStack;
364        }
365    
366        /**
367         * Create a list of random EnchantmentData (enchantments) that can be added together to the ItemStack, the 3rd
368         * parameter is the total enchantability level.
369         */
370        public static List buildEnchantmentList(Random par0Random, ItemStack par1ItemStack, int par2)
371        {
372            Item var3 = par1ItemStack.getItem();
373            int var4 = var3.getItemEnchantability();
374    
375            if (var4 <= 0)
376            {
377                return null;
378            }
379            else
380            {
381                var4 /= 2;
382                var4 = 1 + par0Random.nextInt((var4 >> 1) + 1) + par0Random.nextInt((var4 >> 1) + 1);
383                int var5 = var4 + par2;
384                float var6 = (par0Random.nextFloat() + par0Random.nextFloat() - 1.0F) * 0.15F;
385                int var7 = (int)((float)var5 * (1.0F + var6) + 0.5F);
386    
387                if (var7 < 1)
388                {
389                    var7 = 1;
390                }
391    
392                ArrayList var8 = null;
393                Map var9 = mapEnchantmentData(var7, par1ItemStack);
394    
395                if (var9 != null && !var9.isEmpty())
396                {
397                    EnchantmentData var10 = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, var9.values());
398    
399                    if (var10 != null)
400                    {
401                        var8 = new ArrayList();
402                        var8.add(var10);
403    
404                        for (int var11 = var7; par0Random.nextInt(50) <= var11; var11 >>= 1)
405                        {
406                            Iterator var12 = var9.keySet().iterator();
407    
408                            while (var12.hasNext())
409                            {
410                                Integer var13 = (Integer)var12.next();
411                                boolean var14 = true;
412                                Iterator var15 = var8.iterator();
413    
414                                while (true)
415                                {
416                                    if (var15.hasNext())
417                                    {
418                                        EnchantmentData var16 = (EnchantmentData)var15.next();
419    
420                                        if (var16.enchantmentobj.canApplyTogether(Enchantment.enchantmentsList[var13.intValue()]))
421                                        {
422                                            continue;
423                                        }
424    
425                                        var14 = false;
426                                    }
427    
428                                    if (!var14)
429                                    {
430                                        var12.remove();
431                                    }
432    
433                                    break;
434                                }
435                            }
436    
437                            if (!var9.isEmpty())
438                            {
439                                EnchantmentData var17 = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, var9.values());
440                                var8.add(var17);
441                            }
442                        }
443                    }
444                }
445    
446                return var8;
447            }
448        }
449    
450        /**
451         * Creates a 'Map' of EnchantmentData (enchantments) possible to add on the ItemStack and the enchantability level
452         * passed.
453         */
454        public static Map mapEnchantmentData(int par0, ItemStack par1ItemStack)
455        {
456            Item var2 = par1ItemStack.getItem();
457            HashMap var3 = null;
458            boolean var4 = par1ItemStack.itemID == Item.book.itemID;
459            Enchantment[] var5 = Enchantment.enchantmentsList;
460            int var6 = var5.length;
461    
462            for (int var7 = 0; var7 < var6; ++var7)
463            {
464                Enchantment var8 = var5[var7];
465    
466                if (var8 != null && (var8.canApplyAtEnchantingTable(par1ItemStack) || var4))
467                {
468                    for (int var9 = var8.getMinLevel(); var9 <= var8.getMaxLevel(); ++var9)
469                    {
470                        if (par0 >= var8.getMinEnchantability(var9) && par0 <= var8.getMaxEnchantability(var9))
471                        {
472                            if (var3 == null)
473                            {
474                                var3 = new HashMap();
475                            }
476    
477                            var3.put(Integer.valueOf(var8.effectId), new EnchantmentData(var8, var9));
478                        }
479                    }
480                }
481            }
482    
483            return var3;
484        }
485    }