/*
* 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;
}
}