458 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			458 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2004-2015 L2J Server
 | |
|  * 
 | |
|  * This file is part of L2J Server.
 | |
|  * 
 | |
|  * L2J Server 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.
 | |
|  * 
 | |
|  * L2J Server 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 com.l2jserver.gameserver.model.items;
 | |
| 
 | |
| import java.util.Objects;
 | |
| 
 | |
| import com.l2jserver.gameserver.model.StatsSet;
 | |
| import com.l2jserver.gameserver.model.actor.L2Character;
 | |
| import com.l2jserver.gameserver.model.actor.L2Npc;
 | |
| import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
 | |
| import com.l2jserver.gameserver.model.conditions.Condition;
 | |
| import com.l2jserver.gameserver.model.conditions.ConditionGameChance;
 | |
| import com.l2jserver.gameserver.model.events.EventDispatcher;
 | |
| import com.l2jserver.gameserver.model.events.impl.character.npc.OnNpcSkillSee;
 | |
| import com.l2jserver.gameserver.model.holders.SkillHolder;
 | |
| import com.l2jserver.gameserver.model.items.type.WeaponType;
 | |
| import com.l2jserver.gameserver.model.skills.Skill;
 | |
| import com.l2jserver.gameserver.model.stats.Formulas;
 | |
| import com.l2jserver.gameserver.network.SystemMessageId;
 | |
| import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
 | |
| import com.l2jserver.gameserver.util.Util;
 | |
| import com.l2jserver.util.StringUtil;
 | |
| 
 | |
| /**
 | |
|  * This class is dedicated to the management of weapons.
 | |
|  */
 | |
| public final class L2Weapon extends L2Item
 | |
| {
 | |
| 	private final WeaponType _type;
 | |
| 	private final boolean _isMagicWeapon;
 | |
| 	private final int _rndDam;
 | |
| 	private final int _soulShotCount;
 | |
| 	private final int _spiritShotCount;
 | |
| 	private final int _mpConsume;
 | |
| 	private final int _baseAttackRange;
 | |
| 	private final int _baseAttackAngle;
 | |
| 	/**
 | |
| 	 * Skill that activates when item is enchanted +4 (for duals).
 | |
| 	 */
 | |
| 	private SkillHolder _enchant4Skill = null;
 | |
| 	private final int _changeWeaponId;
 | |
| 	
 | |
| 	// Attached skills for Special Abilities
 | |
| 	private SkillHolder _skillsOnMagic;
 | |
| 	private Condition _skillsOnMagicCondition = null;
 | |
| 	private SkillHolder _skillsOnCrit;
 | |
| 	private Condition _skillsOnCritCondition = null;
 | |
| 	
 | |
| 	private final int _reducedSoulshot;
 | |
| 	private final int _reducedSoulshotChance;
 | |
| 	
 | |
| 	private final int _reducedMpConsume;
 | |
| 	private final int _reducedMpConsumeChance;
 | |
| 	
 | |
| 	private final boolean _isForceEquip;
 | |
| 	private final boolean _isAttackWeapon;
 | |
| 	private final boolean _useWeaponSkillsOnly;
 | |
| 	
 | |
| 	/**
 | |
| 	 * Constructor for Weapon.
 | |
| 	 * @param set the StatsSet designating the set of couples (key,value) characterizing the weapon.
 | |
| 	 */
 | |
| 	public L2Weapon(StatsSet set)
 | |
| 	{
 | |
| 		super(set);
 | |
| 		_type = WeaponType.valueOf(set.getString("weapon_type", "none").toUpperCase());
 | |
| 		_type1 = L2Item.TYPE1_WEAPON_RING_EARRING_NECKLACE;
 | |
| 		_type2 = L2Item.TYPE2_WEAPON;
 | |
| 		_isMagicWeapon = set.getBoolean("is_magic_weapon", false);
 | |
| 		_soulShotCount = set.getInt("soulshots", 0);
 | |
| 		_spiritShotCount = set.getInt("spiritshots", 0);
 | |
| 		_rndDam = set.getInt("random_damage", 0);
 | |
| 		_mpConsume = set.getInt("mp_consume", 0);
 | |
| 		_baseAttackRange = set.getInt("attack_range", 40);
 | |
| 		String[] damgeRange = set.getString("damage_range", "").split(";"); // 0?;0?;fan sector;base attack angle
 | |
| 		if ((damgeRange.length > 1) && Util.isDigit(damgeRange[3]))
 | |
| 		{
 | |
| 			_baseAttackAngle = Integer.parseInt(damgeRange[3]);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			_baseAttackAngle = 120;
 | |
| 		}
 | |
| 		
 | |
| 		String[] reduced_soulshots = set.getString("reduced_soulshot", "").split(",");
 | |
| 		_reducedSoulshotChance = (reduced_soulshots.length == 2) ? Integer.parseInt(reduced_soulshots[0]) : 0;
 | |
| 		_reducedSoulshot = (reduced_soulshots.length == 2) ? Integer.parseInt(reduced_soulshots[1]) : 0;
 | |
| 		
 | |
| 		String[] reduced_mpconsume = set.getString("reduced_mp_consume", "").split(",");
 | |
| 		_reducedMpConsumeChance = (reduced_mpconsume.length == 2) ? Integer.parseInt(reduced_mpconsume[0]) : 0;
 | |
| 		_reducedMpConsume = (reduced_mpconsume.length == 2) ? Integer.parseInt(reduced_mpconsume[1]) : 0;
 | |
| 		
 | |
| 		String skill = set.getString("enchant4_skill", null);
 | |
| 		if (skill != null)
 | |
| 		{
 | |
| 			String[] info = skill.split("-");
 | |
| 			
 | |
| 			if ((info != null) && (info.length == 2))
 | |
| 			{
 | |
| 				int id = 0;
 | |
| 				int level = 0;
 | |
| 				try
 | |
| 				{
 | |
| 					id = Integer.parseInt(info[0]);
 | |
| 					level = Integer.parseInt(info[1]);
 | |
| 				}
 | |
| 				catch (Exception nfe)
 | |
| 				{
 | |
| 					// Incorrect syntax, dont add new skill
 | |
| 					_log.info(StringUtil.concat("> Couldnt parse ", skill, " in weapon enchant skills! item ", toString()));
 | |
| 				}
 | |
| 				if ((id > 0) && (level > 0))
 | |
| 				{
 | |
| 					_enchant4Skill = new SkillHolder(id, level);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		skill = set.getString("onmagic_skill", null);
 | |
| 		if (skill != null)
 | |
| 		{
 | |
| 			String[] info = skill.split("-");
 | |
| 			final int chance = set.getInt("onmagic_chance", 100);
 | |
| 			if ((info != null) && (info.length == 2))
 | |
| 			{
 | |
| 				int id = 0;
 | |
| 				int level = 0;
 | |
| 				try
 | |
| 				{
 | |
| 					id = Integer.parseInt(info[0]);
 | |
| 					level = Integer.parseInt(info[1]);
 | |
| 				}
 | |
| 				catch (Exception nfe)
 | |
| 				{
 | |
| 					// Incorrect syntax, don't add new skill
 | |
| 					_log.info(StringUtil.concat("> Couldnt parse ", skill, " in weapon onmagic skills! item ", toString()));
 | |
| 				}
 | |
| 				if ((id > 0) && (level > 0) && (chance > 0))
 | |
| 				{
 | |
| 					_skillsOnMagic = new SkillHolder(id, level);
 | |
| 					_skillsOnMagicCondition = new ConditionGameChance(chance);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		skill = set.getString("oncrit_skill", null);
 | |
| 		if (skill != null)
 | |
| 		{
 | |
| 			String[] info = skill.split("-");
 | |
| 			final int chance = set.getInt("oncrit_chance", 100);
 | |
| 			if ((info != null) && (info.length == 2))
 | |
| 			{
 | |
| 				int id = 0;
 | |
| 				int level = 0;
 | |
| 				try
 | |
| 				{
 | |
| 					id = Integer.parseInt(info[0]);
 | |
| 					level = Integer.parseInt(info[1]);
 | |
| 				}
 | |
| 				catch (Exception nfe)
 | |
| 				{
 | |
| 					// Incorrect syntax, don't add new skill
 | |
| 					_log.info(StringUtil.concat("> Couldnt parse ", skill, " in weapon oncrit skills! item ", toString()));
 | |
| 				}
 | |
| 				if ((id > 0) && (level > 0) && (chance > 0))
 | |
| 				{
 | |
| 					_skillsOnCrit = new SkillHolder(id, level);
 | |
| 					_skillsOnCritCondition = new ConditionGameChance(chance);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		_changeWeaponId = set.getInt("change_weaponId", 0);
 | |
| 		_isForceEquip = set.getBoolean("isForceEquip", false);
 | |
| 		_isAttackWeapon = set.getBoolean("isAttackWeapon", true);
 | |
| 		_useWeaponSkillsOnly = set.getBoolean("useWeaponSkillsOnly", false);
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the type of Weapon
 | |
| 	 */
 | |
| 	@Override
 | |
| 	public WeaponType getItemType()
 | |
| 	{
 | |
| 		return _type;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the ID of the Etc item after applying the mask.
 | |
| 	 */
 | |
| 	@Override
 | |
| 	public int getItemMask()
 | |
| 	{
 | |
| 		return getItemType().mask();
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return {@code true} if the weapon is magic, {@code false} otherwise.
 | |
| 	 */
 | |
| 	@Override
 | |
| 	public boolean isMagicWeapon()
 | |
| 	{
 | |
| 		return _isMagicWeapon;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the quantity of SoulShot used.
 | |
| 	 */
 | |
| 	public int getSoulShotCount()
 | |
| 	{
 | |
| 		return _soulShotCount;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the quantity of SpiritShot used.
 | |
| 	 */
 | |
| 	public int getSpiritShotCount()
 | |
| 	{
 | |
| 		return _spiritShotCount;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the reduced quantity of SoultShot used.
 | |
| 	 */
 | |
| 	public int getReducedSoulShot()
 | |
| 	{
 | |
| 		return _reducedSoulshot;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the chance to use Reduced SoultShot.
 | |
| 	 */
 | |
| 	public int getReducedSoulShotChance()
 | |
| 	{
 | |
| 		return _reducedSoulshotChance;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the random damage inflicted by the weapon.
 | |
| 	 */
 | |
| 	public int getRandomDamage()
 | |
| 	{
 | |
| 		return _rndDam;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the MP consumption with the weapon.
 | |
| 	 */
 | |
| 	public int getMpConsume()
 | |
| 	{
 | |
| 		return _mpConsume;
 | |
| 	}
 | |
| 	
 | |
| 	public int getBaseAttackRange()
 | |
| 	{
 | |
| 		return _baseAttackRange;
 | |
| 	}
 | |
| 	
 | |
| 	public int getBaseAttackAngle()
 | |
| 	{
 | |
| 		return _baseAttackAngle;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the reduced MP consumption with the weapon.
 | |
| 	 */
 | |
| 	public int getReducedMpConsume()
 | |
| 	{
 | |
| 		return _reducedMpConsume;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the chance to use getReducedMpConsume()
 | |
| 	 */
 | |
| 	public int getReducedMpConsumeChance()
 | |
| 	{
 | |
| 		return _reducedMpConsumeChance;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the skill that player get when has equipped weapon +4 or more (for duals SA).
 | |
| 	 */
 | |
| 	@Override
 | |
| 	public Skill getEnchant4Skill()
 | |
| 	{
 | |
| 		if (_enchant4Skill == null)
 | |
| 		{
 | |
| 			return null;
 | |
| 		}
 | |
| 		return _enchant4Skill.getSkill();
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return the Id in which weapon this weapon can be changed.
 | |
| 	 */
 | |
| 	public int getChangeWeaponId()
 | |
| 	{
 | |
| 		return _changeWeaponId;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return {@code true} if the weapon is force equip, {@code false} otherwise.
 | |
| 	 */
 | |
| 	public boolean isForceEquip()
 | |
| 	{
 | |
| 		return _isForceEquip;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return {@code true} if the weapon is attack weapon, {@code false} otherwise.
 | |
| 	 */
 | |
| 	public boolean isAttackWeapon()
 | |
| 	{
 | |
| 		return _isAttackWeapon;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @return {@code true} if the weapon is skills only, {@code false} otherwise.
 | |
| 	 */
 | |
| 	public boolean useWeaponSkillsOnly()
 | |
| 	{
 | |
| 		return _useWeaponSkillsOnly;
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @param caster the L2Character pointing out the caster
 | |
| 	 * @param target the L2Character pointing out the target
 | |
| 	 */
 | |
| 	public void castOnCriticalSkill(L2Character caster, L2Character target)
 | |
| 	{
 | |
| 		if ((_skillsOnCrit == null))
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		final Skill onCritSkill = _skillsOnCrit.getSkill();
 | |
| 		if (_skillsOnCritCondition != null)
 | |
| 		{
 | |
| 			if (!_skillsOnCritCondition.test(caster, target, onCritSkill))
 | |
| 			{
 | |
| 				// Chance not met
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if (!onCritSkill.checkCondition(caster, target, false))
 | |
| 		{
 | |
| 			// Skill condition not met
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		onCritSkill.activateSkill(caster, target);
 | |
| 	}
 | |
| 	
 | |
| 	/**
 | |
| 	 * @param caster the L2Character pointing out the caster
 | |
| 	 * @param target the L2Character pointing out the target
 | |
| 	 * @param trigger the L2Skill pointing out the skill triggering this action
 | |
| 	 */
 | |
| 	public void castOnMagicSkill(L2Character caster, L2Character target, Skill trigger)
 | |
| 	{
 | |
| 		if (_skillsOnMagic == null)
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		final Skill onMagicSkill = _skillsOnMagic.getSkill();
 | |
| 		
 | |
| 		// Trigger only if both are good or bad magic.
 | |
| 		if (trigger.isBad() != onMagicSkill.isBad())
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		// No Trigger if not Magic Skill
 | |
| 		if (!trigger.isMagic() && !onMagicSkill.isMagic())
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		if (trigger.isToggle())
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		if (caster.getAI().getCastTarget() != target)
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		if (_skillsOnMagicCondition != null)
 | |
| 		{
 | |
| 			if (!_skillsOnMagicCondition.test(caster, target, onMagicSkill))
 | |
| 			{
 | |
| 				// Chance not met
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if (!onMagicSkill.checkCondition(caster, target, false))
 | |
| 		{
 | |
| 			// Skill condition not met
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		if (onMagicSkill.isBad() && (Formulas.calcShldUse(caster, target, onMagicSkill) == Formulas.SHIELD_DEFENSE_PERFECT_BLOCK))
 | |
| 		{
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		// Launch the magic skill and calculate its effects
 | |
| 		// Get the skill handler corresponding to the skill type
 | |
| 		onMagicSkill.activateSkill(caster, target);
 | |
| 		
 | |
| 		// notify quests of a skill use
 | |
| 		if (caster instanceof L2PcInstance)
 | |
| 		{
 | |
| 			L2Character[] targets =
 | |
| 			{
 | |
| 				target
 | |
| 			};
 | |
| 			
 | |
| 			//@formatter:off
 | |
| 			caster.getKnownList().getKnownObjects().values().stream()
 | |
| 				.filter(Objects::nonNull)
 | |
| 				.filter(npc -> npc.isNpc())
 | |
| 				.filter(npc -> Util.checkIfInRange(1000, npc, caster, false))
 | |
| 				.forEach(npc -> 
 | |
| 				{
 | |
| 					EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee((L2Npc) npc, caster.getActingPlayer(), onMagicSkill, targets, false), npc);
 | |
| 				});
 | |
| 			//@formatter:on
 | |
| 		}
 | |
| 		if (caster.isPlayer())
 | |
| 		{
 | |
| 			SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ACTIVATED);
 | |
| 			sm.addSkillName(onMagicSkill);
 | |
| 			caster.sendPacket(sm);
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
