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.thorns.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}