/* * 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 . */ package net.sf.l2j.gameserver.model; import java.util.Collection; import java.util.List; import java.util.logging.Logger; import javolution.util.FastList; import net.sf.l2j.Config; import net.sf.l2j.gameserver.GeoData; import net.sf.l2j.gameserver.datatables.HeroSkillTable; import net.sf.l2j.gameserver.datatables.SkillTreeTable; import net.sf.l2j.gameserver.model.actor.L2Attackable; import net.sf.l2j.gameserver.model.actor.L2Character; import net.sf.l2j.gameserver.model.actor.L2Npc; import net.sf.l2j.gameserver.model.actor.L2Playable; import net.sf.l2j.gameserver.model.actor.L2Summon; import net.sf.l2j.gameserver.model.actor.instance.L2ArtefactInstance; import net.sf.l2j.gameserver.model.actor.instance.L2ChestInstance; import net.sf.l2j.gameserver.model.actor.instance.L2CubicInstance; import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance; import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance; import net.sf.l2j.gameserver.model.actor.instance.L2SiegeFlagInstance; import net.sf.l2j.gameserver.model.actor.instance.L2SummonInstance; import net.sf.l2j.gameserver.network.SystemMessageId; import net.sf.l2j.gameserver.network.serverpackets.SystemMessage; import net.sf.l2j.gameserver.skills.Env; import net.sf.l2j.gameserver.skills.Formulas; import net.sf.l2j.gameserver.skills.Stats; import net.sf.l2j.gameserver.skills.conditions.Condition; import net.sf.l2j.gameserver.skills.funcs.Func; import net.sf.l2j.gameserver.skills.funcs.FuncTemplate; import net.sf.l2j.gameserver.taskmanager.DecayTaskManager; import net.sf.l2j.gameserver.templates.StatsSet; import net.sf.l2j.gameserver.templates.effects.EffectTemplate; import net.sf.l2j.gameserver.templates.skills.L2SkillType; import net.sf.l2j.gameserver.util.Util; /** * This class... * * @version $Revision: 1.3.2.8.2.22 $ $Date: 2005/04/06 16:13:42 $ */ public abstract class L2Skill implements IChanceSkillTrigger { protected static final Logger _log = Logger.getLogger(L2Skill.class.getName()); private static final L2Object[] _emptyTargetList = new L2Object[0]; 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_DIVINE_INSPIRATION = 1405; public static final int SKILL_CLAN_LUCK = 390; public static enum SkillOpType { OP_PASSIVE, OP_ACTIVE, OP_TOGGLE } /** Target types of skills : SELF, PARTY, CLAN, PET... */ public static enum SkillTargetType { TARGET_NONE, TARGET_SELF, TARGET_ONE, TARGET_PARTY, TARGET_ALLY, TARGET_CLAN, TARGET_PET, TARGET_SUMMON, TARGET_AREA, TARGET_FRONT_AREA, TARGET_BEHIND_AREA, TARGET_AURA, TARGET_FRONT_AURA, TARGET_BEHIND_AURA, TARGET_CORPSE, TARGET_UNDEAD, TARGET_AREA_UNDEAD, TARGET_MULTIFACE, TARGET_CORPSE_ALLY, TARGET_CORPSE_CLAN, TARGET_CORPSE_PLAYER, TARGET_CORPSE_PET, TARGET_AREA_CORPSE_MOB, TARGET_CORPSE_MOB, TARGET_UNLOCKABLE, TARGET_HOLY, TARGET_FLAGPOLE, TARGET_PARTY_MEMBER, TARGET_PARTY_OTHER, TARGET_ENEMY_SUMMON, TARGET_OWNER_PET, TARGET_GROUND } //elements public final static int ELEMENT_FIRE = 1; public final static int ELEMENT_WATER = 2; public final static int ELEMENT_WIND = 3; public final static int ELEMENT_EARTH = 4; public final static int ELEMENT_HOLY = 5; public final static int ELEMENT_DARK = 6; //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; 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 boolean _staticReuse; private final boolean _staticHitTime; private final int _mpConsume; private final int _mpInitialConsume; private final int _hpConsume; private final int _cpConsume; private final int _targetConsume; private final int _targetConsumeId; private final int _itemConsume; private final int _itemConsumeId; // item consume count over time private final int _itemConsumeOT; // item consume id over time private final int _itemConsumeIdOT; // how many times to consume an item private final int _itemConsumeSteps; // for summon spells: // a) What is the total lifetime of summons (in millisecs) private final int _summonTotalLifeTime; // b) how much lifetime is lost per second of idleness (non-fighting) private final int _summonTimeLostIdle; // c) how much time is lost per second of activity (fighting) private final int _summonTimeLostActive; private final boolean _isCubic; // cubic AI private final int _activationtime; private final int _activationchance; // item consume time in milliseconds private final int _itemConsumeTime; private final int _castRange; private final int _effectRange; // Abnormal levels for skills and their canceling, e.g. poison vs negate private final int _abnormalLvl; // e.g. poison or bleed lvl 2 // Note: see also _effectAbnormalLvl private final int _negateLvl; // abnormalLvl is negated with negateLvl private final int[] _negateId; // cancels the effect of skill ID private final L2SkillType[] _negateStats; // lists the effect types that are canceled private final int _maxNegatedEffects; // maximum number of effects to negate // kill by damage over time private final boolean _killByDOT; private final int _refId; // all times in milliseconds private final int _hitTime; //private final int _skillInterruptTime; private final int _coolTime; private final int _reuseDelay; private final int _buffDuration; // for item skills delay on equip private final int _equipDelay; /** Target type of the skill : SELF, PARTY, CLAN, PET... */ private final SkillTargetType _targetType; private int _feed; // base success chance private final double _power; private final int _magicLevel; private final int _levelDepend; private final boolean _ignoreResists; private final boolean _isNeutral; // 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 L2SkillType _skillType; private final L2SkillType _effectType; // additional effect has a type private final int _effectAbnormalLvl; // abnormal level for the additional effect type, e.g. poison lvl 1 private final int _effectId; private final int _effectLvl; // normal effect level private final boolean _ispotion; private final int _element; 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 _minPledgeClass; private final int[] _teleportCoords; private final String _recallType; private final boolean _isOffensive; private final int _requiredCharges; private final int _maxCharges; private final int _numCharges; private final int _triggeredId; private final int _triggeredLevel; private final String _chanceType; private final int _soulMaxConsume; private final int _soulConsume; private final int _numSouls; private final int _expNeeded; private final int _critChance; private final int _transformId; private final int _transformDuration; private final int _afterEffectId; private final int _afterEffectLvl; private final boolean _isHeroSkill; // If true the skill is a Hero Skill private final int _baseCritRate; // percent of success for skill critical hit (especially for PDAM & BLOW - they're not affected by rCrit values or buffs). Default loads -1 for all other skills but 0 to PDAM & BLOW private final int _lethalEffect1; // percent of success for lethal 1st effect (hit cp to 1 or if mob hp to 50%) (only for PDAM skills) private final int _lethalEffect2; // percent of success for lethal 2nd effect (hit cp,hp to 1 or if mob hp to 1) (only for PDAM skills) private final boolean _directHpDmg; // If true then dmg is being make directly private final boolean _isDance; // If true then casting more dances will cost more MP private final int _nextDanceCost; private final float _sSBoost; //If true skill will have SoulShot boost (power*2) private final int _aggroPoints; protected Condition _preCondition; protected Condition _itemPreCondition; protected FuncTemplate[] _funcTemplates; protected EffectTemplate[] _effectTemplates; protected EffectTemplate[] _effectTemplatesSelf; protected ChanceCondition _chanceCondition = null; // Flying support private final String _flyType; private final int _flyRadius; private final float _flyCourse; private final boolean _isDebuff; private boolean _isAdvancedFlag; private String _attribute; private int _afroId; private int _learnSkillId; private int _learnSkillLvl; private boolean _useShield; private boolean _isSuicideAttack; protected L2Skill(StatsSet set) { _id = set.getInteger("skill_id"); _level = set.getInteger("level"); _refId = set.getInteger("referenceId", set.getInteger("itemConsumeId", 0)); _afroId = set.getInteger("afroId",0); _displayId = set.getInteger("displayId", _id); _name = set.getString("name"); _operateType = set.getEnum("operateType", SkillOpType.class); _magic = set.getBool("isMagic", false); _staticReuse = set.getBool("staticReuse", false); _staticHitTime = set.getBool("staticHitTime", false); _ispotion = set.getBool("isPotion", false); _mpConsume = set.getInteger("mpConsume", 0); _mpInitialConsume = set.getInteger("mpInitialConsume", 0); _hpConsume = set.getInteger("hpConsume", 0); _cpConsume = set.getInteger("cpConsume", 0); _targetConsume = set.getInteger("targetConsumeCount", 0); _targetConsumeId = set.getInteger("targetConsumeId", 0); _itemConsume = set.getInteger("itemConsumeCount", 0); _itemConsumeId = set.getInteger("itemConsumeId", 0); _itemConsumeOT = set.getInteger("itemConsumeCountOT", 0); _itemConsumeIdOT = set.getInteger("itemConsumeIdOT", 0); _itemConsumeTime = set.getInteger("itemConsumeTime", 0); _itemConsumeSteps = set.getInteger("itemConsumeSteps", 0); _summonTotalLifeTime= set.getInteger("summonTotalLifeTime", 1200000); // 20 minutes default _summonTimeLostIdle= set.getInteger("summonTimeLostIdle", 0); _summonTimeLostActive= set.getInteger("summonTimeLostActive", 0); _afterEffectId = set.getInteger("afterEffectId", 0); _afterEffectLvl = set.getInteger("afterEffectLvl", 1); _isCubic = set.getBool("isCubic", false); String coords = set.getString("teleCoords", null); if (coords != null) { String[] valuesSplit = coords.split(","); _teleportCoords = new int[valuesSplit.length]; for (int i = 0; i < valuesSplit.length;i++) _teleportCoords[i] = Integer.valueOf(valuesSplit[i]); } else _teleportCoords = null; _recallType = set.getString("recallType", ""); _isAdvancedFlag = set.getBool("isAdvancedFlag", false); _activationtime= set.getInteger("activationtime", 8); _activationchance= set.getInteger("activationchance", 30); _castRange = set.getInteger("castRange", -1); _effectRange = set.getInteger("effectRange", -1); _abnormalLvl = set.getInteger("abnormalLvl", -1); _effectAbnormalLvl = set.getInteger("effectAbnormalLvl", -1); // support for a separate effect abnormal lvl, e.g. poison inside a different skill _negateLvl = set.getInteger("negateLvl", -1); _learnSkillId = set.getInteger("learnSkillId",0); _learnSkillLvl = set.getInteger("learnSkillLvl",1); _attribute = set.getString("attribute",""); String str = set.getString("negateStats", ""); if (str == "") _negateStats = new L2SkillType[0]; else { String[] stats = str.split(" "); L2SkillType[] array = new L2SkillType[stats.length]; for (int i = 0; i < stats.length; i++) { L2SkillType type = null; try { type = Enum.valueOf(L2SkillType.class, stats[i]); } catch (Exception e) { throw new IllegalArgumentException("SkillId: "+_id+"Enum value of type "+L2SkillType.class.getName()+"required, but found: "+stats[i]); } array[i] = type; } _negateStats = array; } String negateId = set.getString("negateId", null); if (negateId != null) { String[] valuesSplit = negateId.split(","); _negateId = new int[valuesSplit.length]; for (int i = 0; i < valuesSplit.length;i++) { _negateId[i] = Integer.valueOf(valuesSplit[i]); } } else _negateId = new int[0]; _maxNegatedEffects = set.getInteger("maxNegated", 0); _killByDOT = set.getBool("killByDOT", false); _isNeutral = set.getBool("neutral",false); _hitTime = set.getInteger("hitTime", 0); _coolTime = set.getInteger("coolTime", 0); _isDebuff = set.getBool("isDebuff", false); _feed = set.getInteger("feed", 0); if (Config.ENABLE_MODIFY_SKILL_REUSE && Config.SKILL_REUSE_LIST.containsKey(_id)) { if ( Config.DEBUG ) _log.info("*** Skill " + _name + " (" + _level + ") changed reuse from " + set.getInteger("reuseDelay", 0) + " to " + Config.SKILL_REUSE_LIST.get(_id) + " seconds."); _reuseDelay = Config.SKILL_REUSE_LIST.get(_id); } else { _reuseDelay = set.getInteger("reuseDelay", 0); } _buffDuration = set.getInteger("buffDuration", 0); _equipDelay = set.getInteger("equipDelay", 0); _skillRadius = set.getInteger("skillRadius", 80); _targetType = set.getEnum("target", SkillTargetType.class); _power = set.getFloat("power", 0.f); _magicLevel = set.getInteger("magicLvl", SkillTreeTable.getInstance().getMinSkillLevel(_id, _level)); _levelDepend = set.getInteger("lvlDepend", 0); _ignoreResists = set.getBool("ignoreResists", false); _stat = set.getEnum("stat", Stats.class, null); _useShield = set.getBool("useShield", false); _skillType = set.getEnum("skillType", L2SkillType.class); _effectType = set.getEnum("effectType", L2SkillType.class, null); _effectId = set.getInteger("effectId", 0); _effectLvl = set.getInteger("effectLevel", 0); _element = set.getInteger("element", 0); _condition = set.getInteger("condition", 0); _conditionValue = set.getInteger("conditionValue", 0); _overhit = set.getBool("overHit", false); _isSuicideAttack = set.getBool("isSuicideAttack", false); _weaponsAllowed = set.getInteger("weaponsAllowed", 0); _armorsAllowed = set.getInteger("armorsAllowed", 0); _minPledgeClass = set.getInteger("minPledgeClass", 0); _isOffensive = set.getBool("offensive", isSkillTypeOffensive()); _maxCharges = set.getInteger("maxCharges", 0); _numCharges = set.getInteger("numCharges", 0); _requiredCharges = set.getInteger("requiredCharges", 0); _triggeredId = set.getInteger("triggeredId", 0); _triggeredLevel = set.getInteger("triggeredLevel", 0); _chanceType = set.getString("chanceType", ""); if (_chanceType != "" && !_chanceType.isEmpty()) _chanceCondition = ChanceCondition.parse(set); _numSouls = set.getInteger("num_souls", 0); _soulMaxConsume = set.getInteger("soulMaxConsumeCount", 0); _soulConsume = set.getInteger("soulConsumeCount", 0); _expNeeded = set.getInteger("expNeeded", 0); _critChance = set.getInteger("critChance", 0); _transformId = set.getInteger("transformId", 0); _transformDuration = set.getInteger("transformDuration", 0); _isHeroSkill = HeroSkillTable.isHeroSkill(_id); _baseCritRate = set.getInteger("baseCritRate", (_skillType == L2SkillType.PDAM || _skillType == L2SkillType.BLOW) ? 0 : -1); _lethalEffect1 = set.getInteger("lethal1",0); _lethalEffect2 = set.getInteger("lethal2",0); _directHpDmg = set.getBool("dmgDirectlyToHp",false); _isDance = set.getBool("isDance",false); _nextDanceCost = set.getInteger("nextDanceCost", 0); _sSBoost = set.getFloat("SSBoost", 0.f); _aggroPoints = set.getInteger("aggroPoints", 0); _flyType = set.getString("flyType", null); _flyRadius = set.getInteger("flyRadius", 200); _flyCourse = set.getFloat("flyCourse", 0); } 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 L2SkillType getSkillType() { return _skillType; } public final int getElement() { return _element; } /** * Return the target type of the skill : SELF, PARTY, CLAN, PET...

* */ public final SkillTargetType getTargetType() { return _targetType; } public final int getCondition() { return _condition; } public final boolean isOverhit() { return _overhit; } public final boolean killByDOT() { return _killByDOT; } public final boolean isSuicideAttack() { return _isSuicideAttack; } public final boolean allowOnTransform() { return isPassive(); } /** * Return the power of the skill.

*/ public final double getPower(L2Character activeChar) { if (activeChar == null) return _power; switch (_skillType) { case DEATHLINK: { return _power * Math.pow(1.7165 - activeChar.getCurrentHp() / activeChar.getMaxHp(), 2) * 0.577; /* * DrHouse: * Rolling back to old formula (look below) for DEATHLINK due to this one based on logarithm is not * accurate enough. Commented here because probably is a matter of just adjusting a constant if(activeChar.getCurrentHp() / activeChar.getMaxHp() > 0.005) return _power*(-0.45*Math.log(activeChar.getCurrentHp()/activeChar.getMaxHp())+1.); else return _power*(-0.45*Math.log(0.005)+1.); */ } case FATAL: { return _power*3.5*(1-activeChar.getCurrentHp()/activeChar.getMaxHp()); } default: return _power; } } public final double getPower() { return _power; } public final L2SkillType[] getNegateStats() { return _negateStats; } public final int getAbnormalLvl() { return _abnormalLvl; } public final int getNegateLvl() { return _negateLvl; } public final int[] getNegateId() { return _negateId; } public final int getMagicLevel() { return _magicLevel; } public final int getMaxNegatedEffects() { return _maxNegatedEffects; } public final int getLevelDepend() { return _levelDepend; } /** * Return true if skill should ignore all resistances */ public final boolean ignoreResists() { return _ignoreResists; } /** * Return the additional effect Id.

*/ public final int getEffectId() { return _effectId; } /** * Return the additional effect level.

*/ public final int getEffectLvl() { return _effectLvl; } public final int getEffectAbnormalLvl() { return _effectAbnormalLvl; } /** * Return the additional effect skill type (ex : STUN, PARALYZE,...).

*/ public final L2SkillType 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 cpConsume; */ public final int getCpConsume() { return _cpConsume; } /** * @return Returns the effectRange. */ public final int getEffectRange() { return _effectRange; } /** * @return Returns the hpConsume. */ public final int getHpConsume() { return _hpConsume; } /** * @return Returns the id. */ public final int getId() { return _id; } /** * @return Returns the boolean _isDebuff. */ public final boolean isDebuff() { return _isDebuff; } public int getDisplayId() { return _displayId; } public void setDisplayId(int id) { _displayId = id; } public int getTriggeredId() { return _triggeredId; } public int getTriggeredLevel() { return _triggeredLevel; } public boolean triggerAnotherSkill() { return _triggeredId > 1; } /** * Return the skill type (ex : BLEED, SLEEP, WATER...).

*/ public final Stats getStat() { return _stat; } /** * @return Returns the _targetConsumeId. */ public final int getTargetConsumeId() { return _targetConsumeId; } /** * @return Returns the targetConsume. */ public final int getTargetConsume() { return _targetConsume; } /** * @return Returns the itemConsume. */ public final int getItemConsume() { return _itemConsume; } /** * @return Returns the itemConsumeId. */ public final int getItemConsumeId() { return _itemConsumeId; } /** * @return Returns the itemConsume count over time. */ public final int getItemConsumeOT() { return _itemConsumeOT; } /** * @return Returns the itemConsumeId over time. */ public final int getItemConsumeIdOT() { return _itemConsumeIdOT; } /** * @return Returns the itemConsume count over time. */ public final int getItemConsumeSteps() { return _itemConsumeSteps; } /** * @return Returns the itemConsume count over time. */ public final int getTotalLifeTime() { return _summonTotalLifeTime; } /** * @return Returns the itemConsume count over time. */ public final int getTimeLostIdle() { return _summonTimeLostIdle; } /** * @return Returns the itemConsumeId over time. */ public final int getTimeLostActive() { return _summonTimeLostActive; } public final boolean isCubic() { return _isCubic; } /** * @return Returns the itemConsume time in milliseconds. */ public final int getItemConsumeTime() { return _itemConsumeTime; } /** * @return Returns the activation time for a cubic. */ public final int getActivationTime() { return _activationtime; } /** * @return Returns the activation chance for a cubic. */ public final int getActivationChance() { return _activationchance; } /** * @return Returns the level. */ public final int getLevel() { return _level; } /** * @return Returns the magic. */ public final boolean isMagic() { return _magic; } /** * @return Returns true to set static reuse. */ public final boolean isStaticReuse() { return _staticReuse; } /** * @return Returns true to set static hittime. */ public final boolean isStaticHitTime() { return _staticHitTime; } /** * @return Returns the mpConsume. */ public final int getMpConsume() { return _mpConsume; } /** * @return Returns the mpInitialConsume. */ public final int getMpInitialConsume() { return _mpInitialConsume; } /** * @return Returns the name. */ public final String getName() { return _name; } /** * @return Returns the reuseDelay. */ public final int getReuseDelay() { return _reuseDelay; } public final int getEquipDelay() { return _equipDelay; } public final int getHitTime() { return _hitTime; } /** * @return Returns the coolTime. */ public final int getCoolTime() { return _coolTime; } 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 boolean isChance() { return _chanceCondition != null && isPassive(); } public ChanceCondition getChanceCondition() { return _chanceCondition; } public final boolean isDance() { return _isDance; } public final int getNextDanceMpCost() { return _nextDanceCost; } public final float getSSBoost() { return _sSBoost; } public final int getAggroPoints() { return _aggroPoints; } public final boolean useSoulShot() { switch (getSkillType()) { case PDAM: case STUN: case CHARGEDAM: case BLOW: return true; default: return false; } } public final boolean useSpiritShot() { return isMagic(); } public final boolean useFishShot() { return ((getSkillType() == L2SkillType.PUMPING) || (getSkillType() == L2SkillType.REELING) ); } public final int getWeaponsAllowed() { return _weaponsAllowed; } public int getMinPledgeClass() { return _minPledgeClass; } public final boolean isPvpSkill() { switch (_skillType) { case DOT: case BLEED: case CONFUSION: case POISON: case DEBUFF: case AGGDEBUFF: case STUN: case ROOT: case FEAR: case SLEEP: case MDOT: case MUTE: case WEAKNESS: case PARALYZE: case CANCEL: case MAGE_BANE: case WARRIOR_BANE: case BETRAY: case DISARM: case AGGDAMAGE: return true; default: return false; } } public final boolean isOffensive() { return _isOffensive; } public final boolean isNeutral() { return _isNeutral; } public final boolean isHeroSkill() { return _isHeroSkill; } public final int getNumCharges() { return _numCharges; } public final int getNumSouls() { return _numSouls; } public final int getMaxSoulConsumeCount() { return _soulMaxConsume; } public final int getSoulConsumeCount() { return _soulConsume; } public final int getExpNeeded() { return _expNeeded; } public final int getCritChance() { return _critChance; } public final int getTransformId() { return _transformId; } public final int getTransformDuration() { return _transformDuration; } public final int getBaseCritRate() { return _baseCritRate; } public final int getLethalChance1() { return _lethalEffect1; } public final int getLethalChance2() { return _lethalEffect2; } public final boolean getDmgDirectlyToHP() { return _directHpDmg; } public final String getFlyType() { return _flyType; } public final int getFlyRadius() { return _flyRadius; } public final float getFlyCourse() { return _flyCourse; } public final boolean isSkillTypeOffensive() { switch (_skillType) { case PDAM: case MDAM: case CPDAM: case DOT: case BLEED: case POISON: case AGGDAMAGE: case DEBUFF: case AGGDEBUFF: case STUN: case ROOT: case CONFUSION: case ERASE: case BLOW: case FATAL: 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: case MAGE_BANE: case WARRIOR_BANE: case AGGREMOVE: case AGGREDUCE_CHAR: case BETRAY: case DELUXE_KEY_UNLOCK: case SOW: case HARVEST: case DISARM: case STEAL_BUFF: case INSTANT_JUMP: return true; default: return this.isDebuff(); } } // 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) { if(getWeaponDependancy(activeChar,false)) { return true; } else { SystemMessage message = new SystemMessage(SystemMessageId.S1_CANNOT_BE_USED); message.addSkillName(this); activeChar.sendPacket(message); return false; } } public final boolean getWeaponDependancy(L2Character activeChar,boolean chance) { int weaponsAllowed = getWeaponsAllowed(); //check to see if skill has a weapon dependency. if (weaponsAllowed == 0) return true; int mask = 0; if (activeChar.getActiveWeaponItem() != null) mask |= activeChar.getActiveWeaponItem().getItemType().mask(); if (activeChar.getSecondaryWeaponItem() != null) mask |= activeChar.getSecondaryWeaponItem().getItemType().mask(); if ((mask & weaponsAllowed) != 0) return true; return false; } public boolean checkCondition(L2Character activeChar, L2Object target, boolean itemOrWeapon) { 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. } Condition preCondition = _preCondition; if(itemOrWeapon) preCondition = _itemPreCondition; if (preCondition == null) return true; Env env = new Env(); env.player = activeChar; if (target instanceof L2Character) // TODO: object or char? env.target = (L2Character)target; env.skill = this; if (!preCondition.test(env)) { String msg = preCondition.getMessage(); int msgId = preCondition.getMessageId(); if (msgId != 0) { SystemMessage sm = new SystemMessage(msgId); if (preCondition.isAddName()) sm.addSkillName(_id); activeChar.sendPacket(sm); } else if (msg != null) { activeChar.sendMessage(msg); } return false; } return true; } public final L2Object[] getTargetList(L2Character activeChar, boolean onlyFirst) { // 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(); // If the L2Object targeted is a L2Character, it becomes the L2Character target if (objTarget instanceof L2Character) { target = (L2Character) objTarget; } return getTargetList(activeChar, onlyFirst, target); } /** * Return all targets of the skill in a table in function a the skill type.

* * Values of skill type :

*
  • ONE : The skill can only be used on the L2PcInstance targeted, or on the caster if it's a L2PcInstance and no L2PcInstance targeted
  • *
  • SELF
  • *
  • HOLY, UNDEAD
  • *
  • PET
  • *
  • AURA, AURA_CLOSE
  • *
  • AREA
  • *
  • MULTIFACE
  • *
  • PARTY, CLAN
  • *
  • CORPSE_PLAYER, CORPSE_MOB, CORPSE_CLAN
  • *
  • UNLOCKABLE
  • *
  • ITEM


  • * * @param activeChar The L2Character who use the skill * */ public final L2Object[] getTargetList(L2Character activeChar, boolean onlyFirst, L2Character target) { List targetList = new FastList(); // 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(); // Get the type of the skill // (ex : PDAM, MDAM, DOT, BLEED, POISON, HEAL, HOT, MANAHEAL, MANARECHARGE, AGGDAMAGE, BUFF, DEBUFF, STUN, ROOT, RESURRECT, PASSIVE...) L2SkillType skillType = getSkillType(); switch (targetType) { // The skill can only be used on the L2Character targeted, or on the caster itself case TARGET_ONE: { boolean canTargetSelf = false; switch (skillType) { case BUFF: case HEAL: case HOT: case HEAL_PERCENT: case MANARECHARGE: case MANAHEAL: case NEGATE: case CANCEL: case CANCEL_DEBUFF: case REFLECT: case COMBATPOINTHEAL: case MAGE_BANE: case WARRIOR_BANE: case BETRAY: case BALANCE_LIFE: canTargetSelf = true; break; } // Check for null target or any other invalid target if (target == null || target.isDead() || (target == activeChar && !canTargetSelf)) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } // 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: case TARGET_GROUND: { return new L2Character[] {activeChar}; } case TARGET_HOLY: { if (activeChar instanceof L2PcInstance) { if (target instanceof L2ArtefactInstance) return new L2Character[] {target}; } return _emptyTargetList; } case TARGET_FLAGPOLE: { return new L2Character[] {activeChar}; } case TARGET_PET: { target = activeChar.getPet(); if (target != null && !target.isDead()) return new L2Character[] {target}; return _emptyTargetList; } case TARGET_SUMMON: { target = activeChar.getPet(); if (target != null && !target.isDead() && target instanceof L2SummonInstance) return new L2Character[] {target}; return _emptyTargetList; } case TARGET_OWNER_PET: { if (activeChar instanceof L2Summon) { target = ((L2Summon)activeChar).getOwner(); if (target != null && !target.isDead()) return new L2Character[]{target}; } return _emptyTargetList; } case TARGET_CORPSE_PET: { if (activeChar instanceof L2PcInstance) { target = activeChar.getPet(); if (target != null && target.isDead()) return new L2Character[]{target}; } return _emptyTargetList; } case TARGET_AURA: { int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); L2PcInstance src = activeChar.getActingPlayer(); // Go through the L2Character _knownList Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) if (getSkillType() == L2SkillType.DUMMY) { for (L2Object obj : objs) { if (!(obj == activeChar || obj instanceof L2Npc || obj instanceof L2Attackable)) continue; if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue; targetList.add((L2Character) obj); } targetList.add(activeChar); } else { for (L2Object obj : objs) { if (obj instanceof L2Attackable || obj instanceof L2Playable) { // Don't add this target if this is a Pc->Pc pvp // casting and pvp condition not met if (obj == activeChar || obj == src || ((L2Character) obj).isDead()) continue; if (src != null) { if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; // check if both attacker and target are // L2PcInstances and if they are in same party if (obj instanceof L2PcInstance) { if (!src.checkPvpSkill(obj, this)) continue; if ((src.getParty() != null && ((L2PcInstance) obj).getParty() != null) && src.getParty().getPartyLeaderOID() == ((L2PcInstance) obj).getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == ((L2PcInstance) obj).getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == ((L2PcInstance) obj).getClanId()) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if (!src.checkPvpSkill(trg, this)) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2PlayableInstance { if (!(obj instanceof L2Playable) // Target // is // not // L2PlayableInstance && !activeChar.isConfused()) // and // caster // not // confused // (?) continue; } if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue; if (onlyFirst == false) targetList.add((L2Character) obj); else return new L2Character[] { (L2Character) obj }; } } } return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_FRONT_AURA: { int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); L2PcInstance src = activeChar.getActingPlayer(); // Go through the L2Character _knownList Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (obj instanceof L2Attackable || obj instanceof L2Playable) { // Don't add this target if this is a Pc->Pc pvp // casting and pvp condition not met if (obj == activeChar || obj == src || ((L2Character) obj).isDead()) continue; if (src != null) { if (!((L2Character) obj).isInFrontOf(activeChar)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; // check if both attacker and target are // L2PcInstances and if they are in same party if (obj instanceof L2PcInstance) { if (!src.checkPvpSkill(obj, this)) continue; if ((src.getParty() != null && ((L2PcInstance) obj).getParty() != null) && src.getParty().getPartyLeaderOID() == ((L2PcInstance) obj).getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == ((L2PcInstance) obj).getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == ((L2PcInstance) obj).getClanId()) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if (!src.checkPvpSkill(trg, this)) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2PlayableInstance { if (!(obj instanceof L2Playable) // Target // is // not // L2PlayableInstance && !activeChar.isConfused()) // and // caster // not // confused // (?) continue; } if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue; if (onlyFirst == false) targetList.add((L2Character) obj); else return new L2Character[] { (L2Character) obj }; } } } return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_BEHIND_AURA: { int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); L2PcInstance src = activeChar.getActingPlayer(); // Go through the L2Character _knownList Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (obj instanceof L2Attackable || obj instanceof L2Playable) { // Don't add this target if this is a Pc->Pc pvp // casting and pvp condition not met if (obj == activeChar || obj == src || ((L2Character) obj).isDead()) continue; if (src != null) { if (!((L2Character) obj).isBehind(activeChar)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; // check if both attacker and target are // L2PcInstances and if they are in same party if (obj instanceof L2PcInstance) { if (!src.checkPvpSkill(obj, this)) continue; if ((src.getParty() != null && ((L2PcInstance) obj).getParty() != null) && src.getParty().getPartyLeaderOID() == ((L2PcInstance) obj).getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == ((L2PcInstance) obj).getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == ((L2PcInstance) obj).getClanId()) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if (!src.checkPvpSkill(trg, this)) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(((L2Character) obj).isInsideZone(L2Character.ZONE_PVP) && !((L2Character) obj).isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2PlayableInstance { if (!(obj instanceof L2Playable) // Target // is // not // L2PlayableInstance && !activeChar.isConfused()) // and // caster // not // confused // (?) continue; } if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue; if (onlyFirst == false) targetList.add((L2Character) obj); else return new L2Character[] { (L2Character) obj }; } } } return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target // is // not // L2Attackable // or // L2PlayableInstance (getCastRange() >= 0 && (target == null || target == activeChar || target.isAlikeDead()))) // target // is // null // or // self // or // dead/faking { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } L2Character cha; if (getCastRange() >= 0) { cha = target; if(!onlyFirst) targetList.add(cha); // Add target to target list else return new L2Character[]{cha}; } else cha = activeChar; boolean effectOriginIsL2PlayableInstance = (cha instanceof L2Playable); L2PcInstance src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; if (obj == cha) continue; target = (L2Character) obj; if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, obj, cha, true)) continue; if (src != null) // caster is l2playableinstance // and exists { if (obj instanceof L2PcInstance) { L2PcInstance trg = (L2PcInstance) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Character.ZONE_PEACE)) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(obj, this)) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(trg, this)) continue; } if (((L2Summon) obj).isInsideZone(L2Character.ZONE_PEACE)) continue; } } else // Skill user is not L2PlayableInstance { if (effectOriginIsL2PlayableInstance && // If // effect // starts // at // L2PlayableInstance // and !(obj instanceof L2Playable)) // Object // is // not // L2PlayableInstance continue; } targetList.add((L2Character) obj); } } } if (targetList.isEmpty()) return _emptyTargetList; return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_FRONT_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target // is // not // L2Attackable // or // L2PlayableInstance (getCastRange() >= 0 && (target == null || target == activeChar || target.isAlikeDead()))) // target // is // null // or // self // or // dead/faking { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } L2Character cha; if (getCastRange() >= 0) { cha = target; if(!onlyFirst) targetList.add(cha); // Add target to target // list else return new L2Character[]{cha}; } else cha = activeChar; boolean effectOriginIsL2PlayableInstance = (cha instanceof L2Playable); boolean srcIsSummon = (activeChar instanceof L2Summon); L2PcInstance src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (obj == cha) continue; if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; target = (L2Character) obj; if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, obj, activeChar, true)) continue; if (!((L2Character) obj).isInFrontOf(activeChar)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; if (src != null) // caster is l2playableinstance // and exists { if (obj instanceof L2PcInstance) { L2PcInstance trg = (L2PcInstance) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Character.ZONE_PEACE)) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(obj, this, srcIsSummon)) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(trg, this, srcIsSummon)) continue; } if (((L2Summon) obj).isInsideZone(L2Character.ZONE_PEACE)) continue; } } else // Skill user is not L2PlayableInstance { if (effectOriginIsL2PlayableInstance && // If // effect // starts // at // L2PlayableInstance // and !(obj instanceof L2Playable)) // Object // is // not // L2PlayableInstance continue; } targetList.add((L2Character) obj); } } } if (targetList.isEmpty()) return _emptyTargetList; return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_BEHIND_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target // is // not // L2Attackable // or // L2PlayableInstance (getCastRange() >= 0 && (target == null || target == activeChar || target.isAlikeDead()))) // target // is // null // or // self // or // dead/faking { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } L2Character cha; if (getCastRange() >= 0) { cha = target; if(!onlyFirst) targetList.add(cha); // Add target to target // list else return new L2Character[]{cha}; } else cha = activeChar; boolean effectOriginIsL2PlayableInstance = (cha instanceof L2Playable); L2PcInstance src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; if (obj == cha) continue; target = (L2Character) obj; if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, obj, activeChar, true)) continue; if (!((L2Character) obj).isBehind(activeChar)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; if (src != null) // caster is l2playableinstance // and exists { if (obj instanceof L2PcInstance) { L2PcInstance trg = (L2PcInstance) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Character.ZONE_PEACE)) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(obj, this)) continue; } } if (obj instanceof L2Summon) { L2PcInstance trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(trg, this)) continue; } if (((L2Summon) obj).isInsideZone(L2Character.ZONE_PEACE)) continue; } } else // Skill user is not L2PlayableInstance { if (effectOriginIsL2PlayableInstance && // If // effect // starts // at // L2PlayableInstance // and !(obj instanceof L2Playable)) // Object // is // not // L2PlayableInstance continue; } targetList.add((L2Character) obj); } } } if (targetList.isEmpty()) return _emptyTargetList; return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_MULTIFACE: { if ((!(target instanceof L2Attackable) && !(target instanceof L2PcInstance))) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } if (onlyFirst == false) targetList.add(target); else return new L2Character[] {target}; int radius = getSkillRadius(); Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (!Util.checkIfInRange(radius, activeChar, obj, true)) continue; if (obj instanceof L2Attackable && obj != target) targetList.add((L2Character) obj); if (targetList.isEmpty()) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_CANT_FOUND)); return _emptyTargetList; } } } 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 (onlyFirst) return new L2Character[]{activeChar}; targetList.add(activeChar); L2PcInstance player = null; if (activeChar instanceof L2Summon) { player = ((L2Summon)activeChar).getOwner(); targetList.add(player); } else if (activeChar instanceof L2PcInstance) { player = (L2PcInstance)activeChar; if (activeChar.getPet() != null) targetList.add(activeChar.getPet()); } if (activeChar.getParty() != null) { // Get all visible objects in a spherical area near the L2Character // Get a list of Party Members List partyList = activeChar.getParty().getPartyMembers(); for(L2PcInstance partyMember : partyList) { if (partyMember == null) continue; if (partyMember == player) continue; if (!partyMember.isDead() && Util.checkIfInRange(getSkillRadius(), activeChar, partyMember, true)) { targetList.add(partyMember); if (partyMember.getPet() != null && !partyMember.getPet().isDead()) { targetList.add(partyMember.getPet()); } } } } return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_PARTY_MEMBER: { if ((target != null && target == activeChar) || (target != null && activeChar.getParty() != null && target.getParty() != null && activeChar.getParty().getPartyLeaderOID() == target.getParty().getPartyLeaderOID()) || (target != null && activeChar instanceof L2PcInstance && target instanceof L2Summon && activeChar.getPet() == target) || (target != null && activeChar instanceof L2Summon && target instanceof L2PcInstance && activeChar == target.getPet())) { if (!target.isDead()) { // If a target is found, return it in a table else send a system message TARGET_IS_INCORRECT return new L2Character[]{target}; } else return _emptyTargetList; } else { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } } case TARGET_PARTY_OTHER: { if (target != null && target != activeChar && activeChar.getParty() != null && target.getParty() != null && activeChar.getParty().getPartyLeaderOID() == target.getParty().getPartyLeaderOID()) { if (!target.isDead()) { if (target instanceof L2PcInstance) { L2PcInstance player = (L2PcInstance)target; switch (getId()) { // FORCE BUFFS may cancel here but there should be a proper condition case 426: if (!player.isMageClass()) return new L2Character[]{target}; else return _emptyTargetList; case 427: if (player.isMageClass()) return new L2Character[]{target}; else return _emptyTargetList; } } return new L2Character[]{target}; } else return _emptyTargetList; } else { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } } case TARGET_CORPSE_ALLY: case TARGET_ALLY: { if (activeChar instanceof L2PcInstance) { int radius = getSkillRadius(); L2PcInstance player = (L2PcInstance) activeChar; L2Clan clan = player.getClan(); if (player.isInOlympiadMode()) return new L2Character[] {player}; if (targetType != SkillTargetType.TARGET_CORPSE_ALLY) { if (onlyFirst == false) targetList.add(player); else return new L2Character[] {player}; } if (activeChar.getPet() != null) { if ((targetType != SkillTargetType.TARGET_CORPSE_ALLY) && !(activeChar.getPet().isDead())) targetList.add(activeChar.getPet()); } if (clan != null) { // Get all visible objects in a spherical area near the L2Character // Get Clan Members Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object newTarget : objs) { if (!(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 (player.isInDuel() && (player.getDuelId() != ((L2PcInstance) newTarget).getDuelId() || (player.getParty() != null && !player.getParty().getPartyMembers().contains(newTarget)))) continue; if (((L2PcInstance) newTarget).getPet() != null) if (Util.checkIfInRange(radius, activeChar, ((L2PcInstance) newTarget).getPet(), true)) if ((targetType != SkillTargetType.TARGET_CORPSE_ALLY) && !(((L2PcInstance) newTarget).getPet().isDead()) && player.checkPvpSkill(newTarget, this) && onlyFirst == false) targetList.add(((L2PcInstance) newTarget).getPet()); if (targetType == SkillTargetType.TARGET_CORPSE_ALLY) { if (!((L2PcInstance) newTarget).isDead()) continue; // Siege battlefield resurrect has been made possible for participants if (getSkillType() == L2SkillType.RESURRECT) { if (((L2PcInstance) newTarget).isInsideZone(L2Character.ZONE_SIEGE) && ((L2PcInstance) newTarget).getSiegeState() == 0) 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; if (onlyFirst == false) targetList.add((L2Character) newTarget); else return new L2Character[] { (L2Character) newTarget }; } } } } return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_CORPSE_CLAN: case TARGET_CLAN: { if (activeChar instanceof L2Playable) { int radius = getSkillRadius(); L2PcInstance player = null; if (activeChar instanceof L2Summon) player = ((L2Summon)activeChar).getOwner(); else player = (L2PcInstance) activeChar; if (player == null) return _emptyTargetList; L2Clan clan = player.getClan(); if (player.isInOlympiadMode()) return new L2Character[] {player}; if (targetType != SkillTargetType.TARGET_CORPSE_CLAN) { if (onlyFirst == false) targetList.add(player); else return new L2Character[] {player}; } if (activeChar.getPet() != null) { if ((targetType != SkillTargetType.TARGET_CORPSE_CLAN) && !(activeChar.getPet().isDead())) targetList.add(activeChar.getPet()); } 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 || newTarget == player) continue; if (player.isInDuel() && (player.getDuelId() != newTarget.getDuelId() || (player.getParty() != null && !player.getParty().getPartyMembers().contains(newTarget)))) continue; if (newTarget.getPet() != null) if (Util.checkIfInRange(radius, activeChar, newTarget.getPet(), true)) if ((targetType != SkillTargetType.TARGET_CORPSE_CLAN) && !(newTarget.getPet().isDead()) && player.checkPvpSkill(newTarget, this) && onlyFirst == false) targetList.add(newTarget.getPet()); if (targetType == SkillTargetType.TARGET_CORPSE_CLAN) { if (!newTarget.isDead()) continue; if (getSkillType() == L2SkillType.RESURRECT) { // check target is not in a active siege zone if (newTarget.isInsideZone(L2Character.ZONE_SIEGE)) 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; if (onlyFirst == false) targetList.add(newTarget); else return new L2Character[] {newTarget}; } } } else if (activeChar instanceof L2Npc) { // for buff purposes, returns one unbuffed friendly mob nearby or mob itself? L2Npc npc = (L2Npc) activeChar; Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object newTarget : objs) { if (newTarget instanceof L2Npc && ((L2Npc) newTarget).getFactionId() == npc.getFactionId()) { if (!Util.checkIfInRange(getCastRange(), activeChar, newTarget, true)) continue; if (((L2Npc) newTarget).getFirstEffect(this) != null) { targetList.add((L2Npc) newTarget); break; } } } } if (targetList.isEmpty()) { targetList.add(activeChar); } } 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 (getSkillType() == L2SkillType.RESURRECT) { // check target is not in a active siege zone if (target.isInsideZone(L2Character.ZONE_SIEGE)) { condGood = false; player.sendPacket(new SystemMessage(SystemMessageId.CANNOT_BE_RESURRECTED_DURING_SIEGE)); } if (targetPlayer != null) { if (targetPlayer.isReviveRequested()) { if (targetPlayer.isRevivingPet()) player.sendPacket(new SystemMessage(SystemMessageId.MASTER_CANNOT_RES)); // While a pet is attempting to resurrect, it cannot help in resurrecting its master. else player.sendPacket(new SystemMessage(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED)); // Resurrection is already been proposed. condGood = false; } } else if (targetPet != null) { if (targetPet.getOwner() != player) { condGood = false; player.sendMessage("You are not the owner of this pet"); } } } if (condGood) { if (onlyFirst == false) { targetList.add(target); return targetList.toArray(new L2Object[targetList.size()]); } else return new L2Character[] {target}; } } } activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } case TARGET_CORPSE_MOB: { if (!(target instanceof L2Attackable) || !target.isDead()) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } // Corpse mob only available for half time switch (getSkillType()) { case DRAIN: case SUMMON: { if (DecayTaskManager.getInstance().getTasks().containsKey(target) && (System.currentTimeMillis() - DecayTaskManager.getInstance().getTasks().get(target)) > DecayTaskManager.ATTACKABLE_DECAY_TIME / 2) { activeChar.sendPacket(new SystemMessage(SystemMessageId.CORPSE_TOO_OLD_SKILL_NOT_USED)); return _emptyTargetList; } } } if (onlyFirst == false) { targetList.add(target); return targetList.toArray(new L2Object[targetList.size()]); } else return new L2Character[] {target}; } case TARGET_AREA_CORPSE_MOB: { if ((!(target instanceof L2Attackable)) || !target.isDead()) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } if (onlyFirst == false) targetList.add(target); else return new L2Character[] {target}; boolean srcInArena = (activeChar.isInsideZone(L2Character.ZONE_PVP) && !activeChar.isInsideZone(L2Character.ZONE_SIEGE)); L2PcInstance src = null; if (activeChar instanceof L2PcInstance) src = (L2PcInstance)activeChar; L2PcInstance trg = null; int radius = getSkillRadius(); Collection objs = activeChar.getKnownList().getKnownObjects().values(); //synchronized (activeChar.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (!(obj instanceof L2Attackable || obj instanceof L2Playable) || ((L2Character) obj).isDead() || ((L2Character) obj) == activeChar) continue; if (!Util.checkIfInRange(radius, target, obj, true)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; if (obj instanceof L2PcInstance && src != null) { trg = (L2PcInstance) obj; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Character.ZONE_PEACE)) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(obj, this)) continue; } } if (obj instanceof L2Summon && src != null) { trg = ((L2Summon) obj).getOwner(); if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !(trg.isInsideZone(L2Character.ZONE_PVP) && !trg.isInsideZone(L2Character.ZONE_SIEGE))) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(trg, this)) continue; } if (((L2Summon) obj).isInsideZone(L2Character.ZONE_PEACE)) continue; } targetList.add((L2Character) obj); } } if (targetList.isEmpty()) return _emptyTargetList; return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_UNLOCKABLE: { if (!(target instanceof L2DoorInstance) && !(target instanceof L2ChestInstance)) { //activeChar.sendPacket(new SystemMessage(SystemMessage.TARGET_IS_INCORRECT)); return _emptyTargetList; } if (onlyFirst == false) { targetList.add(target); return targetList.toArray(new L2Object[targetList.size()]); } else return new L2Character[] {target}; } case TARGET_UNDEAD: { if (target instanceof L2Npc || target instanceof L2SummonInstance) { if (!target.isUndead() || target.isDead()) { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } if (onlyFirst == false) targetList.add(target); else return new L2Character[] {target}; return targetList.toArray(new L2Object[targetList.size()]); } else { activeChar.sendPacket(new SystemMessage(SystemMessageId.TARGET_IS_INCORRECT)); return _emptyTargetList; } } case TARGET_AREA_UNDEAD: { L2Character cha; int radius = getSkillRadius(); if (getCastRange() >= 0 && (target instanceof L2Npc || target instanceof L2SummonInstance) && target.isUndead() && !target.isAlikeDead()) { cha = target; if (onlyFirst == false) targetList.add(cha); // Add target to target list else return new L2Character[] {cha}; } else cha = activeChar; Collection objs = cha.getKnownList().getKnownObjects().values(); //synchronized (cha.getKnownList().getKnownObjects()) { for (L2Object obj : objs) { if (obj instanceof L2Npc) target = (L2Npc) obj; else if (obj instanceof L2SummonInstance) target = (L2SummonInstance) obj; else continue; if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; if (!target.isAlikeDead()) // If target is not // dead/fake death and not // self { if (!target.isUndead()) continue; if (!Util.checkIfInRange(radius, cha, obj, true)) continue; if (onlyFirst == false) targetList.add((L2Character) obj); else return new L2Character[] { (L2Character) obj }; } } } if (targetList.isEmpty()) return _emptyTargetList; return targetList.toArray(new L2Character[targetList.size()]); } case TARGET_ENEMY_SUMMON: { if(target instanceof L2Summon) { L2Summon targetSummon = (L2Summon)target; if (activeChar instanceof L2PcInstance && activeChar.getPet() != targetSummon && !targetSummon.isDead() && (targetSummon.getOwner().getPvpFlag() != 0 || targetSummon.getOwner().getKarma() > 0) || (targetSummon.getOwner().isInsideZone(L2Character.ZONE_PVP) && ((L2PcInstance)activeChar).isInsideZone(L2Character.ZONE_PVP))) return new L2Character[]{targetSummon}; } return _emptyTargetList; } default: { activeChar.sendMessage("Target type of skill is not currently handled"); return _emptyTargetList; } }//end switch } public final L2Object[] getTargetList(L2Character activeChar) { return getTargetList(activeChar, false); } public final L2Object getFirstOfTargetList(L2Character activeChar) { L2Object[] targets; targets = getTargetList(activeChar, true); if (targets.length == 0) return null; else return targets[0]; } public final Func[] getStatFuncs(L2Effect effect, L2Character player) { if (!(player instanceof L2PcInstance) && !(player instanceof L2Attackable) && !(player instanceof L2Summon)) return _emptyFunctionSet; if (_funcTemplates == null) return _emptyFunctionSet; List funcs = new FastList(); 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.isEmpty()) return _emptyFunctionSet; return funcs.toArray(new Func[funcs.size()]); } public boolean hasEffects() { return (_effectTemplates != null && _effectTemplates.length > 0); } /** * Env is used to pass parameters for secondary effects (shield and ss/bss/bsss) * * @return an array with the effects that have been added to effector */ public final L2Effect[] getEffects(L2Character effector, L2Character effected, Env env) { if (isPassive()) return _emptyEffectSet; if (_effectTemplates == null) return _emptyEffectSet; // doors and siege flags cannot receive any effects if (effected instanceof L2DoorInstance ||effected instanceof L2SiegeFlagInstance ) return _emptyEffectSet; if (effector != effected) { if (effected.isInvul()) return _emptyEffectSet; if ((isOffensive() || isDebuff()) && effector instanceof L2PcInstance && ((L2PcInstance)effector).isGM()) { if (!((L2PcInstance)effector).getAccessLevel().canGiveDamage()) return _emptyEffectSet; } } List effects = new FastList(); if (env == null) env = new Env(); env.skillMastery = Formulas.calcSkillMastery(effector, this); env.player = effector; env.target = effected; env.skill = this; for (EffectTemplate et : _effectTemplates) { boolean success = true; if (et.effectPower > -1) success = Formulas.calcEffectSuccess(effector, effected, et, this, env.shld, env.ss, env.sps, env.bss); if (success) { L2Effect e = et.getEffect(env); if (e != null) { e.scheduleEffect(); effects.add(e); } } else if (effector instanceof L2PcInstance) { SystemMessage sm = new SystemMessage(SystemMessageId.C1_RESISTED_YOUR_S2); sm.addCharName(effected); sm.addSkillName(this); ((L2PcInstance)effector).sendPacket(sm); } } if (effects.isEmpty()) return _emptyEffectSet; return effects.toArray(new L2Effect[effects.size()]); } /** * Warning: this method doesn't consider modifier (shield, ss, sps, bss) for secondary effects * */ public final L2Effect[] getEffects(L2Character effector, L2Character effected) { return getEffects(effector, effected, null); } /** * This method has suffered some changes in CT2.2 ->CT2.3
    * Effect engine is now supporting secondary effects with independent * success/fail calculus from effect skill. Env parameter has been added to * pass parameters like soulshot, spiritshots, blessed spiritshots or shield deffence. * Some other optimizations have been done *

    * This new feature works following next rules: *
  • To enable feature, effectPower must be over -1 (check DocumentSkill#attachEffect for further information)
  • *
  • If main skill fails, secondary effect always fail
  • */ public final L2Effect[] getEffects(L2CubicInstance effector, L2Character effected, Env env) { if (isPassive()) return _emptyEffectSet; if (_effectTemplates == null) return _emptyEffectSet; if ((!effector.equals(effected)) && effected.isInvul()) return _emptyEffectSet; if ((isDebuff() || isOffensive()) && effector.getOwner() != effected && effector.getOwner().isGM() && !effector.getOwner().getAccessLevel().canGiveDamage()) { return _emptyEffectSet; } List effects = new FastList(); if (env == null) env = new Env(); env.player = effector.getOwner(); env.cubic = effector; env.target = effected; env.skill = this; for (EffectTemplate et : _effectTemplates) { boolean success = true; if (et.effectPower > -1) success = Formulas.calcEffectSuccess(effector.getOwner(), effected, et, this, env.shld, env.ss, env.sps, env.bss); if (success) { L2Effect e = et.getEffect(env); if (e != null) { e.scheduleEffect(); effects.add(e); } } } if (effects.isEmpty()) return _emptyEffectSet; return effects.toArray(new L2Effect[effects.size()]); } public final L2Effect[] getEffectsSelf(L2Character effector) { if (isPassive()) return _emptyEffectSet; if (_effectTemplatesSelf == null) return _emptyEffectSet; List effects = new FastList(); for (EffectTemplate et : _effectTemplatesSelf) { Env env = new Env(); env.player = effector; env.target = effector; env.skill = this; L2Effect e = et.getEffect(env); if (e != null) { e.scheduleEffect(); effects.add(e); } } if (effects.isEmpty()) 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 attachSelf(EffectTemplate effect) { if (_effectTemplatesSelf == null) { _effectTemplatesSelf = new EffectTemplate[] {effect}; } else { int len = _effectTemplatesSelf.length; EffectTemplate[] tmp = new EffectTemplate[len + 1]; System.arraycopy(_effectTemplatesSelf, 0, tmp, 0, len); tmp[len] = effect; _effectTemplatesSelf = tmp; } } public final void attach(Condition c, boolean itemOrWeapon) { if(itemOrWeapon) _itemPreCondition = c; else _preCondition = c; } @Override public String toString() { return "" + _name + "[id=" + _id + ",lvl=" + _level + "]"; } /** * @return */ public boolean isAdvancedFlag() { return _isAdvancedFlag; } /** * @return pet food */ public int getFeed() { return _feed; } /** * used for tracking item id in case that item consume cannot be used * @return reference item id */ public int getReferenceItemId() { return _refId; } /** * @return */ public int getAfroColor() { return _afroId; } /** * used for learning skills through skills * @return new skill id to learn (if not defined, default 0) */ public int getNewSkillId() { return _learnSkillId; } /** * used for learning skills through skills * @return skill lvl to learn (if not defined, default 1) */ public int getNewSkillLvl() { return _learnSkillLvl; } public final int getRequiredCharges() { return _requiredCharges; } public final int getMaxCharges() { return _maxCharges; } public int getAfterEffectId() { return _afterEffectId; } public int getAfterEffectLvl() { return _afterEffectLvl; } @Override public boolean triggersChanceSkill() { return _triggeredId > 0 && isChance(); } @Override public int getTriggeredChanceId() { return _triggeredId; } @Override public int getTriggeredChanceLevel() { return _triggeredLevel; } @Override public ChanceCondition getTriggeredChanceCondition() { return _chanceCondition; } public String getAttributeName() { return _attribute; } public boolean useShield() { return _useShield; } public int[] getTeleportCoords() { return _teleportCoords; } public String getRecallType() { return _recallType; } }