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