    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}