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 nbttaglist = par1ItemStack.getEnchantmentTagList();
045
046            if (nbttaglist == null)
047            {
048                return 0;
049            }
050            else
051            {
052                for (int j = 0; j < nbttaglist.tagCount(); ++j)
053                {
054                    short short1 = ((NBTTagCompound)nbttaglist.tagAt(j)).getShort("id");
055                    short short2 = ((NBTTagCompound)nbttaglist.tagAt(j)).getShort("lvl");
056
057                    if (short1 == par0)
058                    {
059                        return short2;
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 linkedhashmap = new LinkedHashMap();
074        NBTTagList nbttaglist = par0ItemStack.itemID == Item.enchantedBook.itemID ? Item.enchantedBook.func_92110_g(par0ItemStack) : par0ItemStack.getEnchantmentTagList();
075
076        if (nbttaglist != null)
077        {
078            for (int i = 0; i < nbttaglist.tagCount(); ++i)
079            {
080                short short1 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("id");
081                short short2 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("lvl");
082                linkedhashmap.put(Integer.valueOf(short1), Integer.valueOf(short2));
083            }
084        }
085
086        return linkedhashmap;
087    }
088
089    /**
090     * Set the enchantments for the specified stack.
091     */
092    public static void setEnchantments(Map par0Map, ItemStack par1ItemStack)
093    {
094        NBTTagList nbttaglist = new NBTTagList();
095        Iterator iterator = par0Map.keySet().iterator();
096
097        while (iterator.hasNext())
098        {
099            int i = ((Integer)iterator.next()).intValue();
100            NBTTagCompound nbttagcompound = new NBTTagCompound();
101            nbttagcompound.setShort("id", (short)i);
102            nbttagcompound.setShort("lvl", (short)((Integer)par0Map.get(Integer.valueOf(i))).intValue());
103            nbttaglist.appendTag(nbttagcompound);
104
105            if (par1ItemStack.itemID == Item.enchantedBook.itemID)
106            {
107                Item.enchantedBook.func_92115_a(par1ItemStack, new EnchantmentData(i, ((Integer)par0Map.get(Integer.valueOf(i))).intValue()));
108            }
109        }
110
111        if (nbttaglist.tagCount() > 0)
112        {
113            if (par1ItemStack.itemID != Item.enchantedBook.itemID)
114            {
115                par1ItemStack.setTagInfo("ench", nbttaglist);
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 j = 0;
136            ItemStack[] aitemstack1 = par1ArrayOfItemStack;
137            int k = par1ArrayOfItemStack.length;
138
139            for (int l = 0; l < k; ++l)
140            {
141                ItemStack itemstack = aitemstack1[l];
142                int i1 = getEnchantmentLevel(par0, itemstack);
143
144                if (i1 > j)
145                {
146                    j = i1;
147                }
148            }
149
150            return j;
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 nbttaglist = par1ItemStack.getEnchantmentTagList();
162
163            if (nbttaglist != null)
164            {
165                for (int i = 0; i < nbttaglist.tagCount(); ++i)
166                {
167                    short short1 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("id");
168                    short short2 = ((NBTTagCompound)nbttaglist.tagAt(i)).getShort("lvl");
169
170                    if (Enchantment.enchantmentsList[short1] != null)
171                    {
172                        par0IEnchantmentModifier.calculateModifier(Enchantment.enchantmentsList[short1], short2);
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[] aitemstack1 = par1ArrayOfItemStack;
185        int i = par1ArrayOfItemStack.length;
186
187        for (int j = 0; j < i; ++j)
188        {
189            ItemStack itemstack = aitemstack1[j];
190            applyEnchantmentModifier(par0IEnchantmentModifier, itemstack);
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[] aitemstack = par1EntityLiving.getLastActiveItems();
291        int i = aitemstack.length;
292
293        for (int j = 0; j < i; ++j)
294        {
295            ItemStack itemstack = aitemstack[j];
296
297            if (itemstack != null && getEnchantmentLevel(par0Enchantment.effectId, itemstack) > 0)
298            {
299                return itemstack;
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 item = par3ItemStack.getItem();
313        int k = item.getItemEnchantability();
314
315        if (k <= 0)
316        {
317            return 0;
318        }
319        else
320        {
321            if (par2 > 15)
322            {
323                par2 = 15;
324            }
325
326            int l = par0Random.nextInt(8) + 1 + (par2 >> 1) + par0Random.nextInt(par2 + 1);
327            return par1 == 0 ? Math.max(l / 3, 1) : (par1 == 1 ? l * 2 / 3 + 1 : Math.max(l, 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 list = buildEnchantmentList(par0Random, par1ItemStack, par2);
337        boolean flag = par1ItemStack.itemID == Item.book.itemID;
338
339        if (flag)
340        {
341            par1ItemStack.itemID = Item.enchantedBook.itemID;
342        }
343
344        if (list != null)
345        {
346            Iterator iterator = list.iterator();
347
348            while (iterator.hasNext())
349            {
350                EnchantmentData enchantmentdata = (EnchantmentData)iterator.next();
351
352                if (flag)
353                {
354                    Item.enchantedBook.func_92115_a(par1ItemStack, enchantmentdata);
355                }
356                else
357                {
358                    par1ItemStack.addEnchantment(enchantmentdata.enchantmentobj, enchantmentdata.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 item = par1ItemStack.getItem();
373        int j = item.getItemEnchantability();
374
375        if (j <= 0)
376        {
377            return null;
378        }
379        else
380        {
381            j /= 2;
382            j = 1 + par0Random.nextInt((j >> 1) + 1) + par0Random.nextInt((j >> 1) + 1);
383            int k = j + par2;
384            float f = (par0Random.nextFloat() + par0Random.nextFloat() - 1.0F) * 0.15F;
385            int l = (int)((float)k * (1.0F + f) + 0.5F);
386
387            if (l < 1)
388            {
389                l = 1;
390            }
391
392            ArrayList arraylist = null;
393            Map map = mapEnchantmentData(l, par1ItemStack);
394
395            if (map != null && !map.isEmpty())
396            {
397                EnchantmentData enchantmentdata = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, map.values());
398
399                if (enchantmentdata != null)
400                {
401                    arraylist = new ArrayList();
402                    arraylist.add(enchantmentdata);
403
404                    for (int i1 = l; par0Random.nextInt(50) <= i1; i1 >>= 1)
405                    {
406                        Iterator iterator = map.keySet().iterator();
407
408                        while (iterator.hasNext())
409                        {
410                            Integer integer = (Integer)iterator.next();
411                            boolean flag = true;
412                            Iterator iterator1 = arraylist.iterator();
413
414                            while (true)
415                            {
416                                if (iterator1.hasNext())
417                                {
418                                    EnchantmentData enchantmentdata1 = (EnchantmentData)iterator1.next();
419
420                                    if (enchantmentdata1.enchantmentobj.canApplyTogether(Enchantment.enchantmentsList[integer.intValue()]))
421                                    {
422                                        continue;
423                                    }
424
425                                    flag = false;
426                                }
427
428                                if (!flag)
429                                {
430                                    iterator.remove();
431                                }
432
433                                break;
434                            }
435                        }
436
437                        if (!map.isEmpty())
438                        {
439                            EnchantmentData enchantmentdata2 = (EnchantmentData)WeightedRandom.getRandomItem(par0Random, map.values());
440                            arraylist.add(enchantmentdata2);
441                        }
442                    }
443                }
444            }
445
446            return arraylist;
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 item = par1ItemStack.getItem();
457        HashMap hashmap = null;
458        boolean flag = par1ItemStack.itemID == Item.book.itemID;
459        Enchantment[] aenchantment = Enchantment.enchantmentsList;
460        int j = aenchantment.length;
461
462        for (int k = 0; k < j; ++k)
463        {
464            Enchantment enchantment = aenchantment[k];
465
466            if (enchantment != null && (enchantment.canApplyAtEnchantingTable(par1ItemStack) || flag))
467            {
468                for (int l = enchantment.getMinLevel(); l <= enchantment.getMaxLevel(); ++l)
469                {
470                    if (par0 >= enchantment.getMinEnchantability(l) && par0 <= enchantment.getMaxEnchantability(l))
471                    {
472                        if (hashmap == null)
473                        {
474                            hashmap = new HashMap();
475                        }
476
477                        hashmap.put(Integer.valueOf(enchantment.effectId), new EnchantmentData(enchantment, l));
478                    }
479                }
480            }
481        }
482
483        return hashmap;
484    }
485}