/* * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If * not, see <http://www.gnu.org/licenses/>. */ package silentium.gameserver.network.clientpackets; import gnu.trove.map.hash.TIntObjectHashMap; import silentium.gameserver.configs.PlayersConfig; import silentium.gameserver.model.L2ItemInstance; import silentium.gameserver.templates.item.L2Item; import silentium.gameserver.templates.item.L2Weapon; import silentium.gameserver.templates.item.L2WeaponType; public abstract class AbstractEnchantPacket extends L2GameClientPacket { public static final TIntObjectHashMap<EnchantScroll> _scrolls = new TIntObjectHashMap<>(); public static final class EnchantScroll { protected final boolean _isWeapon; protected final int _grade; private final boolean _isBlessed; private final boolean _isCrystal; public EnchantScroll(boolean wep, boolean bless, boolean crystal, int type) { _isWeapon = wep; _grade = type; _isBlessed = bless; _isCrystal = crystal; } /** * @param enchantItem * : The item to enchant. * @return true if support item can be used for this item */ public final boolean isValid(L2ItemInstance enchantItem) { if (enchantItem == null) return false; // checking scroll type and configured maximum enchant level switch (enchantItem.getItem().getType2()) { case L2Item.TYPE2_WEAPON: if (!_isWeapon || (PlayersConfig.ENCHANT_MAX_WEAPON > 0 && enchantItem.getEnchantLevel() >= PlayersConfig.ENCHANT_MAX_WEAPON)) return false; break; case L2Item.TYPE2_SHIELD_ARMOR: case L2Item.TYPE2_ACCESSORY: if (_isWeapon || (PlayersConfig.ENCHANT_MAX_ARMOR > 0 && enchantItem.getEnchantLevel() >= PlayersConfig.ENCHANT_MAX_ARMOR)) return false; break; default: return false; } // check for crystal type if (_grade != enchantItem.getItem().getCrystalType()) return false; return true; } /** * @return true if item is a blessed scroll. */ public final boolean isBlessed() { return _isBlessed; } /** * @return true if item is a crystal scroll. */ public final boolean isCrystal() { return _isCrystal; } /** * Regarding enchant system :<br> * <br> * <u>Weapons</u> * <ul> * <li>magic weapons has chance of 40% until +15 and 20% from +15 and higher. There is no upper limit, there is no dependance on current * enchant level.</li> * <li>non magic weapons has chance of 70% until +15 and 35% from +15 and higher. There is no upper limit, there is no dependance on * current enchant level.</li> * </ul> * <u>Armors</u> * <ul> * <li>non fullbody armors (jewelry, upper armor, lower armor, boots, gloves, helmets and shirts) has chance of 2/3 for +4, 1/3 for +5, * 1/4 for +6, ...., 1/18 +20. If you've made a +20 armor, chance to make it +21 will be equal to zero (0%).</li> * <li>full body armors has a chance of 1/1 for +4, 2/3 for +5, 1/3 for +6, ..., 1/17 for +20. If you've made a +20 armor, chance to make * it +21 will be equal to zero (0%).</li> * </ul> * * @param enchantItem * : The item to enchant. * @return the enchant chance under double format (0.7 / 0.35 / 0.44324...). */ public final double getChance(L2ItemInstance enchantItem) { if (!isValid(enchantItem)) return -1; boolean fullBody = enchantItem.getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR; if (enchantItem.getEnchantLevel() < PlayersConfig.ENCHANT_SAFE_MAX || (fullBody && enchantItem.getEnchantLevel() < PlayersConfig.ENCHANT_SAFE_MAX_FULL)) return 1; double chance = 0; // Armor formula : 0.66^(current-2), chance is lower and lower for each enchant. if (enchantItem.isArmor()) chance = Math.pow(PlayersConfig.ENCHANT_CHANCE_ARMOR, (enchantItem.getEnchantLevel() - 2)); // Weapon formula is 70% for fighter weapon, 40% for mage weapon. Special rates after +14. else if (enchantItem.isWeapon()) { if (((L2Weapon) enchantItem.getItem()).isMagical()) chance = (enchantItem.getEnchantLevel() > 14) ? PlayersConfig.ENCHANT_CHANCE_WEAPON_MAGIC_15PLUS : PlayersConfig.ENCHANT_CHANCE_WEAPON_MAGIC; else chance = (enchantItem.getEnchantLevel() > 14) ? PlayersConfig.ENCHANT_CHANCE_WEAPON_NONMAGIC_15PLUS : PlayersConfig.ENCHANT_CHANCE_WEAPON_NONMAGIC; } return chance; } } /** * Format : itemId, (isWeapon, isBlessed, isCrystal, grade)<br> * Allowed items IDs must be sorted by ascending order. */ static { // Scrolls: Enchant Weapon _scrolls.put(729, new EnchantScroll(true, false, false, L2Item.CRYSTAL_A)); _scrolls.put(947, new EnchantScroll(true, false, false, L2Item.CRYSTAL_B)); _scrolls.put(951, new EnchantScroll(true, false, false, L2Item.CRYSTAL_C)); _scrolls.put(955, new EnchantScroll(true, false, false, L2Item.CRYSTAL_D)); _scrolls.put(959, new EnchantScroll(true, false, false, L2Item.CRYSTAL_S)); // Scrolls: Enchant Armor _scrolls.put(730, new EnchantScroll(false, false, false, L2Item.CRYSTAL_A)); _scrolls.put(948, new EnchantScroll(false, false, false, L2Item.CRYSTAL_B)); _scrolls.put(952, new EnchantScroll(false, false, false, L2Item.CRYSTAL_C)); _scrolls.put(956, new EnchantScroll(false, false, false, L2Item.CRYSTAL_D)); _scrolls.put(960, new EnchantScroll(false, false, false, L2Item.CRYSTAL_S)); // Blessed Scrolls: Enchant Weapon _scrolls.put(6569, new EnchantScroll(true, true, false, L2Item.CRYSTAL_A)); _scrolls.put(6571, new EnchantScroll(true, true, false, L2Item.CRYSTAL_B)); _scrolls.put(6573, new EnchantScroll(true, true, false, L2Item.CRYSTAL_C)); _scrolls.put(6575, new EnchantScroll(true, true, false, L2Item.CRYSTAL_D)); _scrolls.put(6577, new EnchantScroll(true, true, false, L2Item.CRYSTAL_S)); // Blessed Scrolls: Enchant Armor _scrolls.put(6570, new EnchantScroll(false, true, false, L2Item.CRYSTAL_A)); _scrolls.put(6572, new EnchantScroll(false, true, false, L2Item.CRYSTAL_B)); _scrolls.put(6574, new EnchantScroll(false, true, false, L2Item.CRYSTAL_C)); _scrolls.put(6576, new EnchantScroll(false, true, false, L2Item.CRYSTAL_D)); _scrolls.put(6578, new EnchantScroll(false, true, false, L2Item.CRYSTAL_S)); // Crystal Scrolls: Enchant Weapon _scrolls.put(731, new EnchantScroll(true, false, true, L2Item.CRYSTAL_A)); _scrolls.put(949, new EnchantScroll(true, false, true, L2Item.CRYSTAL_B)); _scrolls.put(953, new EnchantScroll(true, false, true, L2Item.CRYSTAL_C)); _scrolls.put(957, new EnchantScroll(true, false, true, L2Item.CRYSTAL_D)); _scrolls.put(961, new EnchantScroll(true, false, true, L2Item.CRYSTAL_S)); // Crystal Scrolls: Enchant Armor _scrolls.put(732, new EnchantScroll(false, false, true, L2Item.CRYSTAL_A)); _scrolls.put(950, new EnchantScroll(false, false, true, L2Item.CRYSTAL_B)); _scrolls.put(954, new EnchantScroll(false, false, true, L2Item.CRYSTAL_C)); _scrolls.put(958, new EnchantScroll(false, false, true, L2Item.CRYSTAL_D)); _scrolls.put(962, new EnchantScroll(false, false, true, L2Item.CRYSTAL_S)); } /** * @param scroll * The instance of item to make checks on. * @return enchant template for scroll. */ protected static final EnchantScroll getEnchantScroll(L2ItemInstance scroll) { return _scrolls.get(scroll.getItemId()); } /** * @param item * The instance of item to make checks on. * @return true if item can be enchanted. */ protected static final boolean isEnchantable(L2ItemInstance item) { if (item.isHeroItem() || item.isShadowItem() || item.isEtcItem() || item.getItem().getItemType() == L2WeaponType.FISHINGROD) return false; // only equipped items or in inventory can be enchanted if (item.getLocation() != L2ItemInstance.ItemLocation.INVENTORY && item.getLocation() != L2ItemInstance.ItemLocation.PAPERDOLL) return false; return true; } }