All pastes #48442 Raw Edit

TobZn - L2skill.java

public text v1 · immutable
#48442 ·published 2006-04-06 21:58 UTC
rendered paste body
/*
 * 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 2, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package net.sf.l2j.gameserver.model;

import java.lang.reflect.Constructor;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javolution.util.FastList;
import net.sf.l2j.Config;
import net.sf.l2j.gameserver.model.actor.instance.L2ArtefactInstance;
import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance;
import net.sf.l2j.gameserver.model.base.ClassId;
import net.sf.l2j.gameserver.SkillTreeTable;
import net.sf.l2j.gameserver.serverpackets.SystemMessage;
import net.sf.l2j.gameserver.skills.Condition;
import net.sf.l2j.gameserver.skills.EffectTemplate;
import net.sf.l2j.gameserver.skills.Env;
import net.sf.l2j.gameserver.skills.Func;
import net.sf.l2j.gameserver.skills.FuncTemplate;
import net.sf.l2j.gameserver.skills.L2SkillCharge;
import net.sf.l2j.gameserver.skills.L2SkillChargeDmg;
import net.sf.l2j.gameserver.skills.L2SkillDefault;
import net.sf.l2j.gameserver.skills.L2SkillDrain;
import net.sf.l2j.gameserver.skills.L2SkillNegate;
import net.sf.l2j.gameserver.skills.L2SkillSeed;
import net.sf.l2j.gameserver.skills.L2SkillSummon;
import net.sf.l2j.gameserver.skills.Stats;
import net.sf.l2j.gameserver.templates.L2WeaponType;
import net.sf.l2j.gameserver.templates.StatsSet;
import net.sf.l2j.gameserver.util.Util;
import net.sf.l2j.gameserver.instancemanager.CastleManager;
import net.sf.l2j.gameserver.model.entity.Castle;
/**
 * This class ...
 * 
 * @version $Revision: 1.3.2.8.2.22 $ $Date: 2005/04/06 16:13:42 $
 */
public abstract class L2Skill
{
	protected static Logger _log = Logger.getLogger(L2Skill.class.getName());
	
	public static final int SKILL_CUBIC_MASTERY = 143;
	public static final int SKILL_LUCKY = 194;
	public static final int SKILL_CREATE_COMMON = 1320; 
	public static final int SKILL_CREATE_DWARVEN = 172;
	public static final int SKILL_CRYSTALLIZE = 248;
	
	public static final int SKILL_FAKE_INT = 9001;
	public static final int SKILL_FAKE_WIT = 9002;
	public static final int SKILL_FAKE_MEN = 9003;
	public static final int SKILL_FAKE_CON = 9004;
	public static final int SKILL_FAKE_DEX = 9005;
	public static final int SKILL_FAKE_STR = 9006;
	
	
	
	public static enum SkillOpType { OP_PASSIVE, OP_ACTIVE, OP_TOGGLE }
	
	public static enum SkillTargetType {
		TARGET_NONE,
		TARGET_SELF,
		TARGET_ONE,
		TARGET_PARTY,
		TARGET_ALLY,
		TARGET_CLAN,
		TARGET_PET,
		TARGET_AREA,
		TARGET_AURA,
		TARGET_CORPSE,
		TARGET_UNDEAD,
		TARGET_AREA_UNDEAD,
		TARGET_MULTIFACE,
		TARGET_CORPSE_ALLY,
		TARGET_CORPSE_CLAN,
		TARGET_CORPSE_PLAYER,
		TARGET_ITEM,
		TARGET_AREA_CORPSE_MOB,
		TARGET_CORPSE_MOB,
		TARGET_UNLOCKABLE,
		TARGET_HOLY
	}
	
	
	public static enum SkillType {
		PDAM,
		MDAM,
		DOT,
		BLEED,
		POISON,
		HEAL,
		HOT,
		COMBATPOINTHEAL,
		CPHOT,
		MANAHEAL,
		MANARECHARGE, 
		MPHOT,
		AGGDAMAGE,
		BUFF,
		DEBUFF,
		STUN,
		ROOT,
		RESURRECT,
		PASSIVE,
		CONT,
		CONFUSION,
		UNLOCK,
		CHARGE                (L2SkillCharge.class),
		FEAR,
		MHOT,
		DRAIN                 (L2SkillDrain.class),
		NEGATE                (L2SkillNegate.class),
		CANCEL                (L2SkillNegate.class),
		SLEEP,
		AGGREDUCE,
		AGGREMOVE,
		AGGREDUCE_CHAR,
		CHARGEDAM             (L2SkillChargeDmg.class),
		CONFUSE_MOB_ONLY,
		DEATHLINK,
		DETECT_WEAKNESS,
		ENCHANT_ARMOR,
		ENCHANT_WEAPON,
		FEED_PET,
		HEAL_PERCENT,
		LUCK,
		MANADAM,
		MDOT,
		MUTE,
		RECALL,
		REFLECT,
		SOULSHOT,
		SPIRITSHOT,
		SPOIL,
		SWEEP,
		SUMMON                (L2SkillSummon.class),
		WEAKNESS,
		DEATHLINK_PET,
		MANA_BY_LEVEL,
		FAKE_DEATH,
		UNBLEED,
		UNPOISON,
		SIEGEFLAG,
		TAKECASTLE,
		UNDEAD_DEFENSE,
		SEED                (L2SkillSeed.class),
		PARALYZE,
		DRAIN_SOUL,
		COMMON_CRAFT, 
		DWARVEN_CRAFT,
		WEAPON_SA,
		
		// unimplemented
		NOTDONE;
		
		private final Class<? extends L2Skill> clazz;
		
		public L2Skill makeSkill(StatsSet set)
		{
			try {
				Constructor<? extends L2Skill> c =
					clazz.getConstructor(StatsSet.class);
				return c.newInstance(set);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		
		private SkillType() {
			this.clazz = L2SkillDefault.class;
		}
		private SkillType(Class<? extends L2Skill> clazz) {
			this.clazz = clazz;
		}
	}
	
	//elements
	public final static int ELEMENT_WIND = 1;
	public final static int ELEMENT_FIRE = 2;
	public final static int ELEMENT_WATER = 3;
	public final static int ELEMENT_EARTH = 4;
	public final static int ELEMENT_HOLY = 5;
	public final static int ELEMENT_DARK = 6;
	
	//save vs 
	public final static int SAVEVS_INT = 1;
	public final static int SAVEVS_WIT = 2;
	public final static int SAVEVS_MEN = 3;
	public final static int SAVEVS_CON = 4;
	public final static int SAVEVS_DEX = 5;
	public final static int SAVEVS_STR = 6;
	
	//stat effected
	public final static int STAT_PATK = 301;           // pAtk 
	public final static int STAT_PDEF = 302;           // pDef
	public final static int STAT_MATK = 303;           // mAtk
	public final static int STAT_MDEF = 304;           // mDef
	public final static int STAT_MAXHP = 305;          // maxHp
	public final static int STAT_MAXMP = 306;          // maxMp
	public final static int STAT_CURHP = 307;
	public final static int STAT_CURMP = 308;
	public final static int STAT_HPREGEN = 309;        // regHp
	public final static int STAT_MPREGEN = 310;        // regMp
	public final static int STAT_CASTINGSPEED = 311;   // sCast
	public final static int STAT_ATKSPD = 312;         // sAtk
	public final static int STAT_CRITDAM = 313;        // critDmg
	public final static int STAT_CRITRATE = 314;       // critRate
	public final static int STAT_FIRERES = 315;        // fireRes
	public final static int STAT_WINDRES = 316;        // windRes
	public final static int STAT_WATERRES = 317;       // waterRes
	public final static int STAT_EARTHRES = 318;       // earthRes
	public final static int STAT_HOLYRES = 336;        // holyRes
	public final static int STAT_DARKRES = 337;        // darkRes
	public final static int STAT_ROOTRES = 319;        // rootRes
	public final static int STAT_SLEEPRES = 320;       // sleepRes
	public final static int STAT_CONFUSIONRES = 321;   // confusRes
	public final static int STAT_BREATH = 322;         // breath
	public final static int STAT_AGGRESSION = 323;     // aggr
	public final static int STAT_BLEED = 324;          // bleed
	public final static int STAT_POISON = 325;         // poison
	public final static int STAT_STUN = 326;           // stun
	public final static int STAT_ROOT = 327;           // root
	public final static int STAT_MOVEMENT = 328;       // move
	public final static int STAT_EVASION = 329;        // evas
	public final static int STAT_ACCURACY = 330;       // accu
	public final static int STAT_COMBAT_STRENGTH = 331;
	public final static int STAT_COMBAT_WEAKNESS = 332;
	public final static int STAT_ATTACK_RANGE = 333;   // rAtk
	public final static int STAT_NOAGG = 334;          // noagg
	public final static int STAT_SHIELDDEF = 335;      // sDef
	
	//COMBAT DAMAGE MODIFIER SKILLS...DETECT WEAKNESS AND WEAKNESS/STRENGTH
	public final static int COMBAT_MOD_ANIMAL = 200;
	public final static int COMBAT_MOD_BEAST    = 201;
	public final static int COMBAT_MOD_BUG  = 202;
	public final static int COMBAT_MOD_DRAGON = 203;
	public final static int COMBAT_MOD_MONSTER= 204;
	public final static int COMBAT_MOD_PLANT    = 205;
	public final static int COMBAT_MOD_HOLY = 206;
	public final static int COMBAT_MOD_UNHOLY = 207;
	public final static int COMBAT_MOD_BOW  = 208;
	public final static int COMBAT_MOD_BLUNT    = 209;
	public final static int COMBAT_MOD_DAGGER = 210;
	public final static int COMBAT_MOD_FIST     = 211;
	public final static int COMBAT_MOD_DUAL     = 212;
	public final static int COMBAT_MOD_SWORD    = 213;
	public final static int COMBAT_MOD_POISON = 214;
	public final static int COMBAT_MOD_BLEED    = 215;
	public final static int COMBAT_MOD_FIRE = 216;
	public final static int COMBAT_MOD_WATER    = 217;
	public final static int COMBAT_MOD_EARTH    = 218;
	public final static int COMBAT_MOD_WIND = 219;
	public final static int COMBAT_MOD_ROOT = 220;
	public final static int COMBAT_MOD_STUN = 221;
	public final static int COMBAT_MOD_CONFUSION = 222;
	public final static int COMBAT_MOD_DARK = 223;
	
	//conditional values
	public final static int COND_RUNNING =   0x0001;
	public final static int COND_WALKING =   0x0002;
	public final static int COND_SIT     =   0x0004;
	public final static int COND_BEHIND  =   0x0008;
	public final static int COND_CRIT    =   0x0010;
	public final static int COND_LOWHP   =   0x0020;
	public final static int COND_ROBES   =   0x0040;
	public final static int COND_CHARGES =   0x0080;
	public final static int COND_SHIELD  =   0x0100;
	public final static int COND_GRADEA  = 0x010000;
	public final static int COND_GRADEB  = 0x020000;
	public final static int COND_GRADEC  = 0x040000;
	public final static int COND_GRADED  = 0x080000;
	public final static int COND_GRADES  = 0x100000;
	
	
	private static final Func[] _emptyFunctionSet = new Func[0];
	private static final L2Effect[] _emptyEffectSet = new L2Effect[0];
	
	// these two build the primary key
	private final int _id;
	private final int _level;
	
	/** Identifier for a skill that client can't display */
	private int _displayId;
	
	// not needed, just for easier debug
	private final String _name;
	private final SkillOpType _operateType;
	private final boolean _magic;
	private final int _mpConsume;
	private final int _hpConsume;
	private final int _itemConsume;
	private final int _itemConsumeId;
	private final int _castRange;
	private final int _effectRange;
	
	// all times in milliseconds 
	private final int _skillTime;
	private final int _skillInterruptTime;
	private final int _hitTime;
	private final int _reuseDelay;
	private final int _buffDuration;
	
	private final SkillTargetType _targetType;
	private final double _power;
	private final int _magicLevel;
	private final int _levelDepend;
	
	// Effecting area of the skill, in radius.
	// The radius center varies according to the _targetType:
	// "caster" if targetType = AURA/PARTY/CLAN or "target" if targetType = AREA
	private final int _skillRadius;
	
	private final SkillType _skillType;
	private final SkillType _effectType;
	private final int _effectPower;
	
	private final boolean _ispotion;
	private final int _element;
	private final int _savevs;
	
	private final Stats _stat;
	
	private final int _condition;
	private final int _conditionValue;
	private final boolean _overhit;
	private final int _weaponsAllowed;
	private final int _armorsAllowed;
	
	private final int _addCrossLearn; // -1 disable, otherwice SP price for others classes, default 1000
	private final float _mulCrossLearn; // multiplay for others classes, default 2
	private final float _mulCrossLearnRace; // multiplay for others races, default 2
	private final float _mulCrossLearnProf; // multiplay for fighter/mage missmatch, default 3
	private final List<ClassId> _canLearn; // which classes can learn
	private final List<Integer> _teachers; // which NPC teaches
	
	
	protected Condition _preCondition;
	protected FuncTemplate[] _funcTemplates;
	protected EffectTemplate[] _effectTemplates;
	
	
	protected L2Skill(StatsSet set)
	{
		_id           = set.getInteger("skill_id");
		_level        = set.getInteger("level");
		
		if ((_id >= 2001 && _id <= 2003) || _id == 2005 ||
				(_id >= 2010 && _id <= 2012) || 
				(_id >= 2032 && _id <= 2035) ||
				_id == 2037 || _id == 2038 ||
				_id == 2169 || _id == 4082)
			_ispotion = true;
		else
			_ispotion = false;
		
		
		_displayId    = set.getInteger("displayId", _id);
		_name         = set.getString("name");
		_operateType  = set.getEnum("operateType", SkillOpType.class);
		_magic        = set.getBool  ("isMagic", false);
		_mpConsume    = set.getInteger("mpConsume", 0);
		_hpConsume    = set.getInteger("hpConsume", 0);
		_itemConsume  = set.getInteger("itemConsumeCount", 0);
		_itemConsumeId= set.getInteger("itemConsumeId", 0);
		
		_castRange    = set.getInteger("castRange", 0);
		_effectRange  = set.getInteger("castRange", _castRange + 200);
		_skillTime    = set.getInteger("skillTime", 0);
		_skillInterruptTime = set.getInteger("skillTime", _skillTime/2);
		_hitTime      = set.getInteger("hitTime", 0);
		_reuseDelay   = set.getInteger("reuseDelay", 0);
		_buffDuration = set.getInteger("buffDuration", 0);
		
		_skillRadius  = set.getInteger("skillRadius", 80);
		
		_targetType   = set.getEnum("target", SkillTargetType.class);
		_power        = set.getFloat("power", 0.f);
		_magicLevel   = set.getInteger("magicLvl", SkillTreeTable.getMinSkillLevel(_id, _level));
		_levelDepend  = set.getInteger("lvlDepend", 0);
		_stat         = set.getEnum  ("stat", Stats.class, null);
		
		_skillType    = set.getEnum("skillType", SkillType.class);
		_effectType   = set.getEnum("effectType", SkillType.class, null);
		_effectPower  = set.getInteger("effectPower", 0);
		
		_element      = set.getInteger("element", 0);
		_savevs       = set.getInteger("save", 0);
		
		
		_condition       = set.getInteger("condition", 0);
		_conditionValue  = set.getInteger("conditionValue", 0);
		_overhit         = set.getBool  ("overHit", false);
		_weaponsAllowed  = set.getInteger("weaponsAllowed", 0);
		_armorsAllowed   = set.getInteger("armorsAllowed", 0);
		
		_addCrossLearn       = set.getInteger("addCrossLearn", 1000);
		_mulCrossLearn       = set.getFloat ("mulCrossLearn", 2.f);
		_mulCrossLearnRace   = set.getFloat ("mulCrossLearnRace", 2.f);
		_mulCrossLearnProf   = set.getFloat ("mulCrossLearnProf", 3.f);
		
		
		
		String canLearn = set.getString("canLearn", null);
		if (canLearn == null) {
			_canLearn = null;
		} else {
			_canLearn = new FastList<ClassId>();
			StringTokenizer st = new StringTokenizer(canLearn, " \r\n\t,;");
			while (st.hasMoreTokens()) {
				String cls = st.nextToken();
				try {
					_canLearn.add(ClassId.valueOf(cls));
				} catch (Throwable t) {
					_log.log(Level.SEVERE, "Bad class "+cls+" to learn skill", t);
				}
			}
		}
		
		String teachers = set.getString("teachers", null);
		if (teachers == null) {
			_teachers = null;
		} else {
			_teachers = new FastList<Integer>();
			StringTokenizer st = new StringTokenizer(teachers, " \r\n\t,;");
			while (st.hasMoreTokens()) {
				String npcid = st.nextToken();
				try {
					_teachers.add(Integer.parseInt(npcid));
				} catch (Throwable t) {
					_log.log(Level.SEVERE, "Bad teacher id "+npcid+" to teach skill", t);
				}
			}
		}
	}
	
	public abstract void useSkill(L2Character caster, L2Object[] targets);
	
	
	public final boolean isPotion()
	{
		return _ispotion;
	}
	
	public final int getArmorsAllowed()
	{
		return _armorsAllowed;
	}
	
	public final int getConditionValue()
	{
		return _conditionValue;
	}
	
	public final SkillType getSkillType() 
	{
		return _skillType;
	}
	
	public final int getSavevs() {
		return _savevs;
	}
	
	public final int getElement() 
	{
		return _element;
	}
	
	public final SkillTargetType getTargetType() 
	{
		return _targetType;
	}
	
	public final int getCondition() {
		return _condition;
	}
	
	public final boolean isOverhit() 
	{
		return _overhit;
	}
	
	
	/**
	 * Return the power of the skill.<BR><BR>
	 */
	public final double getPower(L2Character activeChar)
	{
		if (_skillType == SkillType.DEATHLINK && activeChar != null)
			return _power * Math.pow(1.7165 - activeChar.getCurrentHp()/activeChar.getMaxHp(), 2) * 0.577;
		else return _power;
	}
	
	public final double getPower()
	{
		return _power;
	}
	
	public final int getMagicLevel()
	{
		return _magicLevel;
	}
	
	public final int getLevelDepend()
	{
		return _levelDepend;
	}
	
	/**
	 * Return the additional effect power or base probability.<BR><BR>
	 */
	public final int getEffectPower()
	{
		return _effectPower;
	}
	
	/**
	 * Return the additional effect skill type (ex : STUN, PARALYZE,...).<BR><BR>
	 */
	public final SkillType getEffectType() 
	{
		return _effectType;
	}
	
	/**
	 * @return Returns the buffDuration.
	 */
	public final int getBuffDuration()
	{
		return _buffDuration;
	}
	
	/**
	 * @return Returns the castRange.
	 */
	public final int getCastRange()
	{
		return _castRange;
	}
	
	/**
	 * @return Returns the effectRange.
	 */
	public final int getEffectRange()
	{
		return _effectRange;
	}
	
	/**
	 * @return Returns the hitTime.
	 */
	public final int getHitTime()
	{
		return Math.round(Config.ALT_GAME_SKILL_HIT_RATE * _hitTime);
	}
	
	/**
	 * @return Returns the hpConsume.
	 */
	public final int getHpConsume()
	{
		return _hpConsume;
	}
	
	/**
	 * @return Returns the id.
	 */
	public final int getId()
	{
		return _id;
	}
	
	public int getDisplayId()
	{
		return _displayId;
	}
	
	public void setDisplayId(int id)
	{
		_displayId = id;
	}
	
	/**
	 * Return the skill type (ex : BLEED, SLEEP, WATER...).<BR><BR>
	 */
	public final Stats getStat()
	{
		return _stat;
	}
	
	/**
	 * @return Returns the itemConsume.
	 */
	public final int getItemConsume()
	{
		return _itemConsume;
	}
	
	/**
	 * @return Returns the itemConsumeId.
	 */
	public final int getItemConsumeId()
	{
		return _itemConsumeId;
	}
	
	/**
	 * @return Returns the level.
	 */
	public final int getLevel()
	{
		return _level;
	}
	
	/**
	 * @return Returns the magic.
	 */
	public final boolean isMagic()
	{
		return _magic;
	}
	
	/**
	 * @return Returns the mpConsume.
	 */
	public final int getMpConsume()
	{
		return _mpConsume;
	}
	
	/**
	 * @return Returns the name.
	 */
	public final String getName()
	{
		return _name;
	}
	
	/**
	 * @return Returns the reuseDelay.
	 */
	public final int getReuseDelay()
	{
		return _reuseDelay;
	}
	
	public final int getSkillTime()
	{
		return _skillTime;
	}
	
	public final int getSkillInterruptTime()
	{
		return _skillInterruptTime;
	}
	
	public final int getSkillRadius()
	{
		return _skillRadius;
	}
	
	public final boolean isActive()
	{
		return _operateType == SkillOpType.OP_ACTIVE;
	}
	
	public final boolean isPassive()
	{
		return _operateType == SkillOpType.OP_PASSIVE;
	}
	
	public final boolean isToggle()
	{
		return _operateType == SkillOpType.OP_TOGGLE;
	}
	
	
	public final int getWeaponsAllowed()
	{
		return _weaponsAllowed;
	}
	
	public final int getCrossLearnAdd() {
		return _addCrossLearn;
	}
	public final float getCrossLearnMul() {
		return _mulCrossLearn;
	}
	public final float getCrossLearnRace() {
		return _mulCrossLearnRace;
	}
	public final float getCrossLearnProf() {
		return _mulCrossLearnProf;
	}
	public final boolean getCanLearn(ClassId cls) {
		return _canLearn == null || _canLearn.contains(cls);
	}
	public final boolean canTeachBy(int npcId) {
		return _teachers == null || _teachers.contains(npcId);
	}
	
	public final boolean isPvpSkill() {
		switch (_skillType)
		{
			case DOT:
			case BLEED:
			case CONFUSION:
			case POISON:
			case DEBUFF:
			case STUN:
			case ROOT:
			case FEAR:
			case SLEEP:
			case MDOT:
			case MUTE:
			case WEAKNESS:
			case PARALYZE:
			case CANCEL:
				return true;
			default:
				return false;
		}
	}
	
	public final boolean isOffensive() {
		switch (_skillType)
		{
			case PDAM:
			case MDAM:
			case DOT:
			case BLEED:
			case POISON:
			case AGGDAMAGE:
			case DEBUFF:
			case STUN:
			case ROOT:
			case CONFUSION:
			case UNLOCK:
			case FEAR:
			case DRAIN:
			case SLEEP:
			case CHARGEDAM:
			case CONFUSE_MOB_ONLY:
			case DEATHLINK:
			case DETECT_WEAKNESS:
			case MANADAM:
			case MDOT:
			case MUTE:
			case SOULSHOT:
			case SPIRITSHOT:
			case SPOIL:
			case WEAKNESS:
			case MANA_BY_LEVEL:
			case SWEEP:
			case PARALYZE:
			case DRAIN_SOUL:
			case AGGREDUCE:
			case CANCEL:
				return true;
			default:
				return false;
		}
	}
	
//	int weapons[] = {L2Weapon.WEAPON_TYPE_ETC, L2Weapon.WEAPON_TYPE_BOW,
//	L2Weapon.WEAPON_TYPE_POLE, L2Weapon.WEAPON_TYPE_DUALFIST,
//	L2Weapon.WEAPON_TYPE_DUAL, L2Weapon.WEAPON_TYPE_BLUNT,
//	L2Weapon.WEAPON_TYPE_SWORD, L2Weapon.WEAPON_TYPE_DAGGER};
	
	public final boolean getWeaponDependancy(L2Character activeChar)
	{
		int weaponsAllowed = getWeaponsAllowed();
		//check to see if skill has a weapon dependency.
		if(weaponsAllowed == 0)
			return true;
		if(activeChar.getActiveWeaponItem() != null)
		{
			L2WeaponType playerWeapon;
			playerWeapon = activeChar.getActiveWeaponItem().getItemType();
			int mask = playerWeapon.mask(); 
			if((mask & weaponsAllowed) != 0)
				return true;
			// can be on the secondary weapon
			if (activeChar.getSecondaryWeaponItem() != null)
			{
				playerWeapon = activeChar.getSecondaryWeaponItem().getItemType();
				mask = playerWeapon.mask();
				if((mask & weaponsAllowed) != 0)
					return true;
			}
		}
		StringBuffer skillmsg = new StringBuffer();
		skillmsg.append(getName());
		skillmsg.append(" can only be used with weapons of type ");
		for(L2WeaponType wt : L2WeaponType.values())
		{
			if((wt.mask() & weaponsAllowed) != 0)
				skillmsg.append(wt).append('/');
		}
		skillmsg.setCharAt(skillmsg.length()-1, '.');
		SystemMessage message = new SystemMessage(SystemMessage.S1_S2);
		message.addString(skillmsg.toString()); 
		activeChar.sendPacket(message); 
		
		return false;
	}
	
	public boolean checkCondition(L2Character activeChar)
	{
		if((getCondition() & L2Skill.COND_BEHIND) != 0)
		{
			if (!activeChar.isBehindTarget())
				return false;
		}
		
		if((getCondition() & L2Skill.COND_SHIELD) != 0)
		{
			/*
			 L2Armor armorPiece;
			 L2ItemInstance dummy;
			 dummy = activeChar.getInventory().getPaperdollItem(Inventory.PAPERDOLL_RHAND);
			 armorPiece = (L2Armor) dummy.getItem();
			 */
			//TODO add checks for shield here.
			
		}
		
		if (_preCondition == null)
			return true;
		Env env = new Env();
		env._player = activeChar;
		env._skill = this;
		if (!_preCondition.test(env))
		{
			String msg = _preCondition.getMessage();
			if (msg != null)
			{
				SystemMessage sm = new SystemMessage(SystemMessage.S1_S2);
				sm.addString(msg);
				activeChar.sendPacket(sm);
			}
			return false;
		}
		return true;
	}
	
	
	/**
	 * Return all targets of the skill in a table in function a the skill type.<BR><BR>
	 * 
	 * <B><U> Values of skill type</U> :</B><BR><BR>
	 * <li>ONE : The skill can only be used on the L2PcInstance targeted, or on the caster if it's a L2PcInstance and no L2PcInstance targeted</li>
	 * <li>SELF</li>
	 * <li>HOLY, UNDEAD</li>
	 * <li>PET</li>
	 * <li>AURA, AURA_CLOSE</li>
	 * <li>AREA</li>
	 * <li>MULTIFACE</li>
	 * <li>PARTY, CLAN</li>
	 * <li>CORPSE_PLAYER, CORPSE_MOB, CORPSE_CLAN</li>
	 * <li>UNLOCKABLE</li>
	 * <li>ITEM</li><BR><BR>
	 * 
	 * @param activeChar The L2Character who use the skill
	 * 
	 */
	public final L2Object[] getTargetList(L2Character activeChar)
	{
		List<L2Character> targetList = new FastList<L2Character>();
		
		// Get the target type of the skill 
		// (ex : ONE, SELF, HOLY, PET, AURA, AURA_CLOSE, AREA, MULTIFACE, PARTY, CLAN, CORPSE_PLAYER, CORPSE_MOB, CORPSE_CLAN, UNLOCKABLE, ITEM, UNDEAD)
		SkillTargetType targetType = getTargetType();
		
		// Init to null the target of the skill
		L2Character target = null;
		
		// Get the L2Objcet targeted by the user of the skill at this moment
		L2Object objTarget = activeChar.getTarget();
		
		// Get the type of the skill
		// (ex : PDAM, MDAM, DOT, BLEED, POISON, HEAL, HOT, MANAHEAL, MANARECHARGE, AGGDAMAGE, BUFF, DEBUFF, STUN, ROOT, RESURRECT, PASSIVE...)
		SkillType skillType = getSkillType();
		
		// If the L2Object targeted is a L2Character, it becomes the L2Character target
		if(objTarget instanceof L2Character)
		{
			target = (L2Character) objTarget;
		}
		
		
		switch(targetType)
		{
			// The skill can only be used on the L2Character targeted, or on the caster itself
			case TARGET_ONE:
			{
				/**
				 * Commented out by [NeXuS], since you CAN heal/buff/etc a NPC instance.
				 * But if you do so, you should just flag, like doing it on a flagged player or a player with karma.
				 */
				/* Skills BUFF, HEAL, MANAHEAL, HOT, REFLECT, NEGATE
				 if(skillType == SkillType.BUFF || skillType == SkillType.HEAL || skillType == SkillType.MANAHEAL || skillType == SkillType.HOT || skillType == SkillType.REFLECT || skillType == SkillType.NEGATE)
				 {
				 // If target is npc or null then just focus on self for heal and buff type skills
				  L2PcInstance tgt = null;
				  
				  // If the target is a L2PcInstance, it becomes the target of the skill
				   // else if the activechar is a L2PcInstance, it becomes the target of the skill
				    if(target instanceof L2PcInstance)
				    tgt = (L2PcInstance)target;
				    else if (activeChar instanceof L2PcInstance)
				    tgt = (L2PcInstance)activeChar;
				    
				    // If a target is found, return it in a table else send a system message TARGET_IS_INCORRECT
				     if (tgt != null && !tgt.isAlikeDead())
				     return new L2Character[]{tgt};
				     
				     activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
				     return null;
				     }
				     else
				     {*/
				// Check for null target or any other invalid target
				if(target == null || target.isDead() || 
						(target == activeChar && !(
								skillType == SkillType.BUFF
								|| skillType == SkillType.HEAL
								|| skillType == SkillType.HEAL_PERCENT
								|| skillType == SkillType.HOT
								|| skillType == SkillType.MANAHEAL
								|| skillType == SkillType.MANARECHARGE
								|| skillType == SkillType.NEGATE
								|| skillType == SkillType.CANCEL
								|| skillType == SkillType.REFLECT
								|| skillType == SkillType.UNBLEED
								|| skillType == SkillType.UNPOISON
								|| skillType == SkillType.SEED
						)))
				{
					activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
					return null;
				}
				
				// If a target is found, return it in a table else send a system message TARGET_IS_INCORRECT
				return new L2Character[]{target};
				//}
			}
			case TARGET_SELF:
			{     
				return new L2Character[]{activeChar};
			}
			case TARGET_HOLY:
			{
				if (activeChar instanceof L2PcInstance)
				{
					if (activeChar.getTarget() instanceof L2ArtefactInstance)
						return new L2Character[]{(L2ArtefactInstance)activeChar.getTarget()};
				}
				
				return null;
			}
			case TARGET_PET:
			{
				target = activeChar.getPet();
				if (target != null && !target.isDead())
					return new L2Character[]{target}; 
				
				return null;
			}
			case TARGET_AURA:
			{
				int radius = getSkillRadius();
				
				for (L2Object obj : activeChar.getKnownList().getKnownObjects())
				{   
					if (obj instanceof L2Attackable || obj instanceof L2PcInstance)
					{
//						Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met
						if (activeChar instanceof L2PcInstance && !((L2PcInstance)activeChar).checkPvpSkill(obj, this))
							continue;
						
						// check if both attacker and target are L2PcInstances and if they are in same party or clan
						if (   (activeChar instanceof L2PcInstance && obj instanceof L2PcInstance) && 
								(   ((L2PcInstance)activeChar).getClanId() == ((L2PcInstance)obj).getClanId() || 
										(  (((L2PcInstance)activeChar).getParty() != null && ((L2PcInstance)obj).getParty() != null) &&
												((L2PcInstance)activeChar).getParty().getPartyLeaderOID() == ((L2PcInstance)obj).getParty().getPartyLeaderOID() )))
							continue;
						
						if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue;
						
						targetList.add((L2Character)obj);
					}
				}
				return targetList.toArray(new L2Character[targetList.size()]);
			}
			case TARGET_AREA:
			{
				if (
						(                                               // )
								!(target instanceof L2Attackable) &&    //   Target is not L2Attackable and
								!(target instanceof L2PcInstance)       //   Target is not L2PcInstance
						) ||                                            // ) or
						(                                               // (
								this.getCastRange() >= 0 &&             //   Range skill and
								(                                       //   (
										target == null ||               //     No target or
										target == activeChar ||         //     Target is self or
										target.isAlikeDead()            //     Target is dead/fake death
								)                                       //   )
						)                                               // )
				)
				{
					activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
					return null;
				}
				
				L2Character cha;
				if (this.getCastRange() >= 0)
				{
					cha = target;
					targetList.add((L2Character)cha); // Add target to target list
				}
				else
					cha = activeChar;
				
				boolean skillUserIsL2PcInstance = (activeChar instanceof L2PcInstance);
				boolean effectOriginIsL2PcInstance = (cha instanceof L2PcInstance);
				boolean objIsL2PcInstance;
				int radius = getSkillRadius();
				for (L2Object obj : cha.getKnownList().getKnownObjects())
				{
					if (!(obj instanceof L2Character)) continue;
					
					target = (L2Character) obj;
					if(!target.isAlikeDead() && target != activeChar)   // If target is not dead/fake death and not self
					{
						if (!Util.checkIfInRange(radius, cha, obj, true)) // Go to next obj if obj isn't in range
							continue;
						
						objIsL2PcInstance = (obj instanceof L2PcInstance);
						
						if (skillUserIsL2PcInstance)                // Skill attacker is L2PcInstance, hit everything except
						{
							if (
									(                               // (
											objIsL2PcInstance &&    //   obj is L2PcInstance and
											(                       //   (
													(               //     In same clan
															(((L2PcInstance)activeChar).getClan() != null && ((L2PcInstance)obj).getClan() != null) &&
															((L2PcInstance)activeChar).getClan().getClanId() == ((L2PcInstance)obj).getClan().getClanId()
													) ||            //     or in same party
													(
															(((L2PcInstance)activeChar).getParty() != null && ((L2PcInstance)obj).getParty() != null) &&
															((L2PcInstance)activeChar).getParty().getPartyLeaderOID() == ((L2PcInstance)obj).getParty().getPartyLeaderOID()
													) ||            //     or not pvp with 
													!((L2PcInstance)activeChar).checkPvpSkill(obj, this)
											)                       //   )
									)
							)
								continue;
						}
						else                                                // Skill user is not L2PcInstance
						{
							if (effectOriginIsL2PcInstance &&               // If effect starts at L2PcInstance and
									!objIsL2PcInstance)                     // Object is not L2PcInstance
								continue;
						}
						
						targetList.add((L2Character)obj);   // Add obj to target lists
					}
				}
				
				if (targetList.size() == 0)
					return null;
				
				return targetList.toArray(new L2Character[targetList.size()]);
			}
			case TARGET_MULTIFACE:
			{
				if((!(target instanceof L2Attackable)
						&& !(target instanceof L2PcInstance)))
				{
					activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
					return null;
				}
				
				targetList.add(target);
				
				int radius = getSkillRadius();
				
				for (L2Object obj : activeChar.getKnownList().getKnownObjects())
				{
					if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue;
					
					if(obj instanceof L2Attackable && obj != target)
						targetList.add((L2Character)obj);
					
					if(targetList.size() == 0)
					{
						activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_CANT_FOUND));
						return null;
					}
				}
				return targetList.toArray(new L2Character[targetList.size()]);
				//TODO multiface targets all around right now.  need it to just get targets
				//the character is facing.
			}
			case TARGET_PARTY:
			{
				if(activeChar instanceof L2PcInstance)
				{
					L2PcInstance player = (L2PcInstance) activeChar;
					L2Party party = player.getParty();
					targetList.add(player);
					if(party != null)
					{
						// Get all visible objects in a spheric area near the L2Character
						// Get a list of Party Members
						List<L2PcInstance> partyList = party.getPartyMembers();
						
						int radius = getSkillRadius();
						
						for(L2PcInstance partyMember : partyList)
						{
							if (partyMember == null)
								continue;
							if(!partyMember.isDead())
							{
								if (!Util.checkIfInRange(radius, activeChar, partyMember, true))
									continue;
								
								targetList.add(partyMember);
								//    break;
							}
						}
					}
				}
				return targetList.toArray(new L2Character[targetList.size()]);
			}
			case TARGET_CORPSE_ALLY:
			case TARGET_ALLY:
			{
				if(activeChar instanceof L2PcInstance)
				{
					int radius = getSkillRadius();
					L2PcInstance player = (L2PcInstance) activeChar;
					L2Clan clan = player.getClan();
					if (targetType != SkillTargetType.TARGET_CORPSE_ALLY)
						targetList.add(player);
					if(clan != null)
					{
						// Get all visible objects in a spheric area near the L2Character
						// Get Clan Members
						for ( L2Object newTarget : activeChar.getKnownList().getKnownObjects())
						{
							if (newTarget == null || !(newTarget instanceof L2PcInstance))
								continue;
							if ((((L2PcInstance)newTarget).getAllyId() == 0 || ((L2PcInstance)newTarget).getAllyId() != player.getAllyId()) 
									&& (((L2PcInstance)newTarget).getClan() == null || ((L2PcInstance)newTarget).getClanId() != player.getClanId()))
								continue;
							if (targetType == SkillTargetType.TARGET_CORPSE_ALLY && !((L2PcInstance)newTarget).isDead())
								continue;
							
							if (!Util.checkIfInRange(radius, activeChar, newTarget, true)) continue;
							
							// Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met
							if (!player.checkPvpSkill(newTarget, this))
								continue;
							
							targetList.add((L2Character)newTarget);
						}
					}
				}
				return targetList.toArray(new L2Character[targetList.size()]);
			}
			case TARGET_CORPSE_CLAN:
			case TARGET_CLAN:
			{
				if(activeChar instanceof L2PcInstance)
				{
					int radius = getSkillRadius();
					L2PcInstance player = (L2PcInstance) activeChar;
					L2Clan clan = player.getClan();
					if (targetType != SkillTargetType.TARGET_CORPSE_CLAN)
						targetList.add(player);
					if(clan != null)
					{
						// Get all visible objects in a spheric area near the L2Character
						// Get Clan Members
						for (L2ClanMember member : clan.getMembers())
						{
							L2PcInstance newTarget = member.getPlayerInstance();
							if (newTarget == null)
								continue;
							if (targetType == SkillTargetType.TARGET_CORPSE_CLAN && !((L2PcInstance)newTarget).isDead())
								continue;
							
							if (!Util.checkIfInRange(radius, activeChar, newTarget, true)) continue;
							
							// Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met
							if (!player.checkPvpSkill(newTarget, this))
								continue;
							
							targetList.add((L2Character)newTarget);
						}
					}
				}
				return targetList.toArray(new L2Character[targetList.size()]);
			}
			case TARGET_CORPSE_PLAYER:
			{
				if(target != null && target.isDead())
				{
					L2PcInstance player = null;
					if (activeChar instanceof L2PcInstance) player = (L2PcInstance)activeChar;
					L2PcInstance targetPlayer = null;
					if (target instanceof L2PcInstance) targetPlayer = (L2PcInstance)target;
					L2PetInstance targetPet = null;
					if (target instanceof L2PetInstance) targetPet = (L2PetInstance)target;
					if(player != null && (targetPlayer != null || targetPet != null))
					{
						boolean condGood = true;
						
						if (
								getId() == 1016     // Greater Resurrection
						)
						{
							// check target is not in a active siege zone
							Castle castle = null;
							if (targetPlayer != null)
								castle = CastleManager.getInstance().getCastle(targetPlayer.getX(),targetPlayer.getY());
							else if (targetPet != null)
								castle = CastleManager.getInstance().getCastle(targetPet.getX(),targetPet.getY());
							
							if (castle != null)
								if (castle.getSiege().getIsInProgress())
								{
									condGood = false;
									player.sendMessage("You Cannot Resurect in a Sieged Zone");
								}
							// Can only res party memeber or own pet
							if (targetPet != null)
							{
								if (targetPet.getOwner() != player)
								{
									condGood = false;
									player.sendMessage("You are not the owner of this pet");
								}
							}
							else
							{
								if (player.getParty() == null || targetPlayer.getParty() == null || player.getParty().getPartyLeaderOID() != targetPlayer.getParty().getPartyLeaderOID())
									condGood = false;
							}
						}
						
						if (condGood)
						{
							targetList.add(target);
							return targetList.toArray(new L2Object[targetList.size()]);
						}
					}
				}
				activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
				return null;
			}
			case TARGET_CORPSE_MOB:
			{
				if(!(target instanceof L2Attackable) || !target.isDead())
				{
					activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
					return null;
				}
				targetList.add(target);
				return targetList.toArray(new L2Object[targetList.size()]);
			}
			case TARGET_UNLOCKABLE:
			{
				if(!(target instanceof L2DoorInstance))
				{
					activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
					return null;
				}
				
				targetList.add(target);
				return targetList.toArray(new L2Object[targetList.size()]);
			}       
			case TARGET_ITEM:
			{
				SystemMessage sm = new SystemMessage(SystemMessage.S1_S2);
				sm.addString("Target type of skill is not currently handled");
				activeChar.sendPacket(sm);
				return null;
			}
			case TARGET_UNDEAD:
			{
				if (target instanceof L2NpcInstance)
				{
					if(!((L2NpcInstance)target).isUndead())
					{
						activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT));
						return null;
					}
					
					targetList.add(target);
					return targetList.toArray(new L2Object[targetList.size()]);
				}
			}
			case TARGET_AREA_UNDEAD:
			{
				L2Character cha;
				if (this.getCastRange() >= 0)
				{
					cha = target;
					targetList.add((L2Character)cha); // Add target to target list
				}
				else
					cha = activeChar;
				
				int radius = getSkillRadius();
				if (cha != null && cha.getKnownList() != null)
					for (L2Object obj : cha.getKnownList().getKnownObjects())
					{
						if (!(obj instanceof L2NpcInstance)) continue;
						target = (L2NpcInstance) obj;
						if(!target.isAlikeDead())   // If target is not dead/fake death and not self
						{
							if (!target.isUndead())
								continue;
							if (!Util.checkIfInRange(radius, cha, obj, true)) // Go to next obj if obj isn't in range
								continue;

							targetList.add((L2Character)obj);   // Add obj to target lists
					}
				}
				
				if (targetList.size() == 0)
					return null;
				return targetList.toArray(new L2Character[targetList.size()]);
			}        
			default:
			{
				SystemMessage sm = new SystemMessage(614);
				sm.addString("Target type of skill is not currently handled");
				activeChar.sendPacket(sm);
				return null;
			}
		}//end switch
	}
	
	public final Func[] getStatFuncs(@SuppressWarnings("unused") L2Effect effect, L2Character player)
	{
		if (
				!(player instanceof L2PcInstance) &&
				!(player instanceof L2Attackable) &&
				!(player instanceof L2Summon)
		)
			return _emptyFunctionSet;
		if (_funcTemplates == null)
			return _emptyFunctionSet;
		List<Func> funcs = new FastList<Func>();
		for (FuncTemplate t : _funcTemplates) {
			Env env = new Env();
			env._player = player;
			env._skill = this;
			Func f = t.getFunc(env, this); // skill is owner
			if (f != null)
				funcs.add(f);
		}
		if (funcs.size() == 0)
			return _emptyFunctionSet;
		return funcs.toArray(new Func[funcs.size()]);
	}
	
	
	public final L2Effect[] getEffects(L2Character effector, L2Character effected)
	{
		if (isPassive())
			return _emptyEffectSet;
		
		if (_effectTemplates == null)
			return _emptyEffectSet;
		
		if (effected instanceof L2PcInstance){
			L2PcInstance targetplayer = (L2PcInstance)effected;
			//No effect on invulnerable players unless they cast it themselves.
			if ((effector != effected) && targetplayer.isInvul()){
				return _emptyEffectSet;
			}
		}
		
		List<L2Effect> effects = new FastList<L2Effect>();
		
		for (EffectTemplate et : _effectTemplates) 
		{
			Env env = new Env();
			env._player = effector;
			env._target = effected;
			env._skill = this;
			L2Effect e = et.getEffect(env);
			if (e != null)
				effects.add(e);
		}
		
		if (effects.size() == 0)
			return _emptyEffectSet;
		
		return effects.toArray(new L2Effect[effects.size()]);
	}
	
	public final void attach(FuncTemplate f)
	{
		if (_funcTemplates == null)
		{
			_funcTemplates = new FuncTemplate[]{f};
		}
		else
		{
			int len = _funcTemplates.length;
			FuncTemplate[] tmp = new FuncTemplate[len+1];
			System.arraycopy(_funcTemplates, 0, tmp, 0, len);
			tmp[len] = f;
			_funcTemplates = tmp;
		}
	}
	
	public final void attach(EffectTemplate effect)
	{
		if (_effectTemplates == null)
		{
			_effectTemplates = new EffectTemplate[]{effect};
		}
		else
		{
			int len = _effectTemplates.length;
			EffectTemplate[] tmp = new EffectTemplate[len+1];
			System.arraycopy(_effectTemplates, 0, tmp, 0, len);
			tmp[len] = effect;
			_effectTemplates = tmp;
		}
	}
	
	public final void attach(Condition c)
	{
		_preCondition = c;
	}
	
	public String toString()
	{
		return ""+_name+"[id="+_id+",lvl="+_level+"]";
	}
}