Package l2p.gameserver.model

Source Code of l2p.gameserver.model.L2Skill

package l2p.gameserver.model;

import l2p.Config;
import l2p.common.ThreadPoolManager;
import l2p.extensions.scripts.Functions;
import l2p.gameserver.ai.DefaultAI;
import l2p.gameserver.cache.Msg;
import l2p.gameserver.geodata.GeoEngine;
import l2p.gameserver.model.L2Zone.ZoneType;
import l2p.gameserver.model.base.ClassId;
import l2p.gameserver.model.entity.Duel;
import l2p.gameserver.model.entity.vehicle.L2AirShip;
import l2p.gameserver.model.entity.vehicle.L2Ship;
import l2p.gameserver.model.entity.vehicle.L2Vehicle;
import l2p.gameserver.model.instances.L2ChestInstance;
import l2p.gameserver.model.instances.L2ControlTowerInstance;
import l2p.gameserver.model.instances.L2DecoyInstance;
import l2p.gameserver.model.instances.L2MonsterInstance;
import l2p.gameserver.model.instances.L2StaticObjectInstance;
import l2p.gameserver.model.instances.L2TerritoryFlagInstance;
import l2p.gameserver.model.items.Inventory;
import l2p.gameserver.model.items.L2ItemInstance;
import l2p.gameserver.serverpackets.FlyToLocation.FlyType;
import l2p.gameserver.serverpackets.MagicSkillUse;
import l2p.gameserver.serverpackets.SystemMessage;
import l2p.gameserver.skills.EffectType;
import l2p.gameserver.skills.Env;
import l2p.gameserver.skills.Formulas;
import l2p.gameserver.skills.Stats;
import l2p.gameserver.skills.conditions.Condition;
import l2p.gameserver.skills.effects.EffectTemplate;
import l2p.gameserver.skills.funcs.Func;
import l2p.gameserver.skills.funcs.FuncTemplate;
import l2p.gameserver.skills.skillclasses.*;
import l2p.gameserver.skills.skillclasses.DeathPenalty;
import l2p.gameserver.tables.SkillTable;
import l2p.gameserver.templates.L2Weapon.WeaponType;
import l2p.gameserver.templates.StatsSet;
import l2p.util.ArrayMap;
import l2p.util.GArray;
import l2p.util.Rnd;
import l2p.util.Util;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class L2Skill implements Cloneable
{
  public static class AddedSkill
  {
    public int id;
    public int level;

    public AddedSkill(int id, int level)
    {
      this.id = id;
      this.level = level;
    }

    public L2Skill getSkill()
    {
      return SkillTable.getInstance().getInfo(id, level);
    }
  }

  public static enum Element
  {
    FIRE(0, Stats.ATTACK_ELEMENT_FIRE, Stats.FIRE_RECEPTIVE),
    WATER(1, Stats.ATTACK_ELEMENT_WATER, Stats.WATER_RECEPTIVE),
    WIND(2, Stats.ATTACK_ELEMENT_WIND, Stats.WIND_RECEPTIVE),
    EARTH(3, Stats.ATTACK_ELEMENT_EARTH, Stats.EARTH_RECEPTIVE),
    SACRED(4, Stats.ATTACK_ELEMENT_SACRED, Stats.SACRED_RECEPTIVE),
    UNHOLY(5, Stats.ATTACK_ELEMENT_UNHOLY, Stats.UNHOLY_RECEPTIVE),
    NONE(6, null, null);
    private final int id;
    private final Stats attack;
    private final Stats defence;

    private Element(int id, Stats attack, Stats defence)
    {
      this.id = id;
      this.attack = attack;
      this.defence = defence;
    }

    public int getId()
    {
      return id;
    }

    public Stats getAttack()
    {
      return attack;
    }

    public Stats getDefence()
    {
      return defence;
    }

    public static Element getElementById(int id)
    {
      for(Element e : values())
      {
        if(e.getId() == id)
        {
          return e;
        }
      }
      return NONE;
    }
  }

  public static enum NextAction
  {
    ATTACK,
    CAST,
    DEFAULT,
    MOVE,
    NONE
  }

  public static enum SkillOpType
  {
    OP_ACTIVE,
    OP_PASSIVE,
    OP_TOGGLE,
    OP_ON_ACTION;
  }

  public static enum TriggerActionType
  {
    ADD,
    // скилл срабатывает при добавлении в лист
    ATTACK,
    // OP_ON_ATTACK
    CRIT,
    // OP_ON_CRIT
    //SKILL_USE,
    //MAGIC_SKILL_USE,
    OFFENSIVE_PHYSICAL_SKILL_USE,
    OFFENSIVE_MAGICAL_SKILL_USE,
    // OP_ON_MAGIC_ATTACK
    SUPPORT_MAGICAL_SKILL_USE,
    // OP_ON_MAGIC_SUPPORT
    UNDER_ATTACK,
    // OP_ON_UNDER_ATTACK
    UNDER_MISSED_ATTACK,
    // OP_ON_EVASION
    UNDER_SKILL_ATTACK,
    // OP_ON_UNDER_SKILL_ATTACK
    //UNDER_MAGIC_SKILL_ATTACK,
    //UNDER_OFFENSIVE_SKILL_ATTACK,
    //UNDER_MAGIC_SUPPORT,
    DIE,
  }

  public static enum SkillTargetType
  {
    TARGET_ALLY,
    TARGET_AREA,
    TARGET_AREA_AIM_CORPSE,
    TARGET_AURA,
    TARGET_PET_AURA,
    TARGET_CHEST,
    TARGET_CLAN,
    TARGET_CLAN_ONLY,
    TARGET_CORPSE,
    TARGET_CORPSE_PLAYER,
    TARGET_ENEMY_PET,
    TARGET_ENEMY_SUMMON,
    TARGET_ENEMY_SERVITOR,
    TARGET_FLAGPOLE,
    TARGET_HOLY,
    TARGET_ITEM,
    TARGET_MULTIFACE,
    TARGET_MULTIFACE_AURA,
    TARGET_TUNNEL,
    TARGET_NONE,
    TARGET_ONE,
    TARGET_OWNER,
    TARGET_PARTY,
    TARGET_PARTY_ONE,
    TARGET_PET,
    TARGET_SELF,
    TARGET_SIEGE,
    TARGET_UNLOCKABLE
  }

  public static enum SkillType
  {
    AGGRESSION(Aggression.class),
    AIEFFECTS(AIeffects.class),
    BALANCE(Balance.class),
    BEAST_FEED(BeastFeed.class),
    BLEED(Continuous.class),
    BUFF(Continuous.class),
    BUFF_CHARGER(BuffCharger.class),
    CALL(Call.class),
    CANCEL(Cancel.class),
    CHARGE(Charge.class),
    CHARGE_SOUL(ChargeSoul.class),
    COMBATPOINTHEAL(CombatPointHeal.class),
    CONT(Toggle.class),
    CPDAM(CPDam.class),
    CPHOT(Continuous.class),
    CRAFT(Craft.class),
    DEATH_PENALTY(DeathPenalty.class),
    DEBUFF(Continuous.class),
    DELETE_HATE(DeleteHate.class),
    DELETE_HATE_OF_ME(DeleteHateOfMe.class),
    DESTROY_SUMMON(DestroySummon.class),
    DEFUSE_TRAP(DefuseTrap.class),
    DETECT_TRAP(DetectTrap.class),
    DISCORD(Continuous.class),
    DOT(Continuous.class),
    DRAIN(Drain.class),
    DRAIN_SOUL(DrainSoul.class),
    EFFECT(Effect.class),
    EFFECTS_FROM_SKILLS(EffectsFromSkills.class),
    ENCHANT_ARMOR,
    ENCHANT_WEAPON,
    EXTRACT_STONE(ExtractStone.class),
    FEED_PET,
    FISHING(Fishing.class),
    HARDCODED(Effect.class),
    HARVESTING(Harvesting.class),
    HEAL(Heal.class),
    HEAL_PERCENT(HealPercent.class),
    HOT(Continuous.class),
    KAMAEL_WEAPON_EXCHANGE(KamaelWeaponExchange.class),
    LETHAL_SHOT(LethalShot.class),
    LUCK,
    MANADAM(ManaDam.class),
    MANAHEAL(ManaHeal.class),
    MANAHEAL_PERCENT(ManaHealPercent.class),
    MDAM(MDam.class),
    MDOT(Continuous.class),
    MPHOT(Continuous.class),
    MUTE(Disablers.class),
    NEGATE_EFFECTS(NegateEffects.class),
    NEGATE_STATS(NegateStats.class),
    NOTDONE,
    NOTUSED,
    OUTPOST(Outpost.class),
    PARALYZE(Disablers.class),
    PASSIVE,
    PDAM(PDam.class),
    POISON(Continuous.class),
    PUMPING(ReelingPumping.class),
    RECALL(Recall.class),
    REELING(ReelingPumping.class),
    REFILL(Refill.class),
    RESURRECT(Resurrect.class),
    RIDE(Ride.class),
    ROOT(Disablers.class),
    SHIFT_AGGRESSION(ShiftAggression.class),
    SIEGEFLAG(SiegeFlag.class),
    SLEEP(Disablers.class),
    SOULSHOT,
    SOWING(Sowing.class),
    SPHEAL(SPHeal.class),
    SPIRITSHOT,
    SPOIL(Spoil.class),
    STEAL_BUFF(StealBuff.class),
    STUN(Disablers.class),
    SUMMON(Summon.class),
    SUMMON_ITEM(SummonItem.class),
    SWEEP(Sweep.class),
    TAKECASTLE(TakeCastle.class),
    TAKEFORTRESS(TakeFortress.class),
    TAKEFLAG(TakeFlag.class),
    TELEPORT_NPC(TeleportNpc.class),
    TRANSFORMATION(Transformation.class),
    UNLOCK(Unlock.class),
    WATCHER_GAZE(Continuous.class);
    private final Class<? extends L2Skill> clazz;

    private SkillType()
    {
      clazz = Default.class;
    }

    private SkillType(Class<? extends L2Skill> clazz)
    {
      this.clazz = clazz;
    }

    public L2Skill makeSkill(StatsSet set)
    {
      try
      {
        Constructor<? extends L2Skill> c = clazz.getConstructor(StatsSet.class);
        return c.newInstance(set);
      }
      catch(Exception e)
      {
        e.printStackTrace();
        throw new RuntimeException(e);
      }
    }
  }

  protected static Logger _log = Logger.getLogger(L2Skill.class.getName());
  protected static final TreeMap<TriggerActionType, Double> EMPTY_ACTIONS = new TreeMap<TriggerActionType, Double>();
  protected static final AddedSkill[] _emptyAddedSkills = new AddedSkill[0];
  protected static final Func[] _emptyFunctionSet = new Func[0];
  protected static final HashMap<Integer, GArray<Integer>> _reuseGroups = new HashMap<Integer, GArray<Integer>>();
  protected EffectTemplate[] _effectTemplates;
  protected FuncTemplate[] _funcTemplates;
  protected TreeMap<TriggerActionType, Double> _triggerActions;
  protected GArray<Integer> _teachers; // which NPC teaches
  protected GArray<ClassId> _canLearn; // which classes can learn
  protected AddedSkill[] _addedSkills;
  protected final int[] _itemConsume;
  protected final int[] _itemConsumeId;
  public static final int SKILL_CUBIC_MASTERY = 143;
  public static final int SKILL_CRAFTING = 172;
  public static final int SKILL_POLEARM_MASTERY = 216;
  public static final int SKILL_CRYSTALLIZE = 248;
  public static final int SKILL_WEAPON_MAGIC_MASTERY1 = 249;
  public static final int SKILL_WEAPON_MAGIC_MASTERY2 = 250;
  public static final int SKILL_BLINDING_BLOW = 321;
  public static final int SKILL_STRIDER_ASSAULT = 325;
  public static final int SKILL_WYVERN_AEGIS = 327;
  public static final int SKILL_BLUFF = 358;
  public static final int SKILL_HEROIC_MIRACLE = 395;
  public static final int SKILL_HEROIC_BERSERKER = 396;
  public static final int SKILL_SOUL_MASTERY = 467;
  public static final int SKILL_TRANSFOR_DISPELL = 619;
  public static final int SKILL_FINAL_FLYING_FORM = 840;
  public static final int SKILL_AURA_BIRD_FALCON = 841;
  public static final int SKILL_AURA_BIRD_OWL = 842;
  public static final int SKILL_DETECTION = 933;
  public static final int SKILL_RECHARGE = 1013;
  public static final int SKILL_TRANSFER_PAIN = 1262;
  public static final int SKILL_FISHING_MASTERY = 1315;
  public static final int SKILL_NOBLESSE_BLESSING = 1323;
  public static final int SKILL_SUMMON_CP_POTION = 1324;
  public static final int SKILL_FORTUNE_OF_NOBLESSE = 1325;
  public static final int SKILL_HARMONY_OF_NOBLESSE = 1326;
  public static final int SKILL_SYMPHONY_OF_NOBLESSE = 1327;
  public static final int SKILL_HEROIC_VALOR = 1374;
  public static final int SKILL_HEROIC_GRANDEUR = 1375;
  public static final int SKILL_HEROIC_DREAD = 1376;
  public static final int SKILL_MYSTIC_IMMUNITY = 1411;
  public static final int SKILL_RAID_BLESSING = 2168;
  public static final int SKILL_DISMISS_AGATHION = 3267;
  public static final int SKILL_HINDER_STRIDER = 4258;
  public static final int SKILL_WYVERN_BREATH = 4289;
  public static final int SKILL_RAID_CURSE = 4515;
  public static final int SKILL_CHARM_OF_COURAGE = 5041;
  public static final int SKILL_EVENT_TIMER = 5239;
  public static final int SKILL_BATTLEFIELD_DEATH_SYNDROME = 5660;
  public static final int[] SKILLS_S80_AND_S84_SETS =
    {
      3416,
      8210,
      3354,
      8211,
      3355,
      8212,
      3356,
      8213,
      3357,
      8214,
      3412,
      8202,
      3348,
      8203,
      3349,
      8204,
      3350,
      8205,
      3351,
      8206,
      3413,
      8207,
      3352,
      8208,
      3353,
      8209,
      3414,
      8215,
      3415,
      8216,
      3420,
      8217,
      3420,
      8218,
      3645,
      8229,
      3646,
      8230,
      3647,
      8231,
      3648,
      8232,
      3636,
      8219,
      3637,
      8220,
      3638,
      8221,
      3639,
      8222,
      3640,
      8223,
      3641,
      8224,
      3642,
      8225,
      3643,
      8226,
      3644,
      8227,
      3805,
      8228,
      8283,
      8285,
      8287,
      8284,
      8286,
      8288,
      8301,
      8303,
      8305,
      8302,
      8304,
      8306
    };
  public final static int SAVEVS_CON = 4;
  public final static int SAVEVS_DEX = 5;
  public final static int SAVEVS_INT = 1;
  public final static int SAVEVS_MEN = 3;
  public final static int SAVEVS_STR = 6;
  public final static int SAVEVS_WIT = 2;
  protected boolean _isAltUse;
  protected boolean _isBehind;
  protected boolean _isCancelable;
  protected boolean _isCorpse;
  protected boolean _isCommon;
  protected boolean _isItemHandler;
  protected Boolean _isOffensive;
  protected Boolean _isPvpSkill;
  protected Boolean _isPvm;
  protected boolean _isForceUse;
  protected boolean _isMagic;
  protected boolean _isSaveable;
  protected boolean _isSkillTimePermanent;
  protected boolean _isReuseDelayPermanent;
  protected boolean _isSuicideAttack;
  protected boolean _isShieldignore;
  protected boolean _isUndeadOnly;
  protected Boolean _isUseSS;
  protected boolean _isOverhit;
  protected boolean _isSoulBoost;
  protected boolean _isChargeBoost;
  protected boolean _isUsingWhileCasting;
  protected boolean _skillInterrupt;
  protected boolean _deathlink;
  protected boolean _basedOnTargetDebuff;
  protected boolean _isNotUsedByAI;
  protected boolean _isIgnoreResists;
  protected boolean _isMusic;
  protected boolean _isNotAffectedByMute;
  protected boolean _flyingTransformUsage;
  protected boolean _isOlympiadEnabled;
  protected SkillType _skillType;
  protected SkillOpType _operateType;
  protected SkillTargetType _targetType;
  protected NextAction _nextAction;
  protected Element _element;
  protected FlyType _flyType;
  protected boolean _flyToBack;
  protected Condition[] _preCondition;
  protected Integer _id;
  protected Short _level;
  protected Short _baseLevel;
  protected Integer _displayId;
  protected Short _displayLevel;
  protected int _activateRate;
  protected int _castRange;
  protected int _cancelTarget;
  protected int _condCharges;
  protected int _coolTime;
  protected int _delayedEffect;
  protected int _effectPoint;
  protected int _elementPower;
  protected int _flyRadius;
  protected int _forceId;
  protected int _hitTime;
  protected int _hpConsume;
  protected int _levelModifier;
  protected int _magicLevel;
  protected int _matak;
  protected int _minPledgeClass;
  protected int _minRank;
  protected int _negatePower;
  protected int _negateSkill;
  protected int _npcId;
  protected int _numCharges;
  protected int _reuseGroupId;
  protected int _savevs;
  protected int _skillInterruptTime;
  protected int _skillRadius;
  protected int _soulsConsume;
  protected int _symbolId;
  protected int _weaponsAllowed;
  protected int _castCount;
  protected int _enchantLevelCount;
  protected int _criticalRate;
  protected long _reuseDelay;
  protected double _power;
  protected double _powerPvP;
  protected double _powerPvE;
  protected double _mpConsume1;
  protected double _mpConsume2;
  protected double _lethal1;
  protected double _lethal2;
  protected double _absorbPart;
  protected String _name;
  protected String _baseValues;
  public boolean _isStandart = false;
  // Жрет много памяти, включить только если будет необходимость
  //protected StatsSet _set;

  /**
   * Внимание!!! У наследников вручную надо поменять тип на public
   *
   * @param set парамерты скилла
   */
  protected L2Skill(StatsSet set)
  {
    //_set = set;
    _id = set.getInteger("skill_id");
    _level = set.getShort("level");
    _displayId = set.getInteger("displayId", _id);
    _displayLevel = set.getShort("displayLevel", _level);
    _name = set.getString("name");
    _operateType = set.getEnum("operateType", SkillOpType.class);
    _isMagic = set.getBool("isMagic", false);
    _isAltUse = set.getBool("altUse", false);
    _mpConsume1 = set.getInteger("mpConsume1", 0);
    _mpConsume2 = set.getInteger("mpConsume2", 0);
    _hpConsume = set.getInteger("hpConsume", 0);
    _soulsConsume = set.getInteger("soulsConsume", 0);
    _isSoulBoost = set.getBool("soulBoost", false);
    _isChargeBoost = set.getBool("chargeBoost", false);
    _isUsingWhileCasting = set.getBool("isUsingWhileCasting", false);
    _matak = set.getInteger("mAtk", 0);
    _isUseSS = set.getBool("useSS", null);
    _forceId = set.getInteger("forceId", 0);
    _magicLevel = set.getInteger("magicLevel", 0);
    _castCount = set.getInteger("castCount", 0);
    _baseValues = set.getString("baseValues", null);
    if(_operateType == SkillOpType.OP_ON_ACTION)
    {
      StringTokenizer st = new StringTokenizer(set.getString("triggerActions", ""), ";");
      if(st.hasMoreTokens())
      {
        _triggerActions = new TreeMap<TriggerActionType, Double>();
        while(st.hasMoreTokens())
        {
          TriggerActionType tat = Enum.valueOf(TriggerActionType.class, st.nextToken());
          Double chance = Double.valueOf(st.nextToken());
          _triggerActions.put(tat, chance);
        }
      }
    }
    if(_triggerActions == null)
    {
      _triggerActions = EMPTY_ACTIONS;
    }
    String s1 = set.getString("itemConsumeCount", "");
    String s2 = set.getString("itemConsumeId", "");
    if(s1.length() == 0)
    {
      _itemConsume = new int[]
        {
          0
        };
    }
    else
    {
      String[] s = s1.split(" ");
      _itemConsume = new int[s.length];
      for(int i = 0; i < s.length; i++)
      {
        _itemConsume[i] = Integer.parseInt(s[i]);
      }
    }
    if(s2.length() == 0)
    {
      _itemConsumeId = new int[]
        {
          0
        };
    }
    else
    {
      String[] s = s2.split(" ");
      _itemConsumeId = new int[s.length];
      for(int i = 0; i < s.length; i++)
      {
        _itemConsumeId[i] = Integer.parseInt(s[i]);
      }
    }
    _isItemHandler = set.getBool("isHandler", false);
    _reuseGroupId = set.getInteger("reuseGroup", 0);
    if(_reuseGroupId > 0)
    {
      if(_reuseGroups.get(_reuseGroupId) == null)
      {
        _reuseGroups.put(_reuseGroupId, new GArray<Integer>());
      }
      if(!_reuseGroups.get(_reuseGroupId).contains(_id))
      {
        _reuseGroups.get(_reuseGroupId).add(_id);
      }
    }
    _isCommon = set.getBool("isCommon", false);
    _isSaveable = set.getBool("isSaveable", true);
    _coolTime = set.getInteger("coolTime", 0);
    _skillInterruptTime = set.getInteger("skillInterruptTime", 0);
    _reuseDelay = set.getLong("reuseDelay", 0);
    _skillRadius = set.getInteger("skillRadius", 80);
    _targetType = set.getEnum("target", SkillTargetType.class);
    _isUndeadOnly = set.getBool("undeadOnly", false);
    _isCorpse = set.getBool("corpse", false);
    _power = set.getDouble("power", 0.);
    _powerPvP = set.getDouble("powerPvP", 0.);
    _powerPvE = set.getDouble("powerPvE", 0.);
    _effectPoint = set.getInteger("effectPoint", 0);
    _nextAction = NextAction.valueOf(set.getString("nextAction", "DEFAULT").toUpperCase());
    _skillType = set.getEnum("skillType", SkillType.class);
    _isSuicideAttack = set.getBool("isSuicideAttack", false);
    _isSkillTimePermanent = set.getBool("isSkillTimePermanent", false);
    _isReuseDelayPermanent = set.getBool("isReuseDelayPermanent", false);
    _deathlink = set.getBool("deathlink", false);
    _basedOnTargetDebuff = set.getBool("basedOnTargetDebuff", false);
    _isNotUsedByAI = set.getBool("isNotUsedByAI", false);
    _isIgnoreResists = set.getBool("isIgnoreResists", false);
    _isMusic = set.getBool("isMusic", false);
    _isNotAffectedByMute = set.getBool("isNotAffectedByMute", false);
    _flyingTransformUsage = set.getBool("flyingTransformUsage", false);
    _isOlympiadEnabled = set.getBool("isOlympiadEnabled", false);
    if(Util.isNumber(set.getString("element", "NONE")))
    {
      _element = Element.getElementById(set.getInteger("element", 6));
    }
    else
    {
      _element = Element.valueOf(set.getString("element", "NONE").toUpperCase());
    }
    _elementPower = set.getInteger("elementPower", 0);
    if(Util.isNumber(set.getString("save", "0")))
    {
      _savevs = set.getInteger("save", 0);
    }
    else
    {
      try
      {
        _savevs = L2Skill.class.getField("SAVEVS_" + set.getString("save").toUpperCase()).getInt(null);
      }
      catch(Exception e)
      {
        _log.warning("Invalid savevs value: " + set.getString("save"));
        e.printStackTrace();
      }
    }
    _activateRate = set.getInteger("activateRate", -1);
    _levelModifier = set.getInteger("levelModifier", 1);
    _isCancelable = set.getBool("cancelable", true);
    _isShieldignore = set.getBool("shieldignore", false);
    _criticalRate = set.getInteger("criticalRate", 0);
    _isOverhit = set.getBool("overHit", false);
    _weaponsAllowed = set.getInteger("weaponsAllowed", 0);
    _minPledgeClass = set.getInteger("minPledgeClass", 0);
    _minRank = set.getInteger("minRank", 0);
    _isOffensive = set.getBool("isOffensive", null);
    _isPvpSkill = set.getBool("isPvpSkill", null);
    _isPvm = set.getBool("isPvm", null);
    _isForceUse = set.getBool("isForceUse", false);
    _isBehind = set.getBool("behind", false);
    _symbolId = set.getInteger("symbolId", 0);
    _npcId = set.getInteger("npcId", 0);
    _flyType = FlyType.valueOf(set.getString("flyType", "NONE").toUpperCase());
    _flyToBack = set.getBool("flyToBack", false);
    _flyRadius = set.getInteger("flyRadius", 200);
    _negateSkill = set.getInteger("negateSkill", 0);
    _negatePower = set.getInteger("negatePower", Integer.MAX_VALUE);
    _numCharges = set.getInteger("num_charges", 0);
    _condCharges = set.getInteger("cond_charges", 0);
    _delayedEffect = set.getInteger("delayedEffect", 0);
    _cancelTarget = set.getInteger("cancelTarget", 0);
    _skillInterrupt = set.getBool("skillInterrupt", false);
    _lethal1 = set.getDouble("lethal1", 0);
    _lethal2 = set.getDouble("lethal2", 0);
    _absorbPart = set.getFloat("absorbPart", 0.f);
    StringTokenizer st = new StringTokenizer(set.getString("addSkills", ""), ";");
    while(st.hasMoreTokens())
    {
      int id = Integer.valueOf(st.nextToken());
      int level = Integer.valueOf(st.nextToken());
      if(level == -1)
      {
        level = _level;
      }
      _addedSkills = (AddedSkill[]) Util.addElementToArray(_addedSkills, new AddedSkill(id, level), AddedSkill.class);
    }
    if(_nextAction == NextAction.DEFAULT)
    {
      switch(_skillType)
      {
        case PDAM:
        case CPDAM:
        case LETHAL_SHOT:
        case SPOIL:
        case SOWING:
        case STUN:
        case DRAIN_SOUL:
          _nextAction = NextAction.ATTACK;
          break;
        default:
          _nextAction = NextAction.NONE;
      }
    }
    if(_savevs == 0)
    {
      switch(_skillType)
      {
        case BLEED:
        case DOT:
        case MDOT:
        case LETHAL_SHOT:
        case PDAM:
        case CPDAM:
        case POISON:
        case STUN:
          _savevs = SAVEVS_CON;
          break;
        case CANCEL:
        case MANADAM:
        case DEBUFF:
        case MDAM:
        case MUTE:
        case PARALYZE:
        case ROOT:
        case SLEEP:
          _savevs = SAVEVS_MEN;
          break;
      }
    }
    String canLearn = set.getString("canLearn", null);
    if(canLearn == null)
    {
      _canLearn = null;
    }
    else
    {
      _canLearn = new GArray<ClassId>();
      st = new StringTokenizer(canLearn, " \r\n\t,;");
      while(st.hasMoreTokens())
      {
        String cls = st.nextToken();
        try
        {
          _canLearn.add(ClassId.valueOf(cls));
        }
        catch(Throwable t)
        {
          _log.log(Level.SEVERE, "Bad class " + cls + " to learn skill", t);
        }
      }
    }
    String teachers = set.getString("teachers", null);
    if(teachers == null)
    {
      _teachers = null;
    }
    else
    {
      _teachers = new GArray<Integer>();
      st = new StringTokenizer(teachers, " \r\n\t,;");
      while(st.hasMoreTokens())
      {
        String npcid = st.nextToken();
        try
        {
          _teachers.add(Integer.parseInt(npcid));
        }
        catch(Throwable t)
        {
          _log.log(Level.SEVERE, "Bad teacher id " + npcid + " to teach skill", t);
        }
      }
    }
  }

  public final boolean getWeaponDependancy(L2Character activeChar)
  {
    if(_weaponsAllowed == 0)
    {
      return true;
    }
    if(activeChar.getActiveWeaponInstance() != null && activeChar.getActiveWeaponItem() != null)
    {
      if((activeChar.getActiveWeaponItem().getItemType().mask() & _weaponsAllowed) != 0)
      {
        return true;
      }
    }
    if(activeChar.getSecondaryWeaponInstance() != null && activeChar.getSecondaryWeaponItem() != null)
    {
      if((activeChar.getSecondaryWeaponItem().getItemType().mask() & _weaponsAllowed) != 0)
      {
        return true;
      }
    }
    if(isActive())
    {
      StringBuffer skillmsg = new StringBuffer();
      skillmsg.append(_name);
      skillmsg.append(" can only be used with weapons of type ");
      for(WeaponType wt : WeaponType.values())
      {
        if((wt.mask() & _weaponsAllowed) != 0)
        {
          skillmsg.append(wt).append('/');
        }
      }
      skillmsg.setCharAt(skillmsg.length() - 1, '.');
      activeChar.sendMessage(skillmsg.toString());
    }
    return false;
  }

  public boolean checkCondition(L2Character activeChar, L2Character target, boolean forceUse, boolean dontMove, boolean first)
  {
    L2Player player = activeChar.getPlayer();
    if(activeChar.isDead())
    {
      return false;
    }
    if(target != null && (activeChar.getReflection() != target.getReflection() || target != activeChar && target.isInvisible() && getId() != SKILL_DETECTION))
    {
      activeChar.sendPacket(Msg.CANNOT_SEE_TARGET);
      return false;
    }
    if(!getWeaponDependancy(activeChar))
    {
      return false;
    }
    if(first && activeChar.isSkillDisabled(_id))
    {
      activeChar.sendReuseMessage(this);
      return false;
    }
    if(first && activeChar.getCurrentMp() < (isMagic() ? activeChar.calcStat(Stats.MP_MAGIC_SKILL_CONSUME, _mpConsume1 + _mpConsume2, target, this) : activeChar.calcStat(Stats.MP_PHYSICAL_SKILL_CONSUME, _mpConsume1 + _mpConsume2, target, this)))
    {
      activeChar.sendPacket(Msg.NOT_ENOUGH_MP);
      return false;
    }
    if(activeChar.getCurrentHp() < _hpConsume + 1)
    {
      activeChar.sendPacket(Msg.NOT_ENOUGH_HP);
      return false;
    }
    if(!(_isItemHandler || _isAltUse) && activeChar.isMuted(this))
    {
      return false;
    }
    if(_soulsConsume > activeChar.getConsumedSouls())
    {
      activeChar.sendPacket(Msg.THERE_IS_NOT_ENOUGHT_SOUL);
      return false;
    }
    // TODO перенести потребление из формул сюда
    if(activeChar.getIncreasedForce() < _condCharges || activeChar.getIncreasedForce() < _numCharges)
    {
      activeChar.sendPacket(Msg.YOUR_FORCE_HAS_REACHED_MAXIMUM_CAPACITY_);
      return false;
    }
    if(player != null)
    {
      if(!isOlympiadEnabled() && player.isInOlympiadMode())
      {
        player.sendPacket(Msg.THIS_ITEM_IS_NOT_AVAILABLE_FOR_THE_OLYMPIAD_EVENT);
        return false;
      }
      if(player.isInFlyingTransform() && _isItemHandler && !flyingTransformUsage())
      {
        player.sendPacket(new SystemMessage(SystemMessage.S1_CANNOT_BE_USED_DUE_TO_UNSUITABLE_TERMS).addItemName(getItemConsumeId()[0]));
        return false;
      }
      if(player.isInVehicle())
      {
        L2Vehicle vehicle = player.getVehicle();
        // На воздушных кораблях можно использовать скилы-хэндлеры всем кроме капитана
        if(vehicle.isAirShip() && (!_isItemHandler || ((L2AirShip) vehicle).getDriver() == player))
        {
          return false;
        }
        // С морских кораблей можно ловить рыбу
        if(vehicle instanceof L2Ship && !(this instanceof Fishing || this instanceof ReelingPumping))
        {
          return false;
        }
      }
      if(player.inObserverMode())
      {
        activeChar.sendPacket(Msg.OBSERVERS_CANNOT_PARTICIPATE);
        return false;
      }
      if(first && _itemConsume[0] > 0)
      {
        for(int i = 0; i < _itemConsume.length; i++)
        {
          Inventory inv = ((L2Playable) activeChar).getInventory();
          if(inv == null)
          {
            inv = player.getInventory();
          }
          L2ItemInstance requiredItems = inv.getItemByItemId(_itemConsumeId[i]);
          if(requiredItems == null || requiredItems.getCount() < _itemConsume[i])
          {
            if(activeChar == player)
            {
              player.sendPacket(Msg.INCORRECT_ITEM_COUNT);
            }
            return false;
          }
        }
      }
      if(player.isFishing() && _id != 1312 && _id != 1313 && _id != 1314 && !altUse())
      {
        if(activeChar == player)
        {
          player.sendPacket(Msg.ONLY_FISHING_SKILLS_ARE_AVAILABLE);
        }
        return false;
      }
    }
    if(getFlyType() != FlyType.NONE && (activeChar.isImobilised() || activeChar.isRooted()))
    {
      activeChar.getPlayer().sendPacket(Msg.YOUR_TARGET_IS_OUT_OF_RANGE);
      return false;
    }
    // Fly скиллы нельзя использовать слишком близко
    if(first && target != null && getFlyType() == FlyType.CHARGE && activeChar.isInRange(target.getLoc(), Math.min(150, getFlyRadius())))
    {
      activeChar.getPlayer().sendPacket(Msg.THERE_IS_NOT_ENOUGH_SPACE_TO_MOVE_THE_SKILL_CANNOT_BE_USED);
      return false;
    }
    SystemMessage msg = checkTarget(activeChar, target, target, forceUse, first);
    if(msg != null && activeChar.getPlayer() != null)
    {
      activeChar.getPlayer().sendPacket(msg);
      return false;
    }
    if(_preCondition == null || _preCondition.length == 0)
    {
      return true;
    }
    Env env = new Env();
    env.character = activeChar;
    env.skill = this;
    env.target = target;
    if(first)
    {
      for(Condition с : _preCondition)
      {
        if(с != null && !с.test(env))
        {
          String cond_msg = с.getMessage();
          if(cond_msg != null)
          {
            activeChar.sendMessage(cond_msg);
          }
          return false;
        }
      }
    }
    return true;
  }

  public SystemMessage checkTarget(L2Character activeChar, L2Character target, L2Character aimingTarget, boolean forceUse, boolean first)
  {
    if(target == activeChar && isNotTargetAoE() || target == activeChar.getPet() && _targetType == SkillTargetType.TARGET_PET_AURA)
    {
      return null;
    }
    if(target == null || isOffensive() && target == activeChar)
    {
      return Msg.THAT_IS_THE_INCORRECT_TARGET;
    }
    if(activeChar.getReflection() != target.getReflection()) // Массовые атаки должны попадать по дагерам в Hide. Если потребуется убрать - раскомментировать. || target != activeChar && target.isInvisible() && getId() != SKILL_DETECTION)
    {
      return Msg.CANNOT_SEE_TARGET;
    }
    // Попадает ли цель в радиус действия в конце каста
    if(!first && target != activeChar && target == aimingTarget && getCastRange() > 0 && getCastRange() != 32767 && !activeChar.isInRange(target.getLoc(), getCastRange() + (getCastRange() < 200 ? 400 : 500)))
    {
      return Msg.YOUR_TARGET_IS_OUT_OF_RANGE;
    }
    // Для этих скиллов дальнейшие проверки не нужны
    if(_skillType == SkillType.TAKECASTLE || _skillType == SkillType.TAKEFORTRESS || _skillType == SkillType.TAKEFLAG)
    {
      return null;
    }
    // Конусообразные скиллы
    if(!first && target != activeChar && (_targetType == SkillTargetType.TARGET_MULTIFACE || _targetType == SkillTargetType.TARGET_MULTIFACE_AURA || _targetType == SkillTargetType.TARGET_TUNNEL) && (_isBehind ? activeChar.isInFront(target, 120) : !activeChar.isInFront(target, 60)))
    {
      return Msg.YOUR_TARGET_IS_OUT_OF_RANGE;
    }
    // Проверка на каст по трупу
    if(target.isDead() != _isCorpse && _targetType != SkillTargetType.TARGET_AREA_AIM_CORPSE || _isUndeadOnly && !target.isUndead())
    {
      return Msg.INVALID_TARGET;
    }
    if(target.isMonster() && ((L2MonsterInstance) target).isDying())
    {
      return Msg.INVALID_TARGET;
    }
    if(_targetType != SkillTargetType.TARGET_UNLOCKABLE && target.isDoor() && !target.isAttackable(activeChar))
    {
      return Msg.INVALID_TARGET;
    }
    // Для различных бутылок, и для скилла кормления, дальнейшие проверки не нужны
    if(_isAltUse || _skillType == SkillType.BEAST_FEED || _targetType == SkillTargetType.TARGET_UNLOCKABLE || _targetType == SkillTargetType.TARGET_CHEST)
    {
      return null;
    }
    if(activeChar.isPlayable())
    {
      L2Player player = activeChar.getPlayer();
      if(player == null)
      {
        return Msg.THAT_IS_THE_INCORRECT_TARGET;
      }
      // Запрет на атаку мирных NPC в осадной зоне на TW. Иначе таким способом набивают очки.
      if(player.getTerritorySiege() > -1 && target.isNpc() && !(target instanceof L2TerritoryFlagInstance) && !(target.getAI() instanceof DefaultAI) && player.isInZone(ZoneType.Siege))
      {
        return Msg.INVALID_TARGET;
      }
      if(target.isPlayable())
      {
        if(isPvM())
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        L2Player pcTarget = target.getPlayer();
        if(pcTarget == null)
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(player.isInZone(ZoneType.epic) != pcTarget.isInZone(ZoneType.epic))
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(pcTarget.isInOlympiadMode() && (!player.isInOlympiadMode() || player.getOlympiadGameId() != pcTarget.getOlympiadGameId())) // На всякий случай
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(player.getTeam() > 0 && player.isChecksForTeam() && pcTarget.getTeam() == 0) // Запрет на атаку/баф участником эвента незарегистрированного игрока
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(pcTarget.getTeam() > 0 && pcTarget.isChecksForTeam() && player.getTeam() == 0) // Запрет на атаку/баф участника эвента незарегистрированным игроком
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(isOffensive())
        {
          if(player.isInOlympiadMode() && !player.isOlympiadCompStart()) // Бой еще не начался
          {
            return Msg.INVALID_TARGET;
          }
          if(player.isInOlympiadMode() && player.isOlympiadCompStart() && player.getOlympiadSide() == pcTarget.getOlympiadSide()) // Свою команду атаковать нельзя
          {
            return Msg.THAT_IS_THE_INCORRECT_TARGET;
          }
          if(player.getTeam() > 0 && player.isChecksForTeam() && pcTarget.getTeam() > 0 && pcTarget.isChecksForTeam() && player.getTeam() == pcTarget.getTeam()) // Свою команду атаковать нельзя
          {
            return Msg.THAT_IS_THE_INCORRECT_TARGET;
          }
          if(isAoE() && getCastRange() < Integer.MAX_VALUE && !GeoEngine.canSeeTarget(activeChar, target, activeChar.isFlying()))
          {
            return Msg.CANNOT_SEE_TARGET;
          }
          if(activeChar.isInZoneBattle() != target.isInZoneBattle() && !player.getPlayerAccess().PeaceAttack)
          {
            return Msg.YOU_MAY_NOT_ATTACK_THIS_TARGET_IN_A_PEACEFUL_ZONE;
          }
          if((activeChar.isInZonePeace() || target.isInZonePeace()) && !player.getPlayerAccess().PeaceAttack)
          {
            return Msg.YOU_MAY_NOT_ATTACK_THIS_TARGET_IN_A_PEACEFUL_ZONE;
          }
          if(activeChar.isInZoneBattle())
          {
            if(!forceUse && !isForceUse() && player.getParty() != null && player.getParty() == pcTarget.getParty())
            {
              return Msg.INVALID_TARGET;
            }
            return null; // Остальные условия на аренах и на олимпиаде проверять не требуется
          }
          // Только враг и только если он еше не проиграл.
          Duel duel1 = player.getDuel();
          Duel duel2 = pcTarget.getDuel();
          if(player != pcTarget && duel1 != null && duel1 == duel2)
          {
            if(duel1.getTeamForPlayer(pcTarget) == duel1.getTeamForPlayer(player))
            {
              return Msg.INVALID_TARGET;
            }
            if(duel1.getDuelState(player.getStoredId()) != Duel.DuelState.Fighting)
            {
              return Msg.INVALID_TARGET;
            }
            if(duel1.getDuelState(pcTarget.getStoredId()) != Duel.DuelState.Fighting)
            {
              return Msg.INVALID_TARGET;
            }
            return null;
          }
          if(isPvpSkill() || !forceUse || isAoE())
          {
            if(player == pcTarget)
            {
              return Msg.INVALID_TARGET;
            }
            if(player.getParty() != null && player.getParty() == pcTarget.getParty())
            {
              return Msg.INVALID_TARGET;
            }
            if(player.getClanId() != 0 && player.getClanId() == pcTarget.getClanId())
            {
              return Msg.INVALID_TARGET;
            }
            if(player.getDuel() != null && pcTarget.getDuel() != player.getDuel())
            {
              return Msg.INVALID_TARGET;
            }
          }
          if(activeChar.isInZone(ZoneType.Siege) && target.isInZone(ZoneType.Siege))
          {
            if(player.getTerritorySiege() > -1 && player.getTerritorySiege() == pcTarget.getTerritorySiege())
            {
              return Msg.INVALID_TARGET;
            }
            L2Clan clan1 = player.getClan();
            L2Clan clan2 = pcTarget.getClan();
            if(clan1 == null || clan2 == null)
            {
              return null;
            }
            if(clan1.getSiege() == null || clan2.getSiege() == null)
            {
              return null;
            }
            if(clan1.getSiege() != clan2.getSiege())
            {
              return null;
            }
            if(clan1.isDefender() && clan2.isDefender())
            {
              return Msg.INVALID_TARGET;
            }
            if(clan1.getSiege().isMidVictory())
            {
              return null;
            }
            if(clan1.isAttacker() && clan2.isAttacker())
            {
              return Msg.INVALID_TARGET;
            }
            return null;
          }
          if(player.atMutualWarWith(pcTarget))
          {
            return null;
          }
          if(isForceUse())
          {
            return null;
          }
          // Защита от развода на флаг с копьем
          if(!forceUse && player.getPvpFlag() == 0 && pcTarget.getPvpFlag() != 0 && aimingTarget != target)
          {
            return Msg.INVALID_TARGET;
          }
          if(pcTarget.getPvpFlag() != 0)
          {
            return null;
          }
          if(pcTarget.getKarma() > 0)
          {
            return null;
          }
          if(forceUse && !isPvpSkill() && (!isAoE() || aimingTarget == target))
          {
            return null;
          }
          return Msg.INVALID_TARGET;
        }
        if(pcTarget == player)
        {
          return null;
        }
        if(player.isInOlympiadMode() && player.getOlympiadSide() != pcTarget.getOlympiadSide()) // Чужой команде помогать нельзя
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(player.getTeam() > 0 && player.isChecksForTeam() && pcTarget.getTeam() > 0 && pcTarget.isChecksForTeam() && player.getTeam() != pcTarget.getTeam()) // Чужой команде помогать нельзя
        {
          return Msg.THAT_IS_THE_INCORRECT_TARGET;
        }
        if(!activeChar.isInZoneBattle() && target.isInZoneBattle())
        {
          return Msg.INVALID_TARGET;
        }
        if(activeChar.isInZonePeace() && !target.isInZonePeace())
        {
          return Msg.INVALID_TARGET;
        }
        if(forceUse || isForceUse())
        {
          return null;
        }
        if(player.getDuel() != null && pcTarget.getDuel() != player.getDuel())
        {
          return Msg.INVALID_TARGET;
        }
        if(player != pcTarget && player.getDuel() != null && pcTarget.getDuel() != null && pcTarget.getDuel() == pcTarget.getDuel())
        {
          return Msg.INVALID_TARGET;
        }
        if(player.getParty() != null && player.getParty() == pcTarget.getParty())
        {
          return null;
        }
        if(player.getClanId() != 0 && player.getClanId() == pcTarget.getClanId())
        {
          return null;
        }
        if(player.atMutualWarWith(pcTarget))
        {
          return Msg.INVALID_TARGET;
        }
        if(pcTarget.getPvpFlag() != 0)
        {
          return Msg.INVALID_TARGET;
        }
        if(pcTarget.getKarma() > 0)
        {
          return Msg.INVALID_TARGET;
        }
        return null;
      }
    }
    if(isAoE() && isOffensive() && getCastRange() < Integer.MAX_VALUE && !GeoEngine.canSeeTarget(activeChar, target, activeChar.isFlying()))
    {
      return Msg.CANNOT_SEE_TARGET;
    }
    if(!forceUse && !isForceUse() && !isOffensive() && target.isAutoAttackable(activeChar))
    {
      return Msg.INVALID_TARGET;
    }
    if(!forceUse && !isForceUse() && isOffensive() && !target.isAutoAttackable(activeChar))
    {
      return Msg.INVALID_TARGET;
    }
    if(!target.isAttackable(activeChar))
    {
      return Msg.INVALID_TARGET;
    }
    return null;
  }

  public final L2Character getAimingTarget(L2Character activeChar, L2Object obj)
  {
    L2Character target = obj == null || !obj.isCharacter() ? null : (L2Character) obj;
    switch(_targetType)
    {
      case TARGET_ALLY:
      case TARGET_CLAN:
      case TARGET_PARTY:
      case TARGET_CLAN_ONLY:
      case TARGET_SELF:
        return activeChar;
      case TARGET_AURA:
      case TARGET_MULTIFACE_AURA:
        return activeChar;
      case TARGET_HOLY:
        return target != null && activeChar.isPlayer() && target.isArtefact() ? target : null;
      case TARGET_FLAGPOLE:
        return activeChar.isPlayer() && target instanceof L2StaticObjectInstance && ((L2StaticObjectInstance) target).getType() == 3 ? target : null;
      case TARGET_UNLOCKABLE:
        return target != null && target.isDoor() || target instanceof L2ChestInstance ? target : null;
      case TARGET_CHEST:
        return target instanceof L2ChestInstance ? target : null;
      case TARGET_PET:
      case TARGET_PET_AURA:
        target = activeChar.getPet();
        return target != null && target.isDead() == _isCorpse ? target : null;
      case TARGET_OWNER:
        if(activeChar.isSummon())
        {
          target = activeChar.getPlayer();
        }
        else
        {
          return null;
        }
        return target != null && target.isDead() == _isCorpse ? target : null;
      case TARGET_ENEMY_PET:
        if(target == null || target == activeChar.getPet() || !target.isPet())
        {
          return null;
        }
        return target;
      case TARGET_ENEMY_SUMMON:
        if(target == null || target == activeChar.getPet() || !target.isSummon())
        {
          return null;
        }
        return target;
      case TARGET_ENEMY_SERVITOR:
        if(target == null || target == activeChar.getPet() || !(target instanceof L2Summon))
        {
          return null;
        }
        return target;
      case TARGET_ONE:
        return target != null && target.isDead() == _isCorpse && !(target == activeChar && isOffensive()) && (!_isUndeadOnly || target.isUndead()) ? target : null;
      case TARGET_PARTY_ONE:
        if(target == null)
        {
          return null;
        }
        L2Player player = activeChar.getPlayer();
        L2Player ptarget = target.getPlayer();
        // self or self pet.
        if(ptarget != null && ptarget.equals(activeChar))
        {
          return target;
        }
        // olympiad party member or olympiad party member pet.
        if(player != null && player.isInOlympiadMode() && ptarget != null && player.getOlympiadSide() == ptarget.getOlympiadSide() && player.getOlympiadGameId() == ptarget.getOlympiadGameId() && target.isDead() == _isCorpse && !(target == activeChar && isOffensive()) && (!_isUndeadOnly || target.isUndead()))
        {
          return target;
        }
        // party member or party member pet.
        if(ptarget != null && player != null && player.getParty() != null && player.getParty().containsMember(ptarget) && target.isDead() == _isCorpse && !(target == activeChar && isOffensive()) && (!_isUndeadOnly || target.isUndead()))
        {
          return target;
        }
        return null;
      case TARGET_AREA:
      case TARGET_MULTIFACE:
      case TARGET_TUNNEL:
        return target != null && target.isDead() == _isCorpse && !(target == activeChar && isOffensive()) && (!_isUndeadOnly || target.isUndead()) ? target : null;
      case TARGET_AREA_AIM_CORPSE:
        return target != null && target.isDead() ? target : null;
      case TARGET_CORPSE:
        return target != null && target.isNpc() && target.isDead() ? target : null;
      case TARGET_CORPSE_PLAYER:
        return target != null && target.isPlayable() && target.isDead() ? target : null;
      case TARGET_SIEGE:
        return target != null && !target.isDead() && (target.isDoor() || target instanceof L2ControlTowerInstance) ? target : null;
      default:
        activeChar.sendMessage("Target type of skill is not currently handled");
        return null;
    }
  }

  public GArray<L2Character> getTargets(L2Character activeChar, L2Character aimingTarget, boolean forceUse)
  {
    GArray<L2Character> targets = new GArray<L2Character>();
    if(oneTarget())
    {
      targets.add(aimingTarget);
      return targets;
    }
    switch(_targetType)
    {
      case TARGET_AREA_AIM_CORPSE:
      case TARGET_AREA:
      case TARGET_MULTIFACE:
      case TARGET_TUNNEL:
      {
        if(aimingTarget.isDead() == _isCorpse && (!_isUndeadOnly || aimingTarget.isUndead()))
        {
          targets.add(aimingTarget);
        }
        addTargetsToList(targets, aimingTarget, activeChar, forceUse);
        break;
      }
      case TARGET_AURA:
      case TARGET_MULTIFACE_AURA:
      {
        addTargetsToList(targets, activeChar, activeChar, forceUse);
        break;
      }
      case TARGET_PET_AURA:
      {
        if(activeChar.getPet() == null)
        {
          break;
        }
        addTargetsToList(targets, activeChar.getPet(), activeChar, forceUse);
        break;
      }
      case TARGET_PARTY:
      case TARGET_CLAN:
      case TARGET_CLAN_ONLY:
      case TARGET_ALLY:
      {
        if(activeChar.isMonster() || activeChar.isSiegeGuard())
        {
          targets.add(activeChar);
          for(L2Character c : L2World.getAroundCharacters(activeChar, _skillRadius, 128))
          {
            if(!c.isDead() && (c.isMonster() || c.isSiegeGuard()) /*&& ((L2MonsterInstance) c).getFactionId().equals(mob.getFactionId())*/)
            {
              targets.add(c);
            }
          }
          break;
        }
        L2Player player = activeChar.getPlayer();
        if(player == null)
        {
          if(activeChar.isPet() || activeChar.isSummon())
          {
            break;
          }
          System.out.println("L2Skill.getTargets | player = null | activeChar = " + activeChar + "[" + activeChar.getNpcId() + "] | SkillID: " + getId());
          Thread.dumpStack();
          break;
        }
        if(player.isInOlympiadMode())
        {
          addOlympiadTargetsToList(targets, player);
          addTargetAndPetToList(targets, player, player);
          break;
        }
        for(L2Player target : L2World.getAroundPlayers(player, _skillRadius, 128))
        {
          boolean check = false;
          switch(_targetType)
          {
            case TARGET_PARTY:
              check = player.getParty() != null && player.getParty() == target.getParty();
              break;
            case TARGET_CLAN:
              check = player.getClanId() != 0 && target.getClanId() == player.getClanId() || player.getParty() != null && target.getParty() == player.getParty();
              break;
            case TARGET_CLAN_ONLY:
              check = player.getClanId() != 0 && target.getClanId() == player.getClanId();
              break;
            case TARGET_ALLY:
              check = player.getClanId() != 0 && target.getClanId() == player.getClanId() || player.getAllyId() != 0 && target.getAllyId() == player.getAllyId();
              break;
          }
          if(!check)
          {
            continue;
          }
          if(checkTarget(player, target, aimingTarget, forceUse, false) != null)
          {
            continue;
          }
          addTargetAndPetToList(targets, player, target);
        }
        addTargetAndPetToList(targets, player, player);
        break;
      }
    }
    return targets;
  }

  private void addTargetAndPetToList(GArray<L2Character> targets, L2Player actor, L2Player target)
  {
    if((actor == target || actor.isInRange(target, _skillRadius)) && target.isDead() == _isCorpse)
    {
      targets.add(target);
    }
    L2Summon pet = target.getPet();
    if(pet != null && actor.isInRange(pet, _skillRadius) && pet.isDead() == _isCorpse)
    {
      targets.add(pet);
    }
  }

  private void addOlympiadTargetsToList(GArray<L2Character> targets, L2Player player)
  {
    if(!_isCorpse)
    {
      targets.add(player);
    }
    L2Summon pet = player.getPet();
    if(pet != null && pet.isDead() == _isCorpse)
    {
      targets.add(pet);
    }
    for(L2Player target : L2World.getAroundPlayers(player, _skillRadius, 128))
    {
      if(player.getOlympiadSide() != target.getOlympiadSide()) // Чужой команде помогать нельзя
      {
        continue;
      }
      if(player.getOlympiadGameId() != target.getOlympiadGameId()) // Команде на чужой арене помогать нельзя
      {
        continue;
      }
      addTargetAndPetToList(targets, player, target);
    }
  }

  private void addTargetsToList(GArray<L2Character> targets, L2Character aimingTarget, L2Character activeChar, boolean forceUse)
  {
    int count = 0;
    L2Territory terr = null;
    if(_targetType == SkillTargetType.TARGET_TUNNEL)
    {
      // Создаем параллелепипед ("косой" по вертикали)
      int radius = 100;
      int zmin1 = activeChar.getZ() - 200;
      int zmax1 = activeChar.getZ() + 200;
      int zmin2 = aimingTarget.getZ() - 200;
      int zmax2 = aimingTarget.getZ() + 200;
      double angle = Util.convertHeadingToDegree(activeChar.getHeading());
      double radian1 = Math.toRadians(angle - 90);
      double radian2 = Math.toRadians(angle + 90);
      terr = new L2Territory(0);
      terr.add(activeChar.getX() + (int) (Math.cos(radian1) * radius), activeChar.getY() + (int) (Math.sin(radian1) * radius), zmin1, zmax1);
      terr.add(activeChar.getX() + (int) (Math.cos(radian2) * radius), activeChar.getY() + (int) (Math.sin(radian2) * radius), zmin1, zmax1);
      terr.add(aimingTarget.getX() + (int) (Math.cos(radian2) * radius), aimingTarget.getY() + (int) (Math.sin(radian2) * radius), zmin2, zmax2);
      terr.add(aimingTarget.getX() + (int) (Math.cos(radian1) * radius), aimingTarget.getY() + (int) (Math.sin(radian1) * radius), zmin2, zmax2);
      if(activeChar.isPlayer() && ((L2Player) activeChar).isGM())
      {
        activeChar.sendPacket(Functions.Points2Trace(terr.getCoords(), 50, true, false));
        activeChar.sendPacket(Functions.Points2Trace(terr.getCoords(), 50, true, true));
      }
    }
    for(L2Character target : aimingTarget.getAroundCharacters(_skillRadius, 128))
    {
      if(terr != null && !terr.isInside(target))
      {
        continue;
      }
      if(target == null || activeChar == target || activeChar.getPlayer() != null && activeChar.getPlayer() == target.getPlayer())
      {
        continue;
      }
      if(getId() == SKILL_DETECTION && target.isInvisible() && target.getEffectList().getEffectByType(EffectType.Invisible) != null)
      {
        target.getEffectList().stopEffects(EffectType.Invisible);
      }
      if(checkTarget(activeChar, target, aimingTarget, forceUse, false) != null)
      {
        continue;
      }
      if(!(activeChar instanceof L2DecoyInstance) && activeChar.isNpc() && target.isNpc())
      {
        continue;
      }
      targets.add(target);
      count++;
      if(count >= 20 && !activeChar.isRaid())
      {
        break;
      }
    }
  }

  /**
   * Создает и применяет эффекты скилла. Выполняется в отдельном потоке.
   */
  public final void getEffects(final L2Character effector, final L2Character effected, final boolean calcChance, final boolean applyOnCaster)
  {
    if(isPassive() || _effectTemplates == null || _effectTemplates.length == 0 || effector == null || effected == null)
    {
      return;
    }
    // Mystic Immunity Makes a target temporarily immune to buffs/debuffs
    if(effected.isEffectImmune())
    {
      //effector.sendMessage(new CustomMessage("l2p.gameserver.skills.Formulas.NoChance", effector).addString(effected.getName()).addString(getName()));
      effector.sendPacket(new SystemMessage(SystemMessage.C1_HAS_RESISTED_YOUR_S2).addString(effected.getName()).addSkillName(_displayId, _displayLevel));
      return;
    }
   
    if (Config.DisableDeBuffInCommandChannel)
    {
      if (!(effector instanceof L2Player))
        return;
     
      if (!(effected instanceof L2Player))
        return;
     
      L2Party p1 = ((L2Player) effector).getParty();
      L2Party p2 = ((L2Player) effected).getParty();
      if (p1 == null || p2 == null)
        return;
     
      L2CommandChannel c1 = p1.getCommandChannel();
      L2CommandChannel c2 = p2.getCommandChannel();
     
      if (c1 == null || c2 == null)
        return;
     
      if (getSkillType() == SkillType.DEBUFF && c1 == c2)
        return;
    }
    // No effect on invulnerable characters unless they cast it themselves.
    if(effector != effected && isOffensive() && effected.isInvul())
    {
      if(effector.isPlayer())
      {
        effector.sendPacket(new SystemMessage(SystemMessage.C1_HAS_RESISTED_YOUR_S2).addString(effected.getName()).addSkillName(_displayId, _displayLevel));
      }
      return;
    }
    // No effect on doors/walls
    if(effected.isDoor())
    {
      return;
    }
    if(getSkillType() == SkillType.TRANSFORMATION)
    {
      if(effected.isPlayer())
      {
        L2Player p = (L2Player) effected;
        if(p.isMounted())
        {
          p.unMount();
        }
      }
    }
    final int sps = effector.getChargedSpiritShot();
    ThreadPoolManager.getInstance().executeGeneral(new Runnable()
    {
      public void run()
      {
        final int mastery = effector.getSkillMastery(getId());
        if(mastery == 2 && !applyOnCaster)
        {
          effector.removeSkillMastery(getId());
        }
        boolean success = false;
loop:
        for(EffectTemplate et : _effectTemplates)
        {
          if(applyOnCaster != et._applyOnCaster || et._counter == 0)
          {
            continue;
          }
          L2Character target = et._applyOnCaster ? effector : effected;
          if(et._stackOrder == -1)
          {
            if(et._stackType != EffectTemplate.NO_STACK)
            {
              for(L2Effect e : target.getEffectList().getAllEffects())
              {
                if(e.getStackType().equalsIgnoreCase(et._stackType))
                {
                  continue loop;
                }
              }
            }
            else if(target.getEffectList().getEffectsBySkillId(getId()) != null)
            {
              continue;
            }
          }
          if(target.isRaid() && et.getEffectType().isRaidImmune())
          {
            effector.sendPacket(new SystemMessage(SystemMessage.C1_HAS_RESISTED_YOUR_S2).addString(effected.getName()).addSkillName(_displayId, _displayLevel));
            continue;
          }
          if(isBlockedByChar(target, et))
          {
            continue;
          }
          Env env = new Env(effector, target, L2Skill.this);
          int chance = et.getParam().getInteger("activateRate", getActivateRate());
          if(calcChance && !et._applyOnCaster)
          {
            env.value = chance;
            if(!Formulas.calcSkillSuccess(env, et.getEffectType().getResistType(), et.getEffectType().getAttibuteType(), sps))
            {
              effector.sendPacket(new SystemMessage(SystemMessage.C1_HAS_RESISTED_YOUR_S2).addString(effected.getName()).addSkillName(_displayId, _displayLevel));
              continue;
            }
          }
          if(target != effector && isOffensive() && !effector.isTrap())
          {
            if(Rnd.chance(target.calcStat(isMagic() ? Stats.REFLECT_MAGIC_DEBUFF : Stats.REFLECT_PHYSIC_DEBUFF, 0, effector, L2Skill.this)))
            {
              target.sendPacket(new SystemMessage(SystemMessage.YOU_COUNTERED_C1S_ATTACK).addName(effector));
              effector.sendPacket(new SystemMessage(SystemMessage.C1_DODGES_THE_ATTACK).addName(target));
              target = effector;
              env.target = target;
            }
          }
          if(success)
          {
            env.arraymap = ArrayMap.set(env.arraymap, Env.FirstEffectSuccess, Integer.MAX_VALUE);
          }
          if(mastery != 0)
          {
            env.arraymap = ArrayMap.set(env.arraymap, Env.SkillMastery, mastery);
          }
          final L2Effect e = et.getEffect(env);
          if(e != null)
          {
            if(chance > 0)
            {
              success = true;
            }
            if(e._count == 1 && e.getPeriod() == 0)
            {
              // Эффекты однократного действия не шедулятся, а применяются немедленно
              // Как правило это побочные эффекты для скиллов моментального действия
              e.onStart();
              e.onActionTime();
              e.onExit();
            }
            else
            {
              e.getEffected().getEffectList().addEffect(e);
            }
          }
        }
        if(calcChance)
        {
          if(success)
          {
            effector.sendPacket(new SystemMessage(SystemMessage.S1_HAS_SUCCEEDED).addSkillName(_displayId, _displayLevel));
          }
          else
          {
            effector.sendPacket(new SystemMessage(SystemMessage.S1_HAS_FAILED).addSkillName(_displayId, _displayLevel));
          }
        }
      }
    });
  }

  public final void attach(EffectTemplate effect)
  {
    if(_effectTemplates == null)
    {
      _effectTemplates = new EffectTemplate[]
        {
          effect
        };
    }
    else
    {
      int len = _effectTemplates.length;
      EffectTemplate[] tmp = new EffectTemplate[len + 1];
      System.arraycopy(_effectTemplates, 0, tmp, 0, len);
      tmp[len] = effect;
      _effectTemplates = tmp;
    }
  }

  public final void attach(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 Func[] getStatFuncs()
  {
    if(_funcTemplates == null)
    {
      return _emptyFunctionSet;
    }
    GArray<Func> funcs = new GArray<Func>();
    for(FuncTemplate t : _funcTemplates)
    {
      Func f = t.getFunc(this); // skill is owner
      if(f != null)
      {
        funcs.add(f);
      }
    }
    if(funcs.size() == 0)
    {
      return _emptyFunctionSet;
    }
    return funcs.toArray(new Func[funcs.size()]);
  }

  @Override
  public boolean equals(Object obj)
  {
    if(this == obj)
    {
      return true;
    }
    if(obj == null)
    {
      return false;
    }
    if(getClass() != obj.getClass())
    {
      return false;
    }
    final L2Skill other = (L2Skill) obj;
    if(_displayId == null)
    {
      if(other._displayId != null)
      {
        return false;
      }
    }
    else if(!_displayId.equals(other._displayId))
    {
      return false;
    }
    if(_displayLevel == null)
    {
      if(other._displayLevel != null)
      {
        return false;
      }
    }
    else if(!_displayLevel.equals(other._displayLevel))
    {
      return false;
    }
    if(_id == null)
    {
      if(other._id != null)
      {
        return false;
      }
    }
    else if(!_id.equals(other._id))
    {
      return false;
    }
    if(_level == null)
    {
      if(other._level != null)
      {
        return false;
      }
    }
    else if(!_level.equals(other._level))
    {
      return false;
    }
    return true;
  }

  @Override
  public int hashCode()
  {
    final int prime = 31;
    int result = 1;
    result = prime * result + (_displayId == null ? 0 : _displayId.hashCode());
    result = prime * result + (_displayLevel == null ? 0 : _displayLevel.hashCode());
    result = prime * result + (_id == null ? 0 : _id.hashCode());
    result = prime * result + (_level == null ? 0 : _level.hashCode());
    return result;
  }

  public final void attach(Condition c)
  {
    _preCondition = (Condition[]) Util.addElementToArray(_preCondition, c, Condition.class);
  }

  public final boolean altUse()
  {
    return _isAltUse;
  }

  public final boolean canTeachBy(int npcId)
  {
    return _teachers == null || _teachers.contains(npcId);
  }

  public final int getActivateRate()
  {
    return _activateRate;
  }

  public AddedSkill[] getAddedSkills()
  {
    return _addedSkills == null ? _emptyAddedSkills : _addedSkills;
  }

  public final boolean getCanLearn(ClassId cls)
  {
    return _canLearn == null || _canLearn.contains(cls);
  }

  /**
   * @return Returns the castRange.
   */
  public final int getCastRange()
  {
    return _castRange;
  }

  public final int getAOECastRange()
  {
    return Math.max(_castRange, _skillRadius);
  }

  public int getCondCharges()
  {
    return _condCharges;
  }

  public final int getCoolTime()
  {
    return _coolTime;
  }

  public boolean getCorpse()
  {
    return _isCorpse;
  }

  public int getDelayedEffect()
  {
    return _delayedEffect;
  }

  public final int getDisplayId()
  {
    return _displayId;
  }

  public short getDisplayLevel()
  {
    return _displayLevel;
  }

  public int getEffectPoint()
  {
    return _effectPoint;
  }

  public EffectTemplate[] getEffectTemplates()
  {
    return _effectTemplates;
  }

  public L2Effect getSameByStackType(ConcurrentLinkedQueue<L2Effect> ef_list)
  {
    if(_effectTemplates == null)
    {
      return null;
    }
    L2Effect ret;
    for(EffectTemplate et : _effectTemplates)
    {
      if(et != null && (ret = et.getSameByStackType(ef_list)) != null)
      {
        return ret;
      }
    }
    return null;
  }

  public L2Effect getSameByStackType(EffectList ef_list)
  {
    return getSameByStackType(ef_list.getAllEffects());
  }

  public L2Effect getSameByStackType(L2Character actor)
  {
    return getSameByStackType(actor.getEffectList().getAllEffects());
  }

  public final Element getElement()
  {
    return _element;
  }

  public final int getElementPower()
  {
    return _elementPower;
  }

  public L2Skill getFirstAddedSkill()
  {
    if(_addedSkills == null)
    {
      return null;
    }
    return _addedSkills[0].getSkill();
  }

  public int getFlyRadius()
  {
    return _flyRadius;
  }

  public FlyType getFlyType()
  {
    return _flyType;
  }

  public boolean isFlyToBack()
  {
    return _flyToBack;
  }

  public int getForceId()
  {
    return _forceId;
  }

  public final int getHitTime()
  {
    return _hitTime;
  }

  /**
   * @return Returns the hpConsume.
   */
  public final int getHpConsume()
  {
    return _hpConsume;
  }

  /**
   * @return Returns the id.
   */
  public int getId()
  {
    return _id;
  }

  public void setId(int id)
  {
    _id = id;
  }

  /**
   * @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 short getLevel()
  {
    return _level;
  }

  public final short getBaseLevel()
  {
    return _baseLevel;
  }

  public final void setBaseLevel(short baseLevel)
  {
    _baseLevel = baseLevel;
  }

  public final int getLevelModifier()
  {
    return _levelModifier;
  }

  public final int getMagicLevel()
  {
    return _magicLevel;
  }

  public int getMatak()
  {
    return _matak;
  }

  public int getMinPledgeClass()
  {
    return _minPledgeClass;
  }

  public int getMinRank()
  {
    return _minRank;
  }

  /**
   * @return Returns the mpConsume as _mpConsume1 + _mpConsume2.
   */
  public final double getMpConsume()
  {
    return _mpConsume1 + _mpConsume2;
  }

  /**
   * @return Returns the mpConsume1.
   */
  public final double getMpConsume1()
  {
    return _mpConsume1;
  }

  /**
   * @return Returns the mpConsume2.
   */
  public final double getMpConsume2()
  {
    return _mpConsume2;
  }

  /**
   * @return Returns the name.
   */
  public final String getName()
  {
    return _name;
  }

  public int getNegatePower()
  {
    return _negatePower;
  }

  public int getNegateSkill()
  {
    return _negateSkill;
  }

  public NextAction getNextAction()
  {
    return _nextAction;
  }

  public int getNpcId()
  {
    return _npcId;
  }

  public int getNumCharges()
  {
    return _numCharges;
  }

  public final double getPower(L2Character target)
  {
    if(target != null)
    {
      if(target.isPlayable())
      {
        return getPowerPvP();
      }
      if(target.isMonster())
      {
        return getPowerPvE();
      }
    }
    return getPower();
  }

  public final double getPower()
  {
    return _power;
  }

  public final double getPowerPvP()
  {
    return _powerPvP != 0 ? _powerPvP : _power;
  }

  public final double getPowerPvE()
  {
    return _powerPvE != 0 ? _powerPvE : _power;
  }

  public final long getReuseDelay()
  {
    return _reuseDelay;
  }

  /**
   * для изменения времени отката из скриптов
   */
  public final void setReuseDelay(long newReuseDelay)
  {
    _reuseDelay = newReuseDelay;
  }

  public final GArray<Integer> getReuseGroup()
  {
    return _reuseGroups.get(_reuseGroupId);
  }

  public final int getReuseGroupId()
  {
    return _reuseGroupId;
  }

  public final int getSavevs()
  {
    return _savevs;
  }

  public final boolean getShieldIgnore()
  {
    return _isShieldignore;
  }

  public final int getSkillInterruptTime()
  {
    return _skillInterruptTime;
  }

  public final int getSkillRadius()
  {
    return _skillRadius;
  }

  public final SkillType getSkillType()
  {
    return _skillType;
  }

  public int getSoulsConsume()
  {
    return _soulsConsume;
  }

  public int getSymbolId()
  {
    return _symbolId;
  }

  public final SkillTargetType getTargetType()
  {
    return _targetType;
  }

  public final int getWeaponsAllowed()
  {
    return _weaponsAllowed;
  }

  public double getLethal1()
  {
    return _lethal1;
  }

  public double getLethal2()
  {
    return _lethal2;
  }

  public String getBaseValues()
  {
    return _baseValues;
  }

  public boolean isBlockedByChar(L2Character effected, EffectTemplate et)
  {
    if(et._funcTemplates == null)
    {
      return false;
    }
    for(FuncTemplate func : et._funcTemplates)
    {
      if(func != null && effected.checkBlockedStat(func._stat))
      {
        return true;
      }
    }
    return false;
  }

  public final boolean isCancelable()
  {
    return _isCancelable && getSkillType() != SkillType.TRANSFORMATION && !isToggle();
  }

  /**
   * Является ли скилл общим
   */
  public final boolean isCommon()
  {
    return _isCommon;
  }

  public final int getCriticalRate()
  {
    return _criticalRate;
  }

  public final boolean isHandler()
  {
    return _isItemHandler;
  }

  public final boolean isMagic()
  {
    return _isMagic;
  }

  public void setOperateType(SkillOpType type)
  {
    _operateType = type;
  }

  public double getChanceForAction(TriggerActionType action)
  {
    return _triggerActions.get(action);
  }

  public TreeMap<TriggerActionType, Double> getTriggerActions()
  {
    return _triggerActions;
  }

  public final boolean isOnAction()
  {
    return _operateType == SkillOpType.OP_ON_ACTION;
  }

  public final boolean isOverhit()
  {
    return _isOverhit;
  }

  public final boolean isActive()
  {
    return _operateType == SkillOpType.OP_ACTIVE;
  }

  public final boolean isPassive()
  {
    return _operateType == SkillOpType.OP_PASSIVE;
  }

  public final boolean isLikePassive()
  {
    return _operateType == SkillOpType.OP_PASSIVE || _operateType == SkillOpType.OP_ON_ACTION;
  }

  public boolean isSaveable()
  {
    if(!Config.ALT_SAVE_UNSAVEABLE && (isMusic() || _name.startsWith("Herb of")))
    {
      return false;
    }
    return _isSaveable;
  }

  /**
   * На некоторые скиллы и хендлеры предметов скорости каста/атаки не влияет
   */
  public final boolean isSkillTimePermanent()
  {
    return _isSkillTimePermanent || _isItemHandler || _name.contains("Talisman");
  }

  public final boolean isReuseDelayPermanent()
  {
    return _isReuseDelayPermanent || _isItemHandler;
  }

  public boolean isDeathlink()
  {
    return _deathlink;
  }

  public boolean isBasedOnTargetDebuff()
  {
    return _basedOnTargetDebuff;
  }

  public boolean isSoulBoost()
  {
    return _isSoulBoost;
  }

  public boolean isChargeBoost()
  {
    return _isChargeBoost;
  }

  public boolean isUsingWhileCasting()
  {
    return _isUsingWhileCasting;
  }

  public boolean isBehind()
  {
    return _isBehind;
  }

  /**
   * Может ли скилл тратить шоты, для хендлеров всегда false
   */
  public boolean isSSPossible()
  {
    return Boolean.TRUE.equals(_isUseSS) || (_isUseSS == null && !_isItemHandler && !isMusic() && isActive() && !(getTargetType() == SkillTargetType.TARGET_SELF && !isMagic()));
  }

  public final boolean isSuicideAttack()
  {
    return _isSuicideAttack;
  }

  public final boolean isToggle()
  {
    return _operateType == SkillOpType.OP_TOGGLE;
  }

  public void setCastRange(int castRange)
  {
    _castRange = castRange;
  }

  public void setDisplayLevel(Short lvl)
  {
    _displayLevel = lvl;
  }

  public void setHitTime(int hitTime)
  {
    _hitTime = hitTime;
  }

  public void setHpConsume(int hpConsume)
  {
    _hpConsume = hpConsume;
  }

  public void setIsMagic(boolean isMagic)
  {
    _isMagic = isMagic;
  }

  public final void setMagicLevel(int newlevel)
  {
    _magicLevel = newlevel;
  }

  public void setMpConsume1(double mpConsume1)
  {
    _mpConsume1 = mpConsume1;
  }

  public void setMpConsume2(double mpConsume2)
  {
    _mpConsume2 = mpConsume2;
  }

  public void setName(String name)
  {
    _name = name;
  }

  public void setOverhit(final boolean isOverhit)
  {
    _isOverhit = isOverhit;
  }

  public final void setPower(double power)
  {
    _power = power;
  }

  public void setSkillInterruptTime(int skillInterruptTime)
  {
    _skillInterruptTime = skillInterruptTime;
  }

  public boolean isItemSkill()
  {
    return _name.contains("Item Skill") || _name.contains("Talisman");
  }

  @Override
  public String toString()
  {
    return _name + "[id=" + _id + ",lvl=" + _level + "]";
  }

  public abstract void useSkill(L2Character activeChar, GArray<L2Character> targets);

  /**
   * Такие скиллы не аггрят цель, и не флагают чара, но являются "плохими"
   */
  public boolean isAI()
  {
    switch(_skillType)
    {
      case AGGRESSION:
      case AIEFFECTS:
      case SOWING:
      case DELETE_HATE:
      case DELETE_HATE_OF_ME:
        return true;
      default:
        return false;
    }
  }

  public boolean isAoE()
  {
    switch(_targetType)
    {
      case TARGET_AREA:
      case TARGET_AREA_AIM_CORPSE:
      case TARGET_AURA:
      case TARGET_PET_AURA:
      case TARGET_MULTIFACE:
      case TARGET_MULTIFACE_AURA:
      case TARGET_TUNNEL:
        return true;
      default:
        return false;
    }
  }

  public boolean isNotTargetAoE()
  {
    switch(_targetType)
    {
      case TARGET_AURA:
      case TARGET_MULTIFACE_AURA:
      case TARGET_ALLY:
      case TARGET_CLAN:
      case TARGET_CLAN_ONLY:
      case TARGET_PARTY:
        return true;
      default:
        return false;
    }
  }

  public boolean isOffensive()
  {
    if(_isOffensive != null)
    {
      return _isOffensive;
    }
    switch(_skillType)
    {
      case AGGRESSION:
      case AIEFFECTS:
      case BLEED:
      case CANCEL:
      case DEBUFF:
      case DOT:
      case DRAIN:
      case DRAIN_SOUL:
      case LETHAL_SHOT:
      case MANADAM:
      case MDAM:
      case MDOT:
      case MUTE:
      case PARALYZE:
      case PDAM:
      case CPDAM:
      case POISON:
      case ROOT:
      case SLEEP:
      case SOULSHOT:
      case SPIRITSHOT:
      case SPOIL:
      case STUN:
      case SWEEP:
      case HARVESTING:
      case TELEPORT_NPC:
      case SOWING:
      case DELETE_HATE:
      case DELETE_HATE_OF_ME:
      case DESTROY_SUMMON:
      case STEAL_BUFF:
      case DISCORD:
        return true;
      default:
        return false;
    }
  }

  public final boolean isForceUse()
  {
    return _isForceUse;
  }

  /**
   * Работают только против npc
   */
  public boolean isPvM()
  {
    if(_isPvm != null)
    {
      return _isPvm;
    }
    switch(_skillType)
    {
      case DISCORD:
        return true;
      default:
        return false;
    }
  }

  public final boolean isPvpSkill()
  {
    if(_isPvpSkill != null)
    {
      return _isPvpSkill;
    }
    switch(_skillType)
    {
      case BLEED:
      case CANCEL:
      case AGGRESSION:
      case DEBUFF:
      case DOT:
      case MDOT:
      case MUTE:
      case PARALYZE:
      case POISON:
      case ROOT:
      case SLEEP:
      case MANADAM:
      case DESTROY_SUMMON:
      case NEGATE_STATS:
      case NEGATE_EFFECTS:
      case STEAL_BUFF:
      case DELETE_HATE:
      case DELETE_HATE_OF_ME:
        return true;
      default:
        return false;
    }
  }

  public boolean isMusic()
  {
    return _isMusic;
  }

  public boolean oneTarget()
  {
    switch(_targetType)
    {
      case TARGET_CORPSE:
      case TARGET_CORPSE_PLAYER:
      case TARGET_HOLY:
      case TARGET_FLAGPOLE:
      case TARGET_ITEM:
      case TARGET_NONE:
      case TARGET_ONE:
      case TARGET_PARTY_ONE:
      case TARGET_PET:
      case TARGET_OWNER:
      case TARGET_ENEMY_PET:
      case TARGET_ENEMY_SUMMON:
      case TARGET_ENEMY_SERVITOR:
      case TARGET_SELF:
      case TARGET_UNLOCKABLE:
      case TARGET_CHEST:
      case TARGET_SIEGE:
        return true;
      default:
        return false;
    }
  }

  public int getCancelTarget()
  {
    return _cancelTarget;
  }

  public boolean isSkillInterrupt()
  {
    return _skillInterrupt;
  }

  public boolean isNotUsedByAI()
  {
    return _isNotUsedByAI;
  }

  /**
   * Игнорирование резистов
   */
  public boolean isIgnoreResists()
  {
    return _isIgnoreResists;
  }

  public boolean isNotAffectedByMute()
  {
    return _isNotAffectedByMute;
  }

  public boolean flyingTransformUsage()
  {
    return _flyingTransformUsage;
  }

  public int getCastCount()
  {
    return _castCount;
  }

  public int getEnchantLevelCount()
  {
    return _enchantLevelCount;
  }

  public void setEnchantLevelCount(int count)
  {
    _enchantLevelCount = count;
  }

  public boolean isClanSkill()
  {
    return _id >= 370 && _id <= 391 || _id >= 611 && _id <= 616;
  }

  public double getSimpleDamage(L2Character attacker, L2Character target)
  {
    if(isMagic())
    {
      // магический урон
      double mAtk = attacker.getMAtk(target, this);
      double mdef = target.getMDef(null, this);
      double power = getPower();
      int sps = attacker.getChargedSpiritShot() > 0 && isSSPossible() ? attacker.getChargedSpiritShot() * 2 : 1;
      return 91 * power * Math.sqrt(sps * mAtk) / mdef;
    }
    // физический урон
    double pAtk = attacker.getPAtk(target);
    double pdef = target.getPDef(attacker);
    double power = getPower();
    int ss = attacker.getChargedSoulShot() && isSSPossible() ? 2 : 1;
    return ss * (pAtk + power) * 70. / pdef;
  }

  public long getReuseForMonsters()
  {
    long min = 1000;
    switch(_skillType)
    {
      case PARALYZE:
      case DEBUFF:
      case CANCEL:
      case NEGATE_EFFECTS:
      case NEGATE_STATS:
      case STEAL_BUFF:
        min = 10000;
        break;
      case MUTE:
      case ROOT:
      case SLEEP:
      case STUN:
        min = 5000;
        break;
    }
    return Math.max(Math.max(_hitTime + _coolTime, _reuseDelay), min);
  }

  public double getAbsorbPart()
  {
    return _absorbPart;
  }

  public static void broadcastUseAnimation(L2Skill skill, L2Character user, GArray<L2Character> targets)
  {
    int displayId = 0, displayLevel = 0;
    if(skill.getEffectTemplates() != null)
    {
      displayId = skill.getEffectTemplates()[0]._displayId;
      displayLevel = skill.getEffectTemplates()[0]._displayLevel;
    }
    if(displayId == 0)
    {
      displayId = skill.getDisplayId();
    }
    if(displayLevel == 0)
    {
      displayLevel = skill.getDisplayLevel();
    }
    for(L2Character cha : targets)
    {
      user.broadcastPacket(new MagicSkillUse(user, cha, displayId, displayLevel, 0, 0));
    }
  }

  public boolean isOlympiadEnabled()
  {
    return _isOlympiadEnabled || !_isItemHandler && !_isAltUse;
  }
  /** Жрет много памяти (_set), включить только если будет необходимость
   public L2Skill clone()
   {
   L2Skill skill = getSkillType().makeSkill(_set);
   // Поля, перечисленные ниже, могут не совпадать с _set, поэтому обновляются отдельно
   // Необходимо сверять этот список с SkillTable.loadSqlSkills()
   skill.setPower(_power);
   skill.setBaseLevel(_baseLevel);
   skill.setMagicLevel(_magicLevel);
   skill.setCastRange(_castRange);
   skill.setName(_name);
   skill.setHitTime(_hitTime);
   skill.setSkillInterruptTime(_skillInterruptTime);
   skill.setIsMagic(_isMagic);
   skill.setOverhit(_isOverhit);
   skill.setHpConsume(_hpConsume);
   skill.setMpConsume1(_mpConsume1);
   skill.setMpConsume2(_mpConsume2);
   return skill;
   }
   */
}
TOP

Related Classes of l2p.gameserver.model.L2Skill

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.