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.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    
106            if (var2.tagCount() > 0)
107            {
108                par1ItemStack.setTagInfo("ench", var2);
109            }
110            else if (par1ItemStack.hasTagCompound())
111            {
112                par1ItemStack.getTagCompound().removeTag("ench");
113            }
114        }
115    
116        /**
117         * Returns the biggest level of the enchantment on the array of ItemStack passed.
118         */
119        private static int getMaxEnchantmentLevel(int par0, ItemStack[] par1ArrayOfItemStack)
120        {
121            int var2 = 0;
122            ItemStack[] var3 = par1ArrayOfItemStack;
123            int var4 = par1ArrayOfItemStack.length;
124    
125            for (int var5 = 0; var5 < var4; ++var5)
126            {
127                ItemStack var6 = var3[var5];
128                int var7 = getEnchantmentLevel(par0, var6);
129    
130                if (var7 > var2)
131                {
132                    var2 = var7;
133                }
134            }
135    
136            return var2;
137        }
138    
139        /**
140         * Executes the enchantment modifier on the ItemStack passed.
141         */
142        private static void applyEnchantmentModifier(IEnchantmentModifier par0IEnchantmentModifier, ItemStack par1ItemStack)
143        {
144            if (par1ItemStack != null)
145            {
146                NBTTagList var2 = par1ItemStack.getEnchantmentTagList();
147    
148                if (var2 != null)
149                {
150                    for (int var3 = 0; var3 < var2.tagCount(); ++var3)
151                    {
152                        short var4 = ((NBTTagCompound)var2.tagAt(var3)).getShort("id");
153                        short var5 = ((NBTTagCompound)var2.tagAt(var3)).getShort("lvl");
154    
155                        if (Enchantment.enchantmentsList[var4] != null)
156                        {
157                            par0IEnchantmentModifier.calculateModifier(Enchantment.enchantmentsList[var4], var5);
158                        }
159                    }
160                }
161            }
162        }
163    
164        /**
165         * Executes the enchantment modifier on the array of ItemStack passed.
166         */
167        private static void applyEnchantmentModifierArray(IEnchantmentModifier par0IEnchantmentModifier, ItemStack[] par1ArrayOfItemStack)
168        {
169            ItemStack[] var2 = par1ArrayOfItemStack;
170            int var3 = par1ArrayOfItemStack.length;
171    
172            for (int var4 = 0; var4 < var3; ++var4)
173            {
174                ItemStack var5 = var2[var4];
175                applyEnchantmentModifier(par0IEnchantmentModifier, var5);
176            }
177        }
178    
179        /**
180         * Returns the modifier of protection enchantments on armors equipped on player.
181         */
182        public static int getEnchantmentModifierDamage(ItemStack[] par0ArrayOfItemStack, DamageSource par1DamageSource)
183        {
184            enchantmentModifierDamage.damageModifier = 0;
185            enchantmentModifierDamage.source = par1DamageSource;
186            applyEnchantmentModifierArray(enchantmentModifierDamage, par0ArrayOfItemStack);
187    
188            if (enchantmentModifierDamage.damageModifier > 25)
189            {
190                enchantmentModifierDamage.damageModifier = 25;
191            }
192    
193            return (enchantmentModifierDamage.damageModifier + 1 >> 1) + enchantmentRand.nextInt((enchantmentModifierDamage.damageModifier >> 1) + 1);
194        }
195    
196        /**
197         * Return the (magic) extra damage of the enchantments on player equipped item.
198         */
199        public static int getEnchantmentModifierLiving(EntityLiving par0EntityLiving, EntityLiving par1EntityLiving)
200        {
201            enchantmentModifierLiving.livingModifier = 0;
202            enchantmentModifierLiving.entityLiving = par1EntityLiving;
203            applyEnchantmentModifier(enchantmentModifierLiving, par0EntityLiving.getHeldItem());
204            return enchantmentModifierLiving.livingModifier > 0 ? 1 + enchantmentRand.nextInt(enchantmentModifierLiving.livingModifier) : 0;
205        }
206    
207        /**
208         * Returns the knockback value of enchantments on equipped player item.
209         */
210        public static int getKnockbackModifier(EntityLiving par0EntityLiving, EntityLiving par1EntityLiving)
211        {
212            return getEnchantmentLevel(Enchantment.knockback.effectId, par0EntityLiving.getHeldItem());
213        }
214    
215        public static int func_90036_a(EntityLiving par0EntityLiving)
216        {
217            return getEnchantmentLevel(Enchantment.fireAspect.effectId, par0EntityLiving.getHeldItem());
218        }
219    
220        /**
221         * Returns the 'Water Breathing' modifier of enchantments on player equipped armors.
222         */
223        public static int getRespiration(EntityLiving par0EntityLiving)
224        {
225            return getMaxEnchantmentLevel(Enchantment.respiration.effectId, par0EntityLiving.getLastActiveItems());
226        }
227    
228        /**
229         * Return the extra efficiency of tools based on enchantments on equipped player item.
230         */
231        public static int getEfficiencyModifier(EntityLiving par0EntityLiving)
232        {
233            return getEnchantmentLevel(Enchantment.efficiency.effectId, par0EntityLiving.getHeldItem());
234        }
235    
236        /**
237         * Returns the unbreaking enchantment modifier on current equipped item of player.
238         */
239        public static int getUnbreakingModifier(EntityLiving par0EntityLiving)
240        {
241            return getEnchantmentLevel(Enchantment.unbreaking.effectId, par0EntityLiving.getHeldItem());
242        }
243    
244        /**
245         * Returns the silk touch status of enchantments on current equipped item of player.
246         */
247        public static boolean getSilkTouchModifier(EntityLiving par0EntityLiving)
248        {
249            return getEnchantmentLevel(Enchantment.silkTouch.effectId, par0EntityLiving.getHeldItem()) > 0;
250        }
251    
252        /**
253         * Returns the fortune enchantment modifier of the current equipped item of player.
254         */
255        public static int getFortuneModifier(EntityLiving par0EntityLiving)
256        {
257            return getEnchantmentLevel(Enchantment.fortune.effectId, par0EntityLiving.getHeldItem());
258        }
259    
260        /**
261         * Returns the looting enchantment modifier of the current equipped item of player.
262         */
263        public static int getLootingModifier(EntityLiving par0EntityLiving)
264        {
265            return getEnchantmentLevel(Enchantment.looting.effectId, par0EntityLiving.getHeldItem());
266        }
267    
268        /**
269         * Returns the aqua affinity status of enchantments on current equipped item of player.
270         */
271        public static boolean getAquaAffinityModifier(EntityLiving par0EntityLiving)
272        {
273            return getMaxEnchantmentLevel(Enchantment.aquaAffinity.effectId, par0EntityLiving.getLastActiveItems()) > 0;
274        }
275    
276        /**
277         * Returns the enchantability of itemstack, it's uses a singular formula for each index (2nd parameter: 0, 1 and 2),
278         * cutting to the max enchantability power of the table (3rd parameter)
279         */
280        public static int calcItemStackEnchantability(Random par0Random, int par1, int par2, ItemStack par3ItemStack)
281        {
282            Item var4 = par3ItemStack.getItem();
283            int var5 = var4.getItemEnchantability();
284    
285            if (var5 <= 0)
286            {
287                return 0;
288            }
289            else
290            {
291                if (par2 > 15)
292                {
293                    par2 = 15;
294                }
295    
296                int var6 = par0Random.nextInt(8) + 1 + (par2 >> 1) + par0Random.nextInt(par2 + 1);
297                return par1 == 0 ? Math.max(var6 / 3, 1) : (par1 == 1 ? var6 * 2 / 3 + 1 : Math.max(var6, par2 * 2));
298            }
299        }
300    
301        /**
302         * Adds a random enchantment to the specified item. Args: random, itemStack, enchantabilityLevel
303         */
304        public static ItemStack addRandomEnchantment(Random par0Random, ItemStack par1ItemStack, int par2)
305        {
306            List var3 = buildEnchantmentList(par0Random, par1ItemStack, par2);
307    
308            if (var3 != null)
309            {
310                Iterator var4 = var3.iterator();
311    
312                while (var4.hasNext())
313                {
314                    EnchantmentData var5 = (EnchantmentData)var4.next();
315                    par1ItemStack.addEnchantment(var5.enchantmentobj, var5.enchantmentLevel);
316                }
317            }
318    
319            return par1ItemStack;
320        }
321    
322        /**
323         * Create a list of random EnchantmentData (enchantments) that can be added together to the ItemStack, the 3rd
324         * parameter is the total enchantability level.
325         */
326        public static List buildEnchantmentList(Random par0Random, ItemStack par1ItemStack, int par2)
327        {
328            Item var3 = par1ItemStack.getItem();
329            int var4 = var3.getItemEnchantability();
330    
331            if (var4 <= 0)
332            {
333                return null;
334            }
335            else
336            {
337                var4 /= 2;
338                var4 = 1 + par0Random.nextInt((var4 >> 1) + 1) + par0Random.nextInt((var4 >> 1) + 1);
339                int var5 = var4 + par2;
340                float var6 = (par0Random.nextFloat() + par0Random.nextFloat() - 1.0F) * 0.15F;
341                int var7 = (int)((float)var5 * (1.0F + var6) + 0.5F);
342    
343                if (var7 < 1)
344                {
345                    var7 = 1;
346                }
347    
348                ArrayList var8 = null;
349                Map var9 = mapEnchantmentData(var7, par1ItemStack);
350    
351                if (var9 != null && !var9.isEmpty())
352                {
353                    EnchantmentData var10 = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, var9.values());
354    
355                    if (var10 != null)
356                    {
357                        var8 = new ArrayList();
358                        var8.add(var10);
359    
360                        for (int var11 = var7; par0Random.nextInt(50) <= var11; var11 >>= 1)
361                        {
362                            Iterator var12 = var9.keySet().iterator();
363    
364                            while (var12.hasNext())
365                            {
366                                Integer var13 = (Integer)var12.next();
367                                boolean var14 = true;
368                                Iterator var15 = var8.iterator();
369    
370                                while (true)
371                                {
372                                    if (var15.hasNext())
373                                    {
374                                        EnchantmentData var16 = (EnchantmentData)var15.next();
375    
376                                        if (var16.enchantmentobj.canApplyTogether(Enchantment.enchantmentsList[var13.intValue()]))
377                                        {
378                                            continue;
379                                        }
380    
381                                        var14 = false;
382                                    }
383    
384                                    if (!var14)
385                                    {
386                                        var12.remove();
387                                    }
388    
389                                    break;
390                                }
391                            }
392    
393                            if (!var9.isEmpty())
394                            {
395                                EnchantmentData var17 = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, var9.values());
396                                var8.add(var17);
397                            }
398                        }
399                    }
400                }
401    
402                return var8;
403            }
404        }
405    
406        /**
407         * Creates a 'Map' of EnchantmentData (enchantments) possible to add on the ItemStack and the enchantability level
408         * passed.
409         */
410        public static Map mapEnchantmentData(int par0, ItemStack par1ItemStack)
411        {
412            Item var2 = par1ItemStack.getItem();
413            HashMap var3 = null;
414            Enchantment[] var4 = Enchantment.enchantmentsList;
415            int var5 = var4.length;
416    
417            for (int var6 = 0; var6 < var5; ++var6)
418            {
419                Enchantment var7 = var4[var6];
420    
421                if (var7 != null && var7.canEnchantItem(par1ItemStack))
422                {
423                    for (int var8 = var7.getMinLevel(); var8 <= var7.getMaxLevel(); ++var8)
424                    {
425                        if (par0 >= var7.getMinEnchantability(var8) && par0 <= var7.getMaxEnchantability(var8))
426                        {
427                            if (var3 == null)
428                            {
429                                var3 = new HashMap();
430                            }
431    
432                            var3.put(Integer.valueOf(var7.effectId), new EnchantmentData(var7, var8));
433                        }
434                    }
435                }
436            }
437    
438            return var3;
439        }
440    }