Java tutorial
/* * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package com.l2jfree.gameserver.model.skills; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.l2jfree.Config; import com.l2jfree.gameserver.datatables.SkillTable; import com.l2jfree.gameserver.datatables.SkillTreeTable; import com.l2jfree.gameserver.gameobjects.L2Attackable; import com.l2jfree.gameserver.gameobjects.L2Creature; import com.l2jfree.gameserver.gameobjects.L2Npc; import com.l2jfree.gameserver.gameobjects.L2Object; import com.l2jfree.gameserver.gameobjects.L2Playable; import com.l2jfree.gameserver.gameobjects.L2Player; import com.l2jfree.gameserver.gameobjects.L2Summon; import com.l2jfree.gameserver.gameobjects.instance.L2ArtefactInstance; import com.l2jfree.gameserver.gameobjects.instance.L2ChestInstance; import com.l2jfree.gameserver.gameobjects.instance.L2CubicInstance; import com.l2jfree.gameserver.gameobjects.instance.L2DoorInstance; import com.l2jfree.gameserver.gameobjects.instance.L2MonsterInstance; import com.l2jfree.gameserver.gameobjects.instance.L2PetInstance; import com.l2jfree.gameserver.gameobjects.instance.L2SummonInstance; import com.l2jfree.gameserver.geodata.GeoData; import com.l2jfree.gameserver.handler.SkillTargetHandler; import com.l2jfree.gameserver.instancemanager.CoupleManager; import com.l2jfree.gameserver.instancemanager.FourSepulchersManager; import com.l2jfree.gameserver.instancemanager.SiegeManager; import com.l2jfree.gameserver.model.clan.L2Clan; import com.l2jfree.gameserver.model.clan.L2ClanMember; import com.l2jfree.gameserver.model.entity.Couple; import com.l2jfree.gameserver.model.entity.Siege; import com.l2jfree.gameserver.model.items.templates.L2Weapon; import com.l2jfree.gameserver.model.items.templates.L2WeaponType; import com.l2jfree.gameserver.model.party.L2Party; import com.l2jfree.gameserver.model.restriction.global.GlobalRestrictions; import com.l2jfree.gameserver.model.skills.conditions.Condition; import com.l2jfree.gameserver.model.skills.effects.L2Effect; import com.l2jfree.gameserver.model.skills.effects.templates.EffectTemplate; import com.l2jfree.gameserver.model.skills.funcs.Func; import com.l2jfree.gameserver.model.skills.funcs.FuncOwner; import com.l2jfree.gameserver.model.skills.funcs.FuncTemplate; import com.l2jfree.gameserver.model.skills.learn.L2EnchantSkillLearn; import com.l2jfree.gameserver.model.skills.learn.L2EnchantSkillLearn.EnchantSkillDetail; import com.l2jfree.gameserver.model.skills.templates.L2SkillType; import com.l2jfree.gameserver.model.zone.L2Zone; import com.l2jfree.gameserver.network.SystemMessageId; import com.l2jfree.gameserver.network.packets.server.ActionFailed; import com.l2jfree.gameserver.network.packets.server.FlyToLocation.FlyType; import com.l2jfree.gameserver.network.packets.server.SystemMessage; import com.l2jfree.gameserver.taskmanager.DecayTaskManager; import com.l2jfree.gameserver.templates.StatsSet; import com.l2jfree.gameserver.util.Util; import com.l2jfree.lang.L2Integer; import com.l2jfree.lang.L2System; import com.l2jfree.lang.L2TextBuilder; import com.l2jfree.util.ArrayBunch; import com.l2jfree.util.L2Arrays; import com.l2jfree.util.concurrent.ForEachExecutable; public class L2Skill implements FuncOwner, IChanceSkillTrigger { public static final L2Skill[] EMPTY_ARRAY = new L2Skill[0]; protected static final Log _log = LogFactory.getLog(L2Skill.class); 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_EXPERTISE = 239; public static final int SKILL_CRYSTALLIZE = 248; public static final int SKILL_DIVINE_INSPIRATION = 1405; public static final int SKILL_SOUL_MASTERY = 467; 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_PET, TARGET_SUMMON, TARGET_PARTY, TARGET_PARTY_CLAN, TARGET_ALLY, TARGET_CLAN, TARGET_AREA, TARGET_FRONT_AREA, TARGET_BEHIND_AREA, TARGET_AURA, TARGET_FRONT_AURA, TARGET_BEHIND_AURA, TARGET_SERVITOR_AURA, TARGET_CORPSE, TARGET_CORPSE_ALLY, TARGET_CORPSE_CLAN, TARGET_CORPSE_PLAYER, TARGET_CORPSE_PET, TARGET_AREA_CORPSE_MOB, TARGET_CORPSE_MOB, TARGET_AREA_CORPSES, TARGET_MULTIFACE, TARGET_AREA_UNDEAD, TARGET_UNLOCKABLE, TARGET_HOLY, TARGET_FLAGPOLE, TARGET_PARTY_MEMBER, TARGET_PARTY_OTHER, TARGET_ENEMY_SUMMON, TARGET_OWNER_PET, TARGET_ENEMY_ALLY, TARGET_ENEMY_PET, TARGET_GATE, TARGET_COUPLE, TARGET_MOB, TARGET_AREA_MOB, TARGET_KNOWNLIST, TARGET_GROUND, TARGET_INITIATOR // TARGET_BOSS } private static enum OffensiveState { OFFENSIVE, NEUTRAL, POSITIVE; } // conditional values public final static int COND_BEHIND = 0x0008; public final static int COND_CRIT = 0x0010; // these two build the primary key private final Integer _id; private final int _level; /** Identifier for a skill that client can't display */ private final int _displayId; // not needed, just for easier debug private final String _name; // Reference ID for extractable items private final int _refId; private final SkillOpType _operateType; private final boolean _magic; private final boolean _itemSkill; 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 _itemConsume; private final int _itemConsumeId; private final int _targetConsume; private final int _targetConsumeId; private final int _feed; 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 boolean _negatePhysicalOnly; // cancel physical effects only private final L2SkillType[] _negateStats; // lists the effect types that are canceled private final int _maxNegatedEffects; // maximum number of effects to negate // all times in milliseconds private final int _hitTime; private final int _skillInterruptTime; private final int _coolTime; private final int _reuseDelay; // for item skills delay on equip private final int _equipDelay; /** Target type of the skill : SELF, PARTY, CLAN, PET... */ private final SkillTargetType _targetType; // base success chance private final double _power; private final int _levelDepend; private final boolean _ignoreResists; // Kill by damage over time private final boolean _killByDOT; // 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 _effectPower; private final int _effectId; private final float _effectLvl; // normal effect level private final int _skill_landing_percent; private final boolean _isPotion; private final byte _element; private final int _elementPower; private final int _activateRate; private final int _magicLevel; private final int _condition; private final boolean _overhit; private final boolean _ignoreShld; private final int _weaponsAllowed; private final int _armorsAllowed; private final OffensiveState _offensiveState; private final int _needCharges; private final int _giveCharges; private final int _maxCharges; private final ChanceCondition _chanceCondition; private final TriggeredSkill _triggeredSkill; private final int _soulConsume; private final int _soulMaxConsume; private final int _numSouls; private final int _expNeeded; private final int _critChance; //Stats for transformation skills private final int _transformId; 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 boolean _isSong; // If true then casting more songs will cost more MP private final int _nextDanceCost; private final float _sSBoost; // If true skill will have SoulShot boost (power*2) private final int _timeMulti; private final String _attribute; private final int _minPledgeClass; private final int _aggroPoints; private Condition _preCondition; private FuncTemplate[] _funcTemplates; private EffectTemplate[] _effectTemplates; private EffectTemplate[] _effectTemplatesSelf; // Flying support private final FlyType _flyType; private final int _flyRadius; private final float _flyCourse; private final boolean _isDebuff; private final int _afroId; private final boolean _isHerbEffect; private final boolean _ignoreShield; private final boolean _isSuicideAttack; private final boolean _canBeReflected; private final boolean _canBeDispeled; private final boolean _dispelOnAction; private final boolean _dispelOnAttack; private final int _afterEffectId; private final int _afterEffectLvl; private final boolean _stayAfterDeath; // skill should stay after death private final boolean _sendToClient; private final float _pvpPowerMulti; public L2Skill(StatsSet set) { _id = L2Integer.valueOf(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").intern(); _skillType = set.getEnum("skillType", L2SkillType.class); _operateType = set.getEnum("operateType", SkillOpType.class); _targetType = set.getEnum("target", SkillTargetType.class); _magic = set.getBool("isMagic", isSkillTypeMagic()); _itemSkill = set.getBool("isItem", 3080 <= getId() && getId() <= 3259); _isPotion = set.getBool("isPotion", false); _staticReuse = set.getBool("staticReuse", false); _staticHitTime = set.getBool("staticHitTime", false); _mpConsume = set.getInteger("mpConsume", 0); _mpInitialConsume = set.getInteger("mpInitialConsume", 0); _hpConsume = set.getInteger("hpConsume", 0); _cpConsume = set.getInteger("cpConsume", 0); _itemConsume = set.getInteger("itemConsumeCount", 0); _itemConsumeId = set.getInteger("itemConsumeId", 0); _targetConsume = set.getInteger("targetConsumeCount", 0); _targetConsumeId = set.getInteger("targetConsumeId", 0); _afterEffectId = set.getInteger("afterEffectId", 0); _afterEffectLvl = set.getInteger("afterEffectLvl", 1); _isHerbEffect = _name.contains("Herb"); _castRange = set.getInteger("castRange", 0); _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); 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.parseInt(valuesSplit[i]); } } else _negateId = new int[0]; _negatePhysicalOnly = set.getBool("negatePhysicalOnly", false); _maxNegatedEffects = set.getInteger("maxNegated", 0); _stayAfterDeath = set.getBool("stayAfterDeath", false); _killByDOT = set.getBool("killByDOT", false); _hitTime = set.getInteger("hitTime", 0); _coolTime = set.getInteger("coolTime", 0); _skillInterruptTime = set.getInteger("interruptTime", Math.min(_hitTime, 500)); _reuseDelay = set.getInteger("reuseDelay", 0); _equipDelay = set.getInteger("equipDelay", 0); _isDance = set.getBool("isDance", false); _isSong = set.getBool("isSong", false); if (_isDance || _isSong) _timeMulti = Config.ALT_DANCE_TIME; else if (_skillType == L2SkillType.BUFF) //This should correct the time effect that was caused on debuffs on AltBuffTime config _timeMulti = Config.ALT_BUFF_TIME; else _timeMulti = 1; //If the skills is not a DANCE type skill or BUFF type, the effect time is the normal, without any multiplier _skillRadius = set.getInteger("skillRadius", 80); _power = set.getFloat("power", 0.f); _levelDepend = set.getInteger("lvlDepend", 1); _ignoreResists = set.getBool("ignoreResists", false); _feed = set.getInteger("feed", 0); // Used for pet food _effectType = set.getEnum("effectType", L2SkillType.class, null); _effectPower = set.getInteger("effectPower", 0); _effectId = set.getInteger("effectId", 0); _effectLvl = set.getFloat("effectLevel", 0.f); _skill_landing_percent = set.getInteger("skill_landing_percent", 0); _element = set.getByte("element", (byte) -1); _elementPower = set.getInteger("elementPower", 0); _activateRate = set.getInteger("activateRate", -1); _magicLevel = initMagicLevel(set); _ignoreShld = set.getBool("ignoreShld", false); _condition = set.getInteger("condition", 0); _overhit = set.getBool("overHit", false); _isSuicideAttack = set.getBool("isSuicideAttack", false); _weaponsAllowed = set.getInteger("weaponsAllowed", 0); _armorsAllowed = set.getInteger("armorsAllowed", 0); _needCharges = set.getInteger("needCharges", 0); _giveCharges = set.getInteger("giveCharges", 0); _maxCharges = set.getInteger("maxCharges", 0); _minPledgeClass = set.getInteger("minPledgeClass", 0); final ChanceCondition chanceCondition = ChanceCondition.parse(set); final TriggeredSkill triggeredSkill = TriggeredSkill.parse(set); if (isValid(chanceCondition, triggeredSkill)) { _chanceCondition = chanceCondition; _triggeredSkill = triggeredSkill; } else { _chanceCondition = null; _triggeredSkill = null; } _offensiveState = getOffensiveState(set); _isDebuff = set.getBool("isDebuff", false/*isOffensive()*/); _numSouls = set.getInteger("num_souls", 0); _soulConsume = set.getInteger("soulConsumeCount", 0); _soulMaxConsume = set.getInteger("soulMaxConsumeCount", 0); _expNeeded = set.getInteger("expNeeded", 0); _critChance = set.getInteger("critChance", 0); // Stats for transformation Skill _transformId = set.getInteger("transformId", 0); _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); _nextDanceCost = set.getInteger("nextDanceCost", 0); _sSBoost = set.getFloat("SSBoost", 2); _aggroPoints = set.getInteger("aggroPoints", 0); _flyType = set.getEnum("flyType", FlyType.class, null); _flyRadius = set.getInteger("flyRadius", 200); _flyCourse = set.getFloat("flyCourse", 0); _canBeReflected = set.getBool("canBeReflected", true); _canBeDispeled = set.getBool("canBeDispeled", true); _dispelOnAction = set.getBool("dispelOnAction", false); _dispelOnAttack = set.getBool("dispelOnAttack", false); _attribute = set.getString("attribute", ""); _ignoreShield = set.getBool("ignoreShld", false); _sendToClient = set.getBool("sendToClient", true); _pvpPowerMulti = set.getFloat("pvpPowerMulti", 1); } private int initMagicLevel(StatsSet set) { final int normalLevel = set.getInteger("magicLvl", SkillTreeTable.getInstance().getMinSkillLevel(_id, _level)); // normal skills if (getLevel() < 100) return normalLevel; // enchanted skills final L2EnchantSkillLearn esl = SkillTreeTable.getInstance().getSkillEnchantmentBySkillId(getId()); if (esl == null) return -1; final List<EnchantSkillDetail> route = esl.getEnchantRoutes()[L2EnchantSkillLearn .getEnchantType(getLevel())]; if (route == null) return -1; int minMagicLevel = SkillTreeTable.getInstance().getMinSkillLevel(getId(), 1); if (minMagicLevel == 0) minMagicLevel = normalLevel; if (minMagicLevel != 0) { if (route.size() == 15 && minMagicLevel > 75) { return 81 + ((getLevel() % 100) - 1) / 3; } else if (route.size() == 30 && minMagicLevel <= 75) { return 76 + ((getLevel() % 100) - 1) / 3; } } _log.warn("Invalid skill enchants (route.size(): " + route.size() + ") for " + this); return -1; } private static boolean isValid(ChanceCondition chanceCondition, TriggeredSkill triggeredSkill) { if (chanceCondition == null) return triggeredSkill == null; if (!chanceCondition.isValid()) return false; return triggeredSkill == null || triggeredSkill.isValid(); } private boolean isPurePassiveSkill() { return isPassive() && !isChance(); } private boolean isPureChanceSkill() { return isChance() && getTriggeredSkill() != null; } public void validate() throws Exception { validateEffectsAndFuncs(); validateMpConsume(); validateToggle(); validateOffensiveAndDebuffState(); validateTriggeredSkill(); } private void validateEffectsAndFuncs() { if (isPassive()) if (_effectTemplates != null || _effectTemplatesSelf != null) if (_skillType != L2SkillType.NOTDONE) if (_chanceCondition == null || _triggeredSkill != null) throw new IllegalStateException(toString()); if (!isPassive()) if (_funcTemplates != null) throw new IllegalStateException(toString()); } private void validateMpConsume() throws Exception { if (isToggle() && getMpConsume() != 0) // toggle skills consume the full mp on initial throw new IllegalStateException(toString()); } private void validateToggle() throws Exception { if (!isToggle()) return; if (getTargetType() != SkillTargetType.TARGET_SELF) throw new IllegalStateException(toString()); if (getSkillType() != L2SkillType.CONT) throw new IllegalStateException(toString()); if (getHitTime() != 0 || getSkillInterruptTime() != 0 || getCoolTime() != 0 || getReuseDelay() != 0) throw new IllegalStateException(toString()); if (_effectTemplatesSelf != null) throw new IllegalStateException(toString()); if (_effectTemplates == null || _effectTemplates.length != 1) throw new IllegalStateException(toString()); if (_effectTemplates[0].count != Integer.MAX_VALUE) throw new IllegalStateException(toString()); } private void validateOffensiveAndDebuffState() throws Exception { if (getSkillType() != L2SkillType.NOTDONE || getTargetType() != SkillTargetType.TARGET_NONE) if (!isOffensive() && isDebuff()) throw new IllegalStateException(toString()); if (isBuff() && isDebuff()) throw new IllegalStateException(toString()); } private void validateTriggeredSkill() throws Exception { // must have triggered skill if (isChance()) { if (getTriggeredSkill() != null) { final L2Skill triggeredSkill = getTriggeredSkill().getTriggeredSkill(); if (triggeredSkill == null) throw new IllegalStateException(toString()); if (triggeredSkill == this) throw new IllegalStateException(toString()); } } // can't have triggered skill else { if (getChanceCondition() != null) throw new IllegalStateException(toString()); if (getTriggeredSkill() != null) throw new IllegalStateException(toString()); } } private OffensiveState getOffensiveState(StatsSet set) { final OffensiveState defaultState = getDefaultOffensiveState(); final Boolean isOffensive = set.contains("offensive") ? set.getBool("offensive") : null; final Boolean isNeutral = set.contains("neutral") ? set.getBool("neutral") : null; if (isOffensive == null && isNeutral == null) return defaultState; if (isPurePassiveSkill() || isPureChanceSkill() || isToggle()) throw new IllegalStateException(this + " shouldn't have 'offensive'/'neutral' property specified!"); final List<OffensiveState> denied = new ArrayList<OffensiveState>(2); final List<OffensiveState> requested = new ArrayList<OffensiveState>(2); if (isOffensive != null) { if (isOffensive.booleanValue()) requested.add(OffensiveState.OFFENSIVE); else denied.add(OffensiveState.OFFENSIVE); } if (isNeutral != null) { if (isNeutral.booleanValue()) requested.add(OffensiveState.NEUTRAL); else denied.add(OffensiveState.NEUTRAL); } switch (requested.size()) { case 2: throw new IllegalStateException("Both 'neutral' and 'offensive' property requested for " + this); case 1: return requested.get(0); case 0: if (!denied.contains(defaultState)) return defaultState; //$FALL-THROUGH$ default: throw new IllegalStateException("Requested 'neutral'/'offensive' value rules out default for " + this); } } public void useSkill(L2Creature caster, L2Creature... targets) { caster.sendPacket(ActionFailed.STATIC_PACKET); if (caster instanceof L2Player) ((L2Player) caster).sendMessage("Skill not implemented. Skill ID: " + getId() + " " + getSkillType()); } public final boolean isPotion() { return _isPotion; } public final int getArmorsAllowed() { return _armorsAllowed; } public final L2SkillType getSkillType() { return _skillType; } public final boolean hasEffectWhileCasting() { return getSkillType() == L2SkillType.FUSION || getSkillType() == L2SkillType.SIGNET_CASTTIME; } public final int getActivateRate() { return _activateRate; } public final int getMagicLevel() { return _magicLevel; } public final byte getElement() { return _element; } /** * Return the target type of the skill : SELF, PARTY, CLAN, PET...<BR> * <BR> */ public final SkillTargetType getTargetType() { return _targetType; } public final int getCondition() { return _condition; } public final boolean ignoreShld() { return _ignoreShld; } public final boolean isOverhit() { return _overhit; } public final boolean killByDOT() { return _killByDOT; } public final boolean isSuicideAttack() { return _isSuicideAttack; } /** * Return the power of the skill.<BR> * <BR> */ public final double getPower(L2Creature activeChar) { if (activeChar == null) return _power; switch (_skillType) { case DEATHLINK: { return _power * Math.pow(1.7165 - activeChar.getCurrentHp() / activeChar.getMaxHp(), 2) * 0.577; } case FATALCOUNTER: { 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 boolean getNegatePhysicalOnly() { return _negatePhysicalOnly; } public final int getMaxNegatedEffects() { return _maxNegatedEffects; } public final int getEffectAbnormalLvl() { return _effectAbnormalLvl; } protected final TriggeredSkill getTriggeredSkill() { return _triggeredSkill; } public final int getLevelDepend() { return _levelDepend; } /** * Return the skill landing percent probability.<BR> * <BR> */ public final int getLandingPercent() { return _skill_landing_percent; } /** * Return the additional effect power or base probability.<BR> * <BR> */ public final double getEffectPower() { if (_effectTemplates != null) for (EffectTemplate et : _effectTemplates) if (et.effectPower > 0) return et.effectPower; if (_effectPower > 0) return _effectPower; // to let damage dealing skills having proper resist even without specified effectPower switch (_skillType.getRoot()) { case PDAM: return 20; case MDAM: return 20; default: // to let debuffs succeed even without specified power return (_power <= 0 || 100 < _power) ? 20 : _power; } } /** * Return true if skill should ignore all resistances */ public final boolean ignoreResists() { return _ignoreResists; } /** * Return the additional effect Id.<BR> * <BR> */ public final int getEffectId() { return _effectId; } /** * Return the additional effect level.<BR> * <BR> */ public final float getEffectLvl() { return _effectLvl; } /** * Return the additional effect skill type (ex : STUN, PARALYZE,...).<BR> * <BR> */ public final L2SkillType getEffectType() { if (_effectTemplates != null) for (EffectTemplate et : _effectTemplates) if (et.effectType != null) return et.effectType; if (_effectType != null) return _effectType; // to let damage dealing skills having proper resist even without specified effectType switch (_skillType.getRoot()) { case PDAM: return L2SkillType.STUN; case MDAM: return L2SkillType.PARALYZE; default: return _skillType; } } /** * @return Returns the timeMulti. */ public final int getTimeMulti() { return _timeMulti; } /** * @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 _hitTime; } /** * @return Returns the hpConsume. */ public final int getHpConsume() { return _hpConsume; } /** * @return Returns the cpConsume. */ public final int getCpConsume() { return _cpConsume; } public final boolean allowOnTransform() { // FIXME: do something about item skills!!! return (isPassive() || (getId() > 1999 && getId() < 3000)); } /** * @return Returns the id. */ public final Integer getId() { return _id; } public final int getDisplayId() { return _displayId; } public final int getMinPledgeClass() { return _minPledgeClass; } /** * @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 level. */ public final int getLevel() { return _level; } /** * @return Returns the magic. */ public final boolean isMagic() { return _magic; } public final boolean isItemSkill() { return _itemSkill; } /** * @return Returns true to set static reuse. */ public final boolean isStaticReuse() { return _staticReuse || isItemSkill() && Config.ALT_ITEM_SKILLS_NOT_INFLUENCED; } /** * @return Returns true to set static hittime. */ public final boolean isStaticHitTime() { return _staticHitTime || isItemSkill() && Config.ALT_ITEM_SKILLS_NOT_INFLUENCED; } /** * @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 getCoolTime() { return _coolTime; } 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 boolean isChance() { return getChanceCondition() != null && isPassive(); } public final boolean isDance() { return _isDance; } public final boolean isSong() { return _isSong; } public final boolean isDanceOrSong() { return isDance() || isSong(); } public final int getNextDanceMpCost() { return _nextDanceCost; } /** *@return Returns the boolean _isDebuff. */ public final boolean isDebuff() { return _isDebuff; } public final float getSSBoost() { return _sSBoost; } public final int getAggroPoints() { return _aggroPoints; } public final boolean useSpiritShot() { return isMagic(); } public final boolean useFishShot() { return ((getSkillType() == L2SkillType.PUMPING) || (getSkillType() == L2SkillType.REELING)); } public final int getWeaponsAllowed() { return _weaponsAllowed; } public final boolean isPvpSkill() { switch (_skillType.getRoot()) { case DOT: case BLEED: case CONFUSION: case POISON: case DEBUFF: case AGGDEBUFF: case STUN: case ROOT: case FEAR: case SLEEP: case MDOT: case MANADAM: case MUTE: case WEAKNESS: case PARALYZE: case CANCEL: case MAGE_BANE: case WARRIOR_BANE: case BETRAY: case DISARM: case STEAL_BUFF: case AGGDAMAGE: case DELUXE_KEY_UNLOCK: case FATALCOUNTER: case MAKE_KILLABLE: case MAKE_QUEST_DROPABLE: case AGGREDUCE_CHAR: return true; default: return false; } } public final boolean isOffensive() { return _offensiveState == OffensiveState.OFFENSIVE; } public final boolean isNeutral() { return _offensiveState == OffensiveState.NEUTRAL; } public final boolean isPositive() { return _offensiveState == OffensiveState.POSITIVE; } public final int getNeededCharges() { return _needCharges; } public final int getGiveCharges() { return _giveCharges; } public final int getMaxCharges() { return _maxCharges; } 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 getBaseCritRate() { return _baseCritRate; } public final int getLethalChance1() { return _lethalEffect1; } public final int getLethalChance2() { return _lethalEffect2; } public final boolean getDmgDirectlyToHP() { return _directHpDmg; } /** * @return pet food */ public final int getFeed() { return _feed; } public final FlyType getFlyType() { return _flyType; } public final int getFlyRadius() { return _flyRadius; } public final float getFlyCourse() { return _flyCourse; } public final int getTransformId() { return _transformId; } public final static boolean skillLevelExists(int skillId, int level) { return SkillTable.getInstance().getInfo(skillId, level) != null; } public final boolean isSkillTypeMagic() { switch (getSkillType().getRoot()) { // TODO: other skillTypes case MDAM: case HEAL: case SUMMON_FRIEND: case BALANCE_LIFE: return true; default: return false; } } private OffensiveState getDefaultOffensiveState() { if (isPurePassiveSkill() || isPureChanceSkill() || isToggle()) return OffensiveState.POSITIVE; switch (_skillType) { case PDAM: case MDAM: case CPDAM: case DOT: case CPDAMPERCENT: case CPDRAIN: case BLEED: case POISON: case AGGDAMAGE: case DEBUFF: case AGGDEBUFF: case STUN: case ROOT: case CONFUSION: case ERASE: case BLOW: case FEAR: case DRAIN: case SLEEP: case CHARGEDAM: case STRSIEGEASSAULT: case CONFUSE_MOB_ONLY: case DEATHLINK: case FATALCOUNTER: case DETECT_WEAKNESS: case MDOT: case MANADAM: case MUTE: case SPOIL: case WEAKNESS: case SWEEP: case PARALYZE: case CANCEL: case MAGE_BANE: case WARRIOR_BANE: case AGGREDUCE_CHAR: case BETRAY: case GET_PLAYER: case DISARM: case STEAL_BUFF: case INSTANT_JUMP: case SIGNET_CASTTIME: case BALLISTA: return OffensiveState.OFFENSIVE; case BUFF: case CONT: case HEAL: case HEAL_STATIC: case HEAL_PERCENT: case BALANCE_LIFE: case HOT: case MPHOT: case CPHOT: case MANAHEAL: case MANAHEAL_PERCENT: case MANARECHARGE: case COMBATPOINTHEAL: case CPHEAL_PERCENT: case RECOVER: case REFLECT: case LUCK: case PASSIVE: case RESURRECT: case CANCEL_DEBUFF: case FUSION: case CHARGE_NEGATE: case CHARGESOUL: return OffensiveState.POSITIVE; case DRAIN_SOUL: case HEAL_MOB: case AGGREDUCE: case AGGREMOVE: case SHIFT_TARGET: case SOULSHOT: case SPIRITSHOT: case ENCHANT_ARMOR: case ENCHANT_WEAPON: case MOUNT: case DECOY: case SUMMON: case AGATHION: case SUMMON_TRAP: case SUMMON_TREASURE_KEY: case CREATE_ITEM: case EXTRACTABLE: case UNLOCK: case OPEN_DOOR: case DELUXE_KEY_UNLOCK: case DETECT_TRAP: case REMOVE_TRAP: case DETECTION: case COMMON_CRAFT: case DWARVEN_CRAFT: case SIEGEFLAG: case TAKECASTLE: case TAKEFORT: case TELEPORT: case ZAKEN_TELEPORT: case RECALL: case SUMMON_FRIEND: case GIVE_SP: case GIVE_VITALITY: case CHANGE_APPEARANCE: case LEARN_SKILL: case FEED_PET: case BEAST_FEED: case NEGATE: // should be divided, since can be positive, and negative skill too case CANCEL_STATS: case MAKE_KILLABLE: case MAKE_QUEST_DROPABLE: case SOW: case HARVEST: case FISHING: case PUMPING: case REELING: case TRANSFORMDISPEL: case CHANGEWEAPON: case SIGNET: case DUMMY: case COREDONE: case NOTDONE: return OffensiveState.NEUTRAL; default: _log.info(getSkillType() + " should be covered in L2Skill.getDefaultOffensiveState()!"); return OffensiveState.NEUTRAL; } } public final boolean isNeedWeapon() { return (_skillType.getRoot() == L2SkillType.MDAM); } public final boolean isStayAfterDeath() { switch (getId()) { case 5660: case 840: case 841: case 842: return true; default: return _stayAfterDeath; } } private String _weaponDependancyMessage; public final boolean getWeaponDependancy(L2Creature activeChar, boolean message) { int weaponsAllowed = getWeaponsAllowed(); if (weaponsAllowed == 0) return true; L2Weapon weapon = activeChar.getActiveWeaponItem(); if (weapon != null && (weapon.getItemType().mask() & weaponsAllowed) != 0) return true; L2Weapon weapon2 = activeChar.getSecondaryWeaponItem(); if (weapon2 != null && (weapon2.getItemType().mask() & weaponsAllowed) != 0) return true; if (message && activeChar instanceof L2Player) { if (_weaponDependancyMessage == null) { L2TextBuilder sb = L2TextBuilder.newInstance(); sb.append(getName()); sb.append(" can only be used with weapons of type "); for (L2WeaponType wt : L2WeaponType.VALUES) { if ((wt.mask() & weaponsAllowed) != 0) { if (sb.length() != 0) sb.append('/'); sb.append(wt); } } sb.append("."); _weaponDependancyMessage = sb.moveToString().intern(); } if (activeChar instanceof L2Player) ((L2Player) activeChar).sendMessage(_weaponDependancyMessage); } return false; } public final boolean ownedFuncShouldBeDisabled(L2Creature activeChar) { if (isOffensive()) return false; if (!isDanceOrSong() && !getWeaponDependancy(activeChar, false)) return true; return false; } public boolean checkCondition(L2Creature activeChar, L2Object target) { if (activeChar instanceof L2Player && ((L2Player) activeChar).isGM() && !Config.GM_SKILL_RESTRICTION) return true; Condition preCondition = _preCondition; if (preCondition == null) return true; Env env = new Env(); env.player = activeChar; if (target instanceof L2Creature) env.target = (L2Creature) target; env.skill = this; if (preCondition.test(env)) return true; if (activeChar instanceof L2Player) preCondition.sendMessage((L2Player) activeChar, this); return false; } public final L2Creature[] getTargetList(L2Creature activeChar, boolean onlyFirst) { return getTargetList(activeChar, onlyFirst, activeChar.getTarget(L2Creature.class)); } /** * 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 L2Player targeted, or on * the caster if it's a L2Player and no L2Player 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 L2Creature who use the skill */ public final L2Creature[] getTargetList(L2Creature activeChar, boolean onlyFirst, L2Creature target) { final List<L2Creature> targets = SkillTargetHandler.getInstance().getTargetList(activeChar, this, target); if (targets != null) return targets.toArray(new L2Creature[targets.size()]); ArrayBunch<L2Creature> targetList = new ArrayBunch<L2Creature>(); try { // 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 L2Creature targeted, or on the caster itself case TARGET_ONE: { // automatically selects caster if no target is selected (only positive skills) if (isPositive() && target == null) target = activeChar; boolean canTargetSelf = false; switch (skillType) { case BUFF: case HEAL: case HOT: case HEAL_PERCENT: case MANARECHARGE: case MANAHEAL: case RECOVER: case NEGATE: case CANCEL: case CANCEL_DEBUFF: case REFLECT: case COMBATPOINTHEAL: case CPHEAL_PERCENT: 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(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (!GeoData.getInstance().canSeeTarget(activeChar, target)) return null; return new L2Creature[] { target }; } case TARGET_SELF: case TARGET_GROUND: { return new L2Creature[] { activeChar }; } /* * case TARGET_BOSS: { L2MinionInstance Minion = null; * Minion = (L2MinionInstance)target; if (activeChar * instanceof L2MinionInstance) return new * L2Creature[]{target}; } */ case TARGET_HOLY: { if (activeChar instanceof L2Player) { if (target instanceof L2ArtefactInstance) return new L2Creature[] { target }; } return null; } case TARGET_FLAGPOLE: { return new L2Creature[] { activeChar }; } case TARGET_COUPLE: { if (target != null && target instanceof L2Player) { int _chaid = activeChar.getObjectId(); int targetId = target.getObjectId(); for (Couple cl : CoupleManager.getInstance().getCouples()) { if ((cl.getPlayer1Id() == _chaid && cl.getPlayer2Id() == targetId) || (cl.getPlayer2Id() == _chaid && cl.getPlayer1Id() == targetId)) return new L2Creature[] { target }; } } return null; } case TARGET_PET: { target = activeChar.getPet(); if (target != null && !target.isDead()) return new L2Creature[] { target }; return null; } case TARGET_SUMMON: { target = activeChar.getPet(); if (target != null && !target.isDead() && target instanceof L2SummonInstance) return new L2Creature[] { target }; return null; } case TARGET_OWNER_PET: { if (activeChar instanceof L2Summon) { target = ((L2Summon) activeChar).getOwner(); if (target != null && !target.isDead()) return new L2Creature[] { target }; } return null; } case TARGET_ENEMY_PET: { if (target != null && target instanceof L2Summon) { L2Summon targetPet = null; targetPet = (L2Summon) target; if (activeChar instanceof L2Player && activeChar.getPet() != targetPet && !targetPet.isDead() && targetPet.getOwner().getPvpFlag() != 0) { return new L2Creature[] { target }; } } return null; } case TARGET_CORPSE_PET: { if (activeChar instanceof L2Player) { target = activeChar.getPet(); if (target != null && target.isDead()) { return new L2Creature[] { target }; } } return null; } case TARGET_AURA: case TARGET_SERVITOR_AURA: { int radius = getSkillRadius(); boolean srcInPvP = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); L2Player src = activeChar.getActingPlayer(); // Go through the L2Creature _knownList for (L2Creature cha : activeChar.getKnownList().getKnownCharactersInRadius(radius)) { if (cha instanceof L2Attackable || cha instanceof L2Playable) { boolean targetInPvP = cha.isInsideZone(L2Zone.FLAG_PVP) && !cha.isInsideZone(L2Zone.FLAG_SIEGE); // Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met if (cha == activeChar || cha == src || cha.isDead()) continue; if (src != null) { // check if both attacker and target are L2Players and if they are in same party if (cha instanceof L2Player) { L2Player player = (L2Player) cha; if (!src.checkPvpSkill(cha, this)) continue; if ((src.getParty() != null && player.getParty() != null) && src.getParty() .getPartyLeaderOID() == player.getParty().getPartyLeaderOID()) continue; if (!srcInPvP && !targetInPvP) { if (src.getAllyId() == player.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == player.getClanId()) continue; } } else if (cha instanceof L2Summon) { L2Player trg = ((L2Summon) cha).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 (!srcInPvP && !targetInPvP) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2Playable { if (!(cha instanceof L2Playable) // Target is not L2Playable && !activeChar.isConfused()) // and caster not confused (?) continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, cha)) continue; if (!onlyFirst) targetList.add(cha); else return new L2Creature[] { cha }; } } return targetList.moveToArray(new L2Creature[targetList.size()]); } // [L2J_JP ADD SANDMAN] // case TARGET_AURA: /* * case TARGET_AREA: { return getAreaTargetList(activeChar); * } */ case TARGET_MULTIFACE: { return getMultiFaceTargetList(activeChar); } case TARGET_FRONT_AURA: { int radius = getSkillRadius(); boolean srcInArena = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); L2Player src = activeChar.getActingPlayer(); // Go through the L2Creature _knownList for (L2Creature cha : activeChar.getKnownList().getKnownCharactersInRadius(radius)) { if (cha instanceof L2Attackable || cha instanceof L2Playable) { // Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met if (cha == activeChar || cha == src || cha.isDead()) continue; if (src != null) { if (!cha.isInFrontOf(activeChar)) continue; boolean objInPvpZone = cha.isInsideZone(L2Zone.FLAG_PVP) && !cha.isInsideZone(L2Zone.FLAG_SIEGE); // check if both attacker and target are L2Players and if they are in same party if (cha instanceof L2Player) { L2Player player = (L2Player) cha; if (!src.checkPvpSkill(cha, this)) continue; if ((src.getParty() != null && player.getParty() != null) && src.getParty() .getPartyLeaderOID() == player.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !objInPvpZone) { if (src.getAllyId() == player.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == player.getClanId()) continue; } } if (cha instanceof L2Summon) { L2Player trg = ((L2Summon) cha).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 && !objInPvpZone) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2Playable { if (!(cha instanceof L2Playable) // Target is not L2Playable && !activeChar.isConfused()) // and caster not confused (?) continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, cha)) continue; if (!onlyFirst) targetList.add(cha); else return new L2Creature[] { cha }; } } return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_BEHIND_AURA: { int radius = getSkillRadius(); boolean srcInArena = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); L2Player src = activeChar.getActingPlayer(); // Go through the L2Creature _knownList for (L2Creature cha : activeChar.getKnownList().getKnownCharactersInRadius(radius)) { if (cha instanceof L2Attackable || cha instanceof L2Playable) { // Don't add this target if this is a Pc->Pc pvp casting and pvp condition not met if (cha == activeChar || cha == src || cha.isDead()) continue; if (src != null) { if (!cha.isBehind(activeChar)) continue; boolean objInPvpZone = cha.isInsideZone(L2Zone.FLAG_PVP) && !cha.isInsideZone(L2Zone.FLAG_SIEGE); // check if both attacker and target are L2Players and if they are in same party if (cha instanceof L2Player) { L2Player player = (L2Player) cha; if (!src.checkPvpSkill(cha, this)) continue; if ((src.getParty() != null && player.getParty() != null) && src.getParty() .getPartyLeaderOID() == player.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !objInPvpZone) { if (src.getAllyId() == player.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == player.getClanId()) continue; } } if (cha instanceof L2Summon) { L2Player trg = ((L2Summon) cha).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 && !objInPvpZone) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (src.getClanId() != 0 && src.getClanId() == trg.getClanId()) continue; } } } else // Skill user is not L2Playable { if (!(cha instanceof L2Playable) // Target is not L2Playable && !activeChar.isConfused()) // and caster not confused (?) continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, cha)) continue; if (!onlyFirst) targetList.add(cha); else return new L2Creature[] { cha }; } } return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target is not L2Attackable or L2Playable (getCastRange() >= 0 && (target == activeChar || target.isAlikeDead()))) // target is null or self or dead/faking { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } L2Creature cha; if (getCastRange() >= 0) { cha = target; if (!onlyFirst) targetList.add(cha); // Add target to target list else return new L2Creature[] { cha }; } else cha = activeChar; boolean effectOriginIsL2Playable = (cha instanceof L2Playable); boolean srcIsSummon = (activeChar instanceof L2Summon); L2Player src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInPvP = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; if (obj == cha) continue; target = (L2Creature) obj; boolean targetInPvP = target.isInsideZone(L2Zone.FLAG_PVP) && !target.isInsideZone(L2Zone.FLAG_SIEGE); if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, obj, cha, true)) continue; if (src != null) // caster is L2Playable and exists { if (obj instanceof L2Player) { L2Player trg = (L2Player) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; if (!srcInPvP && !targetInPvP) { 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) { L2Player trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInPvP && !targetInPvP) { 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 (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; } } else // Skill user is not L2Playable { if (effectOriginIsL2Playable && // If effect starts at L2Playable and !(obj instanceof L2Playable)) // Object is not L2Playable continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; targetList.add(target); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_FRONT_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target is not L2Attackable or L2Playable (getCastRange() >= 0 && (target == activeChar || target.isAlikeDead()))) //target is null or self or dead/faking { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } L2Creature cha; if (getCastRange() >= 0) { cha = target; if (!onlyFirst) targetList.add(cha); // Add target to target list else return new L2Creature[] { cha }; } else cha = activeChar; boolean effectOriginIsL2Playable = (cha instanceof L2Playable); L2Player src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInArena = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj == cha) continue; if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; target = (L2Creature) obj; if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, target, activeChar, true)) continue; if (!target.isInFrontOf(activeChar)) continue; if (src != null) // caster is L2Playable and exists { boolean targetInPvP = target.isInsideZone(L2Zone.FLAG_PVP) && !target.isInsideZone(L2Zone.FLAG_SIEGE); if (obj instanceof L2Player) { L2Player trg = (L2Player) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; if (!srcInArena && !targetInPvP) { 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) { L2Player trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !targetInPvP) { 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 (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; } } else // Skill user is not L2Playable { if (effectOriginIsL2Playable && // If effect starts at L2Playable and !(obj instanceof L2Playable)) // Object is not L2Playable continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; targetList.add(target); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_BEHIND_AREA: { if ((!(target instanceof L2Attackable || target instanceof L2Playable)) || // Target is not L2Attackable or L2Playable (getCastRange() >= 0 && (target == activeChar || target.isAlikeDead()))) //target is null or self or dead/faking { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } L2Creature cha; if (getCastRange() >= 0) { cha = target; if (!onlyFirst) targetList.add(cha); // Add target to target list else return new L2Creature[] { cha }; } else cha = activeChar; boolean effectOriginIsL2Playable = (cha instanceof L2Playable); L2Player src = activeChar.getActingPlayer(); int radius = getSkillRadius(); boolean srcInArena = activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE); for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj == cha) continue; if (!(obj instanceof L2Attackable || obj instanceof L2Playable)) continue; target = (L2Creature) obj; if (!target.isDead() && (target != activeChar)) { if (!Util.checkIfInRange(radius, obj, activeChar, true)) continue; if (!target.isBehind(activeChar)) continue; if (src != null) // caster is L2Playable and exists { boolean targetInPvP = target.isInsideZone(L2Zone.FLAG_PVP) && !target.isInsideZone(L2Zone.FLAG_SIEGE); if (obj instanceof L2Player) { L2Player trg = (L2Player) obj; if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; if (!srcInArena && !targetInPvP) { 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) { L2Player trg = ((L2Summon) obj).getOwner(); if (trg == src) continue; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (!srcInArena && !targetInPvP) { if (src.getAllyId() == trg.getAllyId() && src.getAllyId() != 0) continue; if (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; if (src.getClan() != null && trg.getClan() != null) { if (src.getClan().getClanId() == trg.getClan().getClanId()) continue; } if (!src.checkPvpSkill(trg, this)) continue; } } } else // Skill user is not L2Playable { // If effect starts at L2Playable and object is not L2Playable if (effectOriginIsL2Playable && !(obj instanceof L2Playable)) continue; } if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; targetList.add(target); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_AREA_UNDEAD: { L2Creature cha; int radius = getSkillRadius(); if (getCastRange() >= 0 && (target instanceof L2Npc || target instanceof L2SummonInstance) && target.isUndead() && !target.isAlikeDead()) { cha = target; if (!onlyFirst) targetList.add(cha); // Add target to target list else return new L2Creature[] { cha }; } else cha = activeChar; for (L2Object obj : cha.getKnownList().getKnownObjects().values()) { if (obj instanceof L2Npc) target = (L2Npc) obj; else if (obj instanceof L2SummonInstance) target = (L2SummonInstance) obj; else 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)) // Go to next obj if obj isn't in range continue; if (!GeoData.getInstance().canSeeTarget(activeChar, target)) continue; if (!onlyFirst) targetList.add((L2Creature) obj); // Add obj to target lists else return new L2Creature[] { (L2Creature) obj }; } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_PARTY: { if (onlyFirst) return new L2Creature[] { activeChar }; targetList.add(activeChar); L2Player player = null; if (activeChar instanceof L2Summon) { player = ((L2Summon) activeChar).getOwner(); targetList.add(player); } else if (activeChar instanceof L2Player) { player = (L2Player) activeChar; if (activeChar.getPet() != null) targetList.add(activeChar.getPet()); } if (activeChar.getParty() != null) { // Get all visible objects in a spheric area near the L2Creature // Get a list of Party Members List<L2Player> partyList = activeChar.getParty().getPartyMembers(); for (L2Player partyMember : partyList) { if (player == null || partyMember == null || partyMember == player) continue; if (player.isInDuel() && player.getDuelId() != partyMember.getDuelId()) continue; if (!eventCheck(player, partyMember)) 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.moveToArray(new L2Creature[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 L2Player && target instanceof L2Summon && activeChar.getPet() == target) || (target != null && activeChar instanceof L2Summon && target instanceof L2Player && 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 L2Creature[] { target }; } return null; } activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } 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 L2Player) { L2Player player = (L2Player) target; switch (getId()) { // FORCE BUFFS may cancel here but there should be a proper condition case 426: if (!player.isMageClass()) return new L2Creature[] { target }; return null; case 427: if (player.isMageClass()) return new L2Creature[] { target }; return null; } } return new L2Creature[] { target }; } return null; } activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } case TARGET_PARTY_CLAN: { if (onlyFirst) return new L2Creature[] { activeChar }; final L2Player player = activeChar.getActingPlayer(); if (player == null) return null; targetList.add(player); final int radius = getSkillRadius(); final boolean hasClan = player.getClan() != null; final boolean hasParty = player.isInParty(); if (addSummon(activeChar, player, radius, false)) targetList.add(player.getPet()); // if player in olympiad mode or not in clan and not in party if (player.isInOlympiadMode() || !(hasClan || hasParty)) return new L2Creature[] { player }; for (L2Player obj : activeChar.getKnownList().getKnownPlayersInRadius(radius)) { if (obj == null) continue; if (player.isInDuel()) { if (player.getDuelId() != obj.getDuelId()) continue; if (hasParty && obj.isInParty() && player.getParty().getPartyLeaderOID() != obj.getParty().getPartyLeaderOID()) continue; } if (!((hasClan && obj.getClanId() == player.getClanId()) || (hasParty && obj.isInParty() && player.getParty().getPartyLeaderOID() == obj.getParty().getPartyLeaderOID()))) continue; // Don't add this target if this is a Pc->Pc pvp // casting and pvp condition not met if (!player.checkPvpSkill(obj, this)) continue; if (!eventCheck(player, obj)) continue; if (!onlyFirst && addSummon(activeChar, obj, radius, false)) targetList.add(obj.getPet()); if (!addCharacter(activeChar, obj, radius, false)) continue; if (onlyFirst) return new L2Creature[] { obj }; targetList.add(obj); } return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_CORPSE_ALLY: case TARGET_ALLY: { if (activeChar instanceof L2Playable) { int radius = getSkillRadius(); L2Player player = activeChar.getActingPlayer(); if (player == null) return null; L2Clan clan = player.getClan(); if (player.isInOlympiadMode()) { if (player.getPet() == null) return new L2Creature[] { player }; return new L2Creature[] { player, player.getPet() }; } if (targetType != SkillTargetType.TARGET_CORPSE_ALLY) { if (!onlyFirst) targetList.add(player); else return new L2Creature[] { 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 spheric area near the L2Creature // Get Clan Members for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj == player || !(obj instanceof L2Playable) || obj.getActingPlayer() == null) continue; L2Player newTarget = obj.getActingPlayer(); if ((newTarget.getAllyId() == 0 || newTarget.getAllyId() != player.getAllyId()) && (newTarget.getClan() == null || newTarget.getClanId() != player.getClanId())) continue; if (player.isInDuel() && (player.getDuelId() != newTarget.getDuelId() || (player.getParty() != null && player.getParty() != newTarget.getParty()))) continue; if (!eventCheck(player, newTarget)) continue; L2Summon pet = newTarget.getPet(); if (pet != null && Util.checkIfInRange(radius, activeChar, pet, true) && !onlyFirst && ((targetType == SkillTargetType.TARGET_CORPSE_ALLY && pet.isDead()) || (targetType == SkillTargetType.TARGET_ALLY && !pet.isDead())) && player.checkPvpSkill(newTarget, this)) targetList.add(pet); if (targetType == SkillTargetType.TARGET_CORPSE_ALLY) { if (!newTarget.isDead()) continue; // Siege battlefield resurrect has been made possible for participants if (getSkillType() == L2SkillType.RESURRECT) { if (newTarget.isInsideZone(L2Zone.FLAG_SIEGE) && !newTarget.isInSiege()) 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) targetList.add(newTarget); return new L2Creature[] { newTarget }; } } } return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_ENEMY_ALLY: { // int charX, charY, charZ, targetX, targetY, targetZ, dx, dy, dz; int radius = getSkillRadius(); L2Creature newTarget; if (getCastRange() > -1 && target != null) { newTarget = target; } else newTarget = activeChar; if (newTarget != activeChar || isOffensive()) targetList.add(newTarget); for (L2Creature obj : activeChar.getKnownList().getKnownCharactersInRadius(radius)) { if (obj == newTarget || obj == activeChar) continue; if (obj instanceof L2Attackable) { if (!obj.isAlikeDead()) { // Don't add this target if this is a PC->PC pvp casting and pvp condition not met if (activeChar instanceof L2Player && !((L2Player) activeChar).checkPvpSkill(obj, this)) continue; // check if both attacker and target are L2Players and if they are in same party or clan if ((activeChar instanceof L2Player && obj instanceof L2Player) && (((L2Player) activeChar).getClanId() != ((L2Player) obj).getClanId() || (((L2Player) activeChar).getAllyId() != ((L2Player) obj).getAllyId() && ((activeChar.getParty() != null && obj.getParty() != null) && activeChar.getParty().getPartyLeaderOID() != obj .getParty().getPartyLeaderOID())))) continue; targetList.add(obj); } } } //FIXME: (Noctarius) Added return here to deny fallthrough - is it wished to add more targets? return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_CORPSE_CLAN: case TARGET_CLAN: { if (activeChar instanceof L2Playable) { int radius = getSkillRadius(); L2Player player = activeChar.getActingPlayer(); if (player == null) return null; L2Clan clan = player.getClan(); if (player.isInOlympiadMode()) { if (player.getPet() == null) return new L2Creature[] { player }; return new L2Creature[] { player, player.getPet() }; } if (targetType != SkillTargetType.TARGET_CORPSE_CLAN) { if (!onlyFirst) targetList.add(player); else return new L2Creature[] { 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 L2Creature // Get Clan Members for (L2ClanMember member : clan.getMembers()) { L2Player newTarget = member.getPlayerInstance(); if (newTarget == null || newTarget == player) continue; if (player.isInDuel() && (player.getDuelId() != newTarget.getDuelId() || (player.getParty() == null && player.getParty() != newTarget.getParty()))) continue; if (!eventCheck(player, newTarget)) continue; L2Summon pet = newTarget.getPet(); if (pet != null && Util.checkIfInRange(radius, activeChar, pet, true) && !onlyFirst && ((targetType == SkillTargetType.TARGET_CORPSE_CLAN && pet.isDead()) || (targetType == SkillTargetType.TARGET_CLAN && !pet.isDead())) && player.checkPvpSkill(newTarget, this)) targetList.add(pet); if (targetType == SkillTargetType.TARGET_CORPSE_CLAN) { if (!newTarget.isDead()) continue; if (getSkillType() == L2SkillType.RESURRECT) { // check for charm of courage and caster being a siege participant, otherwise do not allow resurrection // on siege battlefield Siege siege = SiegeManager.getInstance().getSiege(newTarget); if (siege != null && siege.getIsInProgress()) { // could/should be a more accurate check for siege clans if (!newTarget.getCharmOfCourage() || player.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) targetList.add(newTarget); else return new L2Creature[] { newTarget }; } } } else if (activeChar instanceof L2Npc) { // for buff purposes, returns one unbuffed friendly mob nearby or mob itself? L2Npc npc = (L2Npc) activeChar; for (L2Object newTarget : activeChar.getKnownList().getKnownObjects().values()) { 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.moveToArray(new L2Creature[targetList.size()]); } case TARGET_CORPSE_PLAYER: { if (target != null && target.isDead()) { L2Player player = null; if (activeChar instanceof L2Player) player = (L2Player) activeChar; L2Player targetPlayer = null; if (target instanceof L2Player) targetPlayer = (L2Player) 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 Siege siege = null; if (targetPlayer != null) siege = SiegeManager.getInstance().getSiege(targetPlayer); else if (targetPet != null) siege = SiegeManager.getInstance().getSiege(targetPet); if (siege != null && siege.getIsInProgress() && targetPlayer != null && (!targetPlayer.getCharmOfCourage() || player.getSiegeState() == 0)) { condGood = false; player.sendPacket(SystemMessageId.CANNOT_BE_RESURRECTED_DURING_SIEGE); } if (targetPlayer != null) { if (targetPlayer.isFestivalParticipant()) // Check to see if the current player target is in a festival. { condGood = false; player.sendMessage("You may not resurrect participants in a festival."); } if (targetPlayer.isReviveRequested()) { player.sendPacket(SystemMessageId.RES_HAS_ALREADY_BEEN_PROPOSED); // Resurrection is already been // proposed. condGood = false; } } else if (targetPet != null) { if (targetPet.getOwner() != player) { if (targetPet.getOwner().isPetReviveRequested()) { player.sendPacket(SystemMessageId.CANNOT_RES_PET2); // A pet cannot be resurrected while it's owner is in the process of resurrecting. condGood = false; } } } } if (condGood) { if (!onlyFirst) { targetList.add(target); return targetList.moveToArray(new L2Creature[targetList.size()]); } return new L2Creature[] { target }; } } } activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } case TARGET_CORPSE_MOB: { if (!(target instanceof L2Attackable) || !target.isDead()) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } // Corpse mob only available for half time switch (getSkillType()) { case DRAIN: case SUMMON: { if (DecayTaskManager.getInstance().hasDecayTask(target)) { if (DecayTaskManager.getInstance().getRemainingDecayTime(target) < 0.5) { activeChar.sendPacket(SystemMessageId.CORPSE_TOO_OLD_SKILL_NOT_USED); return null; } } } } if (!onlyFirst) { targetList.add(target); return targetList.moveToArray(new L2Creature[targetList.size()]); } return new L2Creature[] { target }; } case TARGET_AREA_CORPSE_MOB: { if (!((target instanceof L2Attackable) || (target instanceof L2SummonInstance)) || !target.isDead()) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (!onlyFirst) targetList.add(target); else return new L2Creature[] { target }; boolean srcInArena = (activeChar.isInsideZone(L2Zone.FLAG_PVP) && !activeChar.isInsideZone(L2Zone.FLAG_SIEGE)); L2Player src = null; if (activeChar instanceof L2Player) src = (L2Player) activeChar; L2Player trg = null; int radius = getSkillRadius(); for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(obj instanceof L2Attackable || obj instanceof L2Playable) || ((L2Creature) obj).isDead() || obj == activeChar) continue; boolean targetInPvP = ((L2Creature) obj).isInsideZone(L2Zone.FLAG_PVP) && !((L2Creature) obj).isInsideZone(L2Zone.FLAG_SIEGE); if (!Util.checkIfInRange(radius, target, obj, true)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, obj)) continue; if (obj instanceof L2Player && src != null) { trg = (L2Player) obj; if ((src.getParty() != null && trg.getParty() != null) && src.getParty().getPartyLeaderOID() == trg.getParty().getPartyLeaderOID()) continue; if (trg.isInsideZone(L2Zone.FLAG_PEACE)) continue; if (!srcInArena && !targetInPvP) { 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 && !targetInPvP) { 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(L2Zone.FLAG_PEACE)) continue; } targetList.add((L2Creature) obj); } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_AREA_CORPSES: { if (!(target instanceof L2Attackable) || !target.isDead()) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (!onlyFirst) targetList.add(target); else return new L2Creature[] { target }; int radius = getSkillRadius(); if (activeChar.getKnownList() != null) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj == null || !(obj instanceof L2Attackable)) continue; L2Creature cha = (L2Creature) obj; if (!cha.isDead() || !Util.checkIfInRange(radius, target, cha, true)) continue; if (!GeoData.getInstance().canSeeTarget(activeChar, cha)) continue; targetList.add(cha); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_UNLOCKABLE: { if (!(target instanceof L2DoorInstance) && !(target instanceof L2ChestInstance)) { // activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (!onlyFirst) { targetList.add(target); return targetList.moveToArray(new L2Creature[targetList.size()]); } return new L2Creature[] { target }; } case TARGET_ENEMY_SUMMON: { if (target instanceof L2Summon) { L2Summon targetSummon = (L2Summon) target; if (activeChar instanceof L2Player && activeChar.getPet() != targetSummon && !targetSummon.isDead() && (targetSummon.getOwner().getPvpFlag() != 0 || targetSummon.getOwner().getKarma() > 0) || (targetSummon.getOwner().isInsideZone(L2Zone.FLAG_PVP) && activeChar.isInsideZone(L2Zone.FLAG_PVP))) return new L2Creature[] { targetSummon }; } return null; } case TARGET_GATE: { // Check for null target or any other invalid target if (target == null || target.isDead() || !(target instanceof L2DoorInstance)) { activeChar.sendPacket(SystemMessageId.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 L2Creature[] { target }; } case TARGET_MOB: { // Check for null target or any other invalid target if (target == null || target.isDead() || !(target instanceof L2Attackable)) { activeChar.sendPacket(SystemMessageId.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 L2Creature[] { target }; } case TARGET_KNOWNLIST: { if (target != null && target.getKnownList() != null) for (L2Object obj : target.getKnownList().getKnownObjects().values()) { if (obj instanceof L2Attackable || obj instanceof L2Playable) return new L2Creature[] { (L2Creature) obj }; } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } case TARGET_INITIATOR: if (target != null) return new L2Creature[] { target }; else return null; default: { if (activeChar instanceof L2Player || _log.isDebugEnabled()) // normally log only player skills errors _log.error("Target type of skill Id " + _id + " is not implemented."); return null; } }// end switch } finally { targetList.clear(); } } /* // [L2J_JP ADD SANDMAN START] public final L2Creature[] getAreaTargetList(L2Creature activeChar) { ArrayBunch<L2Creature> targetList = new ArrayBunch<L2Creature>(); L2Object target; L2Player tgOwner; L2Clan acClan; L2Clan tgClan; L2Party acPt = activeChar.getParty(); int radius = getSkillRadius(); if (getCastRange() <= 0 || (getTargetType() == SkillTargetType.TARGET_AURA)) target = activeChar; else target = activeChar.getTarget(); if (target == null || !(target instanceof L2Creature)) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if ((getTargetType() == SkillTargetType.TARGET_AREA) && (target.getObjectId() != activeChar.getObjectId())) { if (!((L2Creature) target).isAlikeDead()) targetList.add((L2Creature) target); else { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } } if (!(activeChar instanceof L2Playable)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj instanceof L2Playable) { if (!(Util.checkIfInRange(radius, target, obj, true))) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } if (activeChar instanceof L2Player) acClan = ((L2Player) activeChar).getClan(); else if (activeChar instanceof L2Summon) acClan = ((L2Summon) activeChar).getOwner().getClan(); else { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (activeChar.isInsideZone(L2Zone.FLAG_SIEGE)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(Util.checkIfInRange(radius, target, obj, true))) continue; if (obj instanceof L2Player) { tgClan = ((L2Player) obj).getClan(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(obj)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (tgClan != null) { if (tgClan.getClanId() == acClan.getClanId()) continue; else if (tgClan.getAllyId() == acClan.getAllyId()) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Summon) { tgOwner = ((L2Summon) obj).getOwner(); tgClan = tgOwner.getClan(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(tgOwner)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (tgClan != null) { if (tgClan.getClanId() == acClan.getClanId()) continue; else if (tgClan.getAllyId() == acClan.getAllyId()) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Attackable) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else { continue; } } } else if (activeChar.isInsideZone(L2Zone.FLAG_STADIUM) || activeChar.isInsideZone(L2Zone.FLAG_PVP) || FourSepulchersManager.getInstance().checkIfInZone(activeChar)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(Util.checkIfInRange(radius, target, obj, true))) continue; if (obj instanceof L2Player) { if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(obj)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Summon) { tgOwner = ((L2Summon) obj).getOwner(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(tgOwner)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Attackable) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else { continue; } } } else { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(Util.checkIfInRange(radius, target, obj, true))) continue; if (obj instanceof L2MonsterInstance) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } } } if (targetList.size() == 0) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } return targetList.moveToArray(new L2Creature[targetList.size()]); } */ public final L2Creature[] getMultiFaceTargetList(L2Creature activeChar) { ArrayBunch<L2Creature> targetList = new ArrayBunch<L2Creature>(); L2Object target; L2Object FirstTarget; L2Player tgOwner; L2Clan acClan; L2Clan tgClan; L2Party acPt = activeChar.getParty(); int radius = getSkillRadius(); if (getCastRange() <= 0) target = activeChar; else target = activeChar.getTarget(); FirstTarget = target; if (target == null || !(target instanceof L2Creature)) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } int newHeading = getNewHeadingToTarget(activeChar, (L2Creature) target); if (target.getObjectId() != activeChar.getObjectId()) { if (!((L2Creature) target).isAlikeDead()) targetList.add((L2Creature) target); else { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } } if (!(activeChar instanceof L2Playable)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (obj instanceof L2Playable) { if (!(Util.checkIfInRange(radius, target, obj, true))) continue; else if (isBehindFromCaster(newHeading, (L2Creature) FirstTarget, (L2Creature) target)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } } if (targetList.size() == 0) return null; return targetList.moveToArray(new L2Creature[targetList.size()]); } if (activeChar.getActingPlayer() != null) acClan = activeChar.getActingPlayer().getClan(); else { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } if (activeChar.isInsideZone(L2Zone.FLAG_SIEGE)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(obj instanceof L2Playable)) continue; if (!(Util.checkIfInRange(radius, target, obj, true))) continue; else if (isBehindFromCaster(newHeading, (L2Creature) FirstTarget, (L2Creature) obj)) continue; if (obj instanceof L2Player) { tgClan = ((L2Player) obj).getClan(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(obj)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (tgClan != null) { if (tgClan.getClanId() == acClan.getClanId()) continue; else if (tgClan.getAllyId() == acClan.getAllyId()) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Summon) { tgOwner = ((L2Summon) obj).getOwner(); tgClan = tgOwner.getClan(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(tgOwner)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (tgClan != null) { if (tgClan.getClanId() == acClan.getClanId()) continue; else if (tgClan.getAllyId() == acClan.getAllyId()) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Attackable) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else { continue; } } } else if (activeChar.isInsideZone(L2Zone.FLAG_STADIUM) || activeChar.isInsideZone(L2Zone.FLAG_PVP) || FourSepulchersManager.getInstance().checkIfInZone(activeChar)) { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(obj instanceof L2Playable)) continue; if (!(Util.checkIfInRange(radius, target, obj, true))) continue; else if (isBehindFromCaster(newHeading, (L2Creature) FirstTarget, (L2Creature) obj)) continue; if (obj instanceof L2Player) { if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(obj)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Summon) { tgOwner = ((L2Summon) obj).getOwner(); if (acPt != null) { if (activeChar.getParty().getPartyMembers().contains(tgOwner)) continue; else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else if (obj instanceof L2Attackable) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } else { continue; } } } else { for (L2Object obj : activeChar.getKnownList().getKnownObjects().values()) { if (!(obj instanceof L2Playable)) continue; if (!(Util.checkIfInRange(radius, target, obj, true))) continue; else if (isBehindFromCaster(newHeading, (L2Creature) FirstTarget, (L2Creature) obj)) continue; if (obj instanceof L2MonsterInstance) { if (!((L2Creature) obj).isAlikeDead()) targetList.add((L2Creature) obj); } } } if (targetList.size() == 0) { activeChar.sendPacket(SystemMessageId.TARGET_IS_INCORRECT); return null; } return targetList.moveToArray(new L2Creature[targetList.size()]); } public static final boolean addSummon(L2Creature caster, L2Player owner, int radius, boolean isDead) { final L2Summon summon = owner.getPet(); if (summon == null) return false; return addCharacter(caster, summon, radius, isDead); } public static final boolean addCharacter(L2Creature caster, L2Creature target, int radius, boolean isDead) { if (isDead != target.isDead()) return false; if (radius > 0 && !Util.checkIfInRange(radius, caster, target, true)) return false; return true; } private boolean eventCheck(L2Player player, L2Player newTarget) { if (GlobalRestrictions.isProtected(player, newTarget, this, false)) return false; return true; } private int getNewHeadingToTarget(L2Creature caster, L2Creature target) { if (caster == null || target == null) return 0; double befHeading = Util.convertHeadingToDegree(caster.getHeading()); if (befHeading > 360) befHeading -= 360; int dx = caster.getX() - target.getX(); int dy = caster.getY() - target.getY(); double dist = Math.sqrt(dx * dx + dy * dy); if (dist == 0) dist = 0.01; double sin = dy / dist; double cos = dx / dist; int heading = (int) (Math.atan2(-sin, -cos) * 10430.378350470452724949566316381); return heading; } public final boolean isBehindFromCaster(int heading, L2Creature caster, L2Creature target) { if (caster == null || target == null) return true; double befHeading = Util.convertHeadingToDegree(heading); if (befHeading > 360) befHeading -= 360; else if (befHeading < 0) befHeading += 360; int dx = caster.getX() - target.getX(); int dy = caster.getY() - target.getY(); double dist = Math.sqrt(dx * dx + dy * dy); if (dist == 0) dist = 0.01; double sin = dy / dist; double cos = dx / dist; int newheading = (int) (Math.atan2(-sin, -cos) * 10430.378350470452724949566316381); double aftHeading = Util.convertHeadingToDegree(newheading); if (aftHeading > 360) aftHeading -= 360; else if (aftHeading < 0) aftHeading += 360; double diffHeading = Math.abs(aftHeading - befHeading); if (diffHeading > 360) diffHeading -= 360; else if (diffHeading < 0) diffHeading += 360; return (diffHeading > 90) && (diffHeading < 270); } // [L2J_JP ADD SANDMAN END] public final L2Creature[] getTargetList(L2Creature activeChar) { return getTargetList(activeChar, false); } public final L2Creature getFirstOfTargetList(L2Creature activeChar) { return getFirstOfTargetList(activeChar, null); } public final L2Creature getFirstOfTargetList(L2Creature activeChar, L2Creature[] targets) { switch (getTargetType()) { case TARGET_SELF: case TARGET_PARTY: case TARGET_PARTY_CLAN: case TARGET_CLAN: case TARGET_ALLY: case TARGET_ENEMY_ALLY: case TARGET_AURA: case TARGET_FRONT_AURA: case TARGET_BEHIND_AURA: case TARGET_GROUND: return activeChar; case TARGET_PET: case TARGET_SUMMON: case TARGET_SERVITOR_AURA: return activeChar.getActingSummon(); case TARGET_OWNER_PET: return activeChar.getActingPlayer(); } if (targets == null) targets = getTargetList(activeChar, true); return targets == null || targets.length == 0 ? null : targets[0]; } private Func[] _statFuncs; public final Func[] getStatFuncs(L2Creature player) { if (!(player instanceof L2Playable) && !(player instanceof L2Attackable)) return Func.EMPTY_ARRAY; if (_statFuncs == null) { if (_funcTemplates == null) { _statFuncs = Func.EMPTY_ARRAY; } else { final Func[] funcs = new Func[_funcTemplates.length]; for (int i = 0; i < _funcTemplates.length; i++) funcs[i] = _funcTemplates[i].getFunc(this); _statFuncs = L2Arrays.compact(funcs); } } return _statFuncs; } public final boolean hasEffects() { return _effectTemplates != null && _effectTemplates.length > 0; } public final boolean hasSelfEffects() { return _effectTemplatesSelf != null && _effectTemplatesSelf.length > 0; } public final void dealDamage(L2Creature activeChar, L2Creature target, L2Skill skill, double damage, byte reflect, boolean mcrit, boolean pcrit) { activeChar.sendDamageMessage(target, (int) damage, mcrit, pcrit, false); if (skill.getDmgDirectlyToHP()) { double actCp1 = target.getStatus().getCurrentCp(); target.getStatus().setCurrentCp(0); target.reduceCurrentHp(damage, activeChar, skill); target.getStatus().setCurrentCp(actCp1); // vengeance reflected damage if ((reflect & Formulas.SKILL_REFLECT_VENGEANCE) != 0) { double actCp2 = activeChar.getStatus().getCurrentCp(); activeChar.getStatus().setCurrentCp(0); activeChar.reduceCurrentHp(damage, target, skill); activeChar.getStatus().setCurrentCp(actCp2); } } else { target.reduceCurrentHp(damage, activeChar, skill); // vengeance reflected damage if ((reflect & Formulas.SKILL_REFLECT_VENGEANCE) != 0) activeChar.reduceCurrentHp(damage, target, skill); } // Manage attack or cast break of the target (calculating rate, sending message...) if (!target.isRaid() && Formulas.calcAtkBreak(target, damage)) { target.breakAttack(); target.breakCast(); } } public final void getEffects(L2Creature effector, L2Creature effected, byte reflect, byte shld, boolean ss, boolean sps, boolean bss) { if (_effectTemplates == null) return; if (!GlobalRestrictions.canCreateEffect(effector, effected, this)) return; // Activate attacked effects, if any if (Formulas.calcSkillSuccess(effector, effected, this, shld, ss, sps, bss)) { if ((reflect & Formulas.SKILL_REFLECT_SUCCEED) != 0) effected = effector; Env env = new Env(); env.player = effector; env.target = effected; env.skill = this; env.skillMastery = Formulas.calcSkillMastery(effector, this); for (EffectTemplate et : _effectTemplates) et.getEffect(env); if (effected instanceof L2Player) { SystemMessage sm = new SystemMessage(SystemMessageId.YOU_FEEL_S1_EFFECT); sm.addSkillName(this); effected.getActingPlayer().sendPacket(sm); } } else { effector.sendResistedMyEffectMessage(effected, this); } } public final void getEffects(L2Creature effector, L2Creature effected) { getEffects(effector, effected, null); } public final void getEffects(L2Creature effector, L2Creature effected, ForEachExecutable<L2Effect> executable) { if (_effectTemplates == null) return; if (!GlobalRestrictions.canCreateEffect(effector, effected, this)) return; Env env = new Env(); env.player = effector; env.target = effected; env.skill = this; env.skillMastery = Formulas.calcSkillMastery(effector, this); for (EffectTemplate et : _effectTemplates) { final L2Effect e = et.getEffect(env); if (e != null) if (executable != null) executable.execute(e); } } public final void getEffects(L2CubicInstance effector, L2Creature effected) { if (_effectTemplates == null) return; if (!GlobalRestrictions.canCreateEffect(effector.getOwner(), effected, this)) return; Env env = new Env(); env.player = effector.getOwner(); //env.cubic = effector; env.target = effected; env.skill = this; for (EffectTemplate et : _effectTemplates) et.getEffect(env); } public final void getEffectsSelf(L2Creature effector) { if (_effectTemplatesSelf == null) return; if (!GlobalRestrictions.canCreateEffect(effector, effector, this)) return; Env env = new Env(); env.player = effector; env.target = effector; env.skill = this; for (EffectTemplate et : _effectTemplatesSelf) et.getEffect(env); } public final EffectTemplate[] getEffectTemplates() { return _effectTemplates; } 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 { // support for improved buffs, in case it gets overwritten in DP for (EffectTemplate template : _effectTemplates) if (template.merge(this, effect)) return; 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 { // support for improved buffs, in case it gets overwritten in DP for (EffectTemplate template : _effectTemplatesSelf) if (template.merge(this, effect)) return; 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) { Condition old = _preCondition; if (old != null) _log.fatal("Replaced " + old + " condition with " + c + " condition at skill: " + this); _preCondition = c; } @Override public final String toString() { return _name + "[id=" + _id + ",lvl=" + _level + "]"; } public final String generateUniqueStackType() { int count = _effectTemplates == null ? 0 : _effectTemplates.length; count += _effectTemplatesSelf == null ? 0 : _effectTemplatesSelf.length; return _id + "-" + count; } public final float generateStackOrder() { return getLevel(); } @Override public final String getFuncOwnerName() { return getName(); } @Override public final L2Skill getFuncOwnerSkill() { return this; } /** * used for tracking item id in case that item consume cannot be used * * @return reference item id */ public final int getReferenceItemId() { return _refId; } /** * @return */ public final int getAfroColor() { return _afroId; } public final boolean is7Signs() { return (4360 < getId() && getId() < 4367); } public final boolean isBuff() { if (is7Signs()) // 7s buffs return false; // TODO: this is a so ugly hax switch (getSkillType().getRoot()) { case BUFF: case REFLECT: case HEAL_PERCENT: case MANAHEAL_PERCENT: case COMBATPOINTHEAL: return true; default: return false; } } public final boolean isHerbEffect() { return _isHerbEffect; } @Override public final boolean equals(Object obj) { if (!(obj instanceof L2Skill)) return false; L2Skill skill = (L2Skill) obj; return getId() == skill.getId() && getLevel() == skill.getLevel(); } @Override public final int hashCode() { return L2System.hash(SkillTable.getSkillUID(this)); } public final int getElementPower() { return _elementPower; } public final String getAttributeName() { return _attribute; } public final boolean ignoreShield() { return _ignoreShield; } public final boolean canBeReflected() { return _canBeReflected; } public boolean canBeDispeled() { return _canBeDispeled; } public boolean isDispeledOnAction() { return _dispelOnAction; } public boolean isDispeledOnAttack() { return _dispelOnAttack; } public final int getAfterEffectId() { return _afterEffectId; } public final int getAfterEffectLvl() { return _afterEffectLvl; } public final L2Skill getAfterEffectSkill() { return SkillTable.getInstance().getInfo(getAfterEffectId(), getAfterEffectLvl()); } public final boolean canSendToClient() { return _sendToClient; } public final float getPvpPowerMultiplier() { return _pvpPowerMulti; } @Override public final L2Skill getChanceTriggeredSkill(L2Creature activeChar, L2Creature evtInitiator) { if (!getWeaponDependancy(activeChar, false)) return null; if (!checkCondition(activeChar, evtInitiator)) return null; if (getTriggeredSkill() == null) return this; return getTriggeredSkill().getTriggeredSkill(); } @Override public final ChanceCondition getChanceCondition() { return _chanceCondition; } }