001package net.minecraft.enchantment;
002
003import java.util.ArrayList;
004import java.util.HashMap;
005import java.util.Iterator;
006import java.util.LinkedHashMap;
007import java.util.List;
008import java.util.Map;
009import java.util.Random;
010import net.minecraft.entity.EntityLiving;
011import net.minecraft.item.Item;
012import net.minecraft.item.ItemStack;
013import net.minecraft.nbt.NBTTagCompound;
014import net.minecraft.nbt.NBTTagList;
015import net.minecraft.util.DamageSource;
016import net.minecraft.util.WeightedRandom;
017
018public 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.enchantedBook.itemID ? Item.enchantedBook.func_92110_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.enchantedBook.itemID)
106            {
107                Item.enchantedBook.func_92115_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.enchantedBook.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_92098_i(EntityLiving par0EntityLiving)
284    {
285        return getMaxEnchantmentLevel(Enchantment.field_92091_k.effectId, par0EntityLiving.getLastActiveItems());
286    }
287
288    public static ItemStack func_92099_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.enchantedBook.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.enchantedBook.func_92115_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}