Package l2p.gameserver.model

Source Code of l2p.gameserver.model.L2Effect$ActionDispelListener

package l2p.gameserver.model;

import java.util.logging.Logger;

import l2p.Config;
import l2p.extensions.listeners.MethodCollection;
import l2p.extensions.listeners.MethodInvokeListener;
import l2p.extensions.listeners.events.MethodEvent;
import l2p.gameserver.serverpackets.AbnormalStatusUpdate;
import l2p.gameserver.serverpackets.ExOlympiadSpelledInfo;
import l2p.gameserver.serverpackets.PartySpelled;
import l2p.gameserver.serverpackets.SystemMessage;
import l2p.gameserver.skills.AbnormalEffect;
import l2p.gameserver.skills.EffectType;
import l2p.gameserver.skills.Env;
import l2p.gameserver.skills.Stats;
import l2p.gameserver.skills.effects.EffectTemplate;
import l2p.gameserver.skills.funcs.Func;
import l2p.gameserver.skills.funcs.FuncOwner;
import l2p.gameserver.skills.funcs.FuncTemplate;
import l2p.gameserver.tables.SkillTable;
import l2p.gameserver.taskmanager.EffectTaskManager;
import l2p.util.ArrayMap;

public abstract class L2Effect implements Comparable<L2Effect>, FuncOwner
{
  protected static final Logger _log = Logger.getLogger(L2Effect.class.getName());

  public static enum EffectState
  {
    CREATED,
    ACTING,
    FINISHING,
    FINISHED
  }

  private static final Func[] _emptyFunctionSet = new Func[0];
  /**
   * Накладывающий эффект
   */
  protected final L2Character _effector;
  /**
   * Тот, на кого накладывают эффект
   */
  protected final L2Character _effected;
  protected final L2Skill _skill;
  protected final int _displayId;
  protected final int _displayLevel;
  // the value of an update
  private final double _value;
  // the current state
  protected EffectState _state;
  // period, milliseconds
  private long _period;
  private long _periodStartTime;
  // function templates
  private final FuncTemplate[] _funcTemplates;
  private final EffectType _effectType;
  // counter
  protected int _count;
  // abnormal effects
  private AbnormalEffect _abnormalEffect;
  private AbnormalEffect _abnormalEffect2;
  /**
   * The Identifier of the stack group
   */
  private final String _stackType;
  private final String _stackType2;
  /**
   * The position of the effect in the stack group
   */
  private final int _stackOrder;
  private boolean _inUse = false;
  private L2Effect _next = null;
  private boolean _active = false;
  private boolean _skillMastery = false;
  public final EffectTemplate _template;

  protected L2Effect(Env env, EffectTemplate template)
  {
    _template = template;
    _state = EffectState.CREATED;
    _skill = env.skill;
    _effector = env.character;
    _effected = env.target;
    _value = template._value;
    _funcTemplates = template._funcTemplates;
    _abnormalEffect = template._abnormalEffect;
    _abnormalEffect2 = template._abnormalEffect2;
    _stackType = template._stackType;
    _stackType2 = template._stackType2;
    _stackOrder = template._stackOrder;
    _effectType = template._effectType;
    _count = template._counter;
    _period = template.getPeriod();
    _displayId = template._displayId != 0 ? template._displayId : _skill.getDisplayId();
    _displayLevel = template._displayLevel != 0 ? template._displayLevel : _skill.getDisplayLevel();
    // Check for skill mastery duration time increase
    if(ArrayMap.get(env.arraymap, Env.SkillMastery) == 2)
    {
      if(_count > 1)
      {
        _count *= 2;
      }
      else
      {
        _period *= 2;
      }
      _skillMastery = true;
    }
    // Считаем влияние резистов
    if(!template._applyOnCaster && _skill.isOffensive() && !_skill.isIgnoreResists() && !_effector.isRaid())
    {
      double res = 0;
      if(_effectType.getResistType() != null)
      {
        res += _effected.calcStat(_effectType.getResistType(), _effector, _skill);
      }
      if(_effectType.getAttibuteType() != null)
      {
        res -= _effector.calcStat(_effectType.getAttibuteType(), _effected, _skill);
      }
      res += _effected.calcStat(Stats.DEBUFF_RECEPTIVE, _effector, _skill);
      if(res != 0)
      {
        double mod = 1 + Math.abs(0.01 * res);
        if(res > 0)
        {
          mod = 1. / mod;
        }
        if(_count > 1)
        {
          _count = (int) Math.floor(Math.max(_count * mod, 1));
        }
        else
        {
          _period = (long) Math.floor(Math.max(_period * mod, 1));
        }
      }
    }
    for(int i = 0; i < Config.SkillTimeModifier.length; i += 2)
    {
      if(_skill.getId() == Config.SkillTimeModifier[i])
      {
        _period = Config.SkillTimeModifier[i + 1] * 60000;
        break;
      }
    }
    if(_skill.getId() >= 4342 && _skill.getId() <= 4360)
    {
      _period *= Config.BUFFTIME_MODIFIER_CLANHALL;
    }
    _periodStartTime = System.currentTimeMillis();
  }

  public long getPeriod()
  {
    return _period;
  }

  public void setPeriod(long time)
  {
    _period = time;
  }

  public int getCount()
  {
    return _count;
  }

  public void setCount(int newcount)
  {
    _count = newcount;
  }

  public long getTime()
  {
    return System.currentTimeMillis() - _periodStartTime;
  }

  public long getPeriodStartTime()
  {
    return _periodStartTime;
  }

  /**
   * Возвращает оставшееся время в миллисекундах.
   */
  public long getTimeLeft()
  {
    return getPeriod() * getCount() - getTime();
  }

  public boolean isInUse()
  {
    return _inUse;
  }

  public void setInUse(boolean inUse)
  {
    _inUse = inUse;
    if(_inUse)
    {
      scheduleEffect();
    }
    else if(_state != EffectState.FINISHED)
    {
      _state = EffectState.FINISHING;
    }
  }

  public boolean isActive()
  {
    return _active;
  }

  /**
   * true означает что эффект зашедулен и сейчас не считается активным. Для неактивных эфектов не вызывается onActionTime.
   */
  public void setActive(boolean set)
  {
    _active = set;
  }

  public String getStackType()
  {
    return _stackType;
  }

  public String getStackType2()
  {
    return _stackType2;
  }

  public boolean checkStackType(String param)
  {
    return _stackType.equalsIgnoreCase(param) || _stackType2.equalsIgnoreCase(param);
  }

  public boolean checkStackType(L2Effect param)
  {
    return checkStackType(param.getStackType()) || checkStackType(param.getStackType2());
  }

  public int getStackOrder()
  {
    return _stackOrder;
  }

  public L2Skill getSkill()
  {
    return _skill;
  }

  public L2Character getEffector()
  {
    return _effector;
  }

  public L2Character getEffected()
  {
    return _effected;
  }

  public double calc()
  {
    return _value;
  }

  /**
   * Stop the L2Effect task and send Server->Client update packet.<BR><BR>
   * <p/>
   * <B><U> Actions</U> :</B><BR><BR>
   * <li>Cancel the effect in the the abnormal effect map of the L2Character </li>
   * <li>Stop the task of the L2Effect, remove it and update client magic icon </li><BR><BR>
   */
  public void exit()
  {
    if(_next != null)
    {
      _next.exit();
    }
    _next = null;
    if(_state == EffectState.FINISHED)
    {
      return;
    }
    if(_state != EffectState.CREATED)
    {
      _state = EffectState.FINISHING;
      scheduleEffect();
    }
    else
    {
      _state = EffectState.FINISHING;
    }
  }

  public boolean isEnded()
  {
    return _state == EffectState.FINISHED || _state == EffectState.FINISHING;
  }

  public boolean isFinishing()
  {
    return _state == EffectState.FINISHING;
  }

  public boolean isFinished()
  {
    return _state == EffectState.FINISHED;
  }

  /**
   * Stop the task of the L2Effect, remove it and update client magic icon.<BR><BR>
   * <p/>
   * <B><U> Actions</U> :</B><BR><BR>
   * <li>Cancel the task </li>
   * <li>Stop and remove L2Effect from L2Character and update client magic icon </li><BR><BR>
   */
  private synchronized void stopEffectTask()
  {
    _effected.getEffectList().removeEffect(this);
    updateEffects();
  }

  private ActionDispelListener _listener;

  private class ActionDispelListener implements MethodInvokeListener, MethodCollection
  {
    public boolean accept(MethodEvent event)
    {
      return event.getMethodName().equals(onStartAttack) || event.getMethodName().equals(onStartCast) || event.getMethodName().equals(onStartAltCast);
    }

    public void methodInvoked(MethodEvent e)
    {
      exit();
    }
  }

  public boolean checkCondition()
  {
    return true;
  }

  /**
   * Notify started
   */
  public void onStart()
  {
    if(_abnormalEffect != AbnormalEffect.NULL)
    {
      getEffected().startAbnormalEffect(_abnormalEffect);
    }
    else if(getEffectType().getAbnormal() != null)
    {
      getEffected().startAbnormalEffect(getEffectType().getAbnormal());
    }
    if(_abnormalEffect2 != AbnormalEffect.NULL)
    {
      getEffected().startAbnormalEffect(_abnormalEffect2);
    }
    if(_template._cancelOnAction)
    {
      getEffected().addMethodInvokeListener(_listener = new ActionDispelListener());
    }
  }

  /**
   * Cancel the effect in the the abnormal effect map of the effected L2Character.<BR><BR>
   */
  public void onExit()
  {
    if(_abnormalEffect != AbnormalEffect.NULL)
    {
      getEffected().stopAbnormalEffect(_abnormalEffect);
    }
    else if(getEffectType().getAbnormal() != null)
    {
      getEffected().stopAbnormalEffect(getEffectType().getAbnormal());
    }
    if(_abnormalEffect2 != AbnormalEffect.NULL)
    {
      getEffected().stopAbnormalEffect(_abnormalEffect2);
    }
    if(_template._cancelOnAction)
    {
      getEffected().removeMethodInvokeListener(_listener);
    }
  }

  /**
   * Return true for continuation of this effect
   */
  public abstract boolean onActionTime();

  public final void scheduleEffect()
  {
    L2Character effected = getEffected();
    if(effected == null)
    {
      return;
    }
    // Если персонаж выходит (или уже вышел) из игры, просто останавливаем эффект
    if(_state != EffectState.FINISHED && effected.isPlayer() && ((L2Player) effected).isDeleting())
    {
      _state = EffectState.FINISHED;
      _inUse = false;
      onExit();
      stopEffectTask();
      return;
    }
    if(_state == EffectState.CREATED)
    {
      if(!checkCondition())
      {
        // TODO Переделать так, чтобы проверка вызывалась до owner.addStatFuncs(newEffect.getStatFuncs()); и эффект вообще не добавлялся игроку, если условие не прошло.
        // Учесть случаи, когда эффект ставится в очередь, либо вынимается из очереди. Лучше всего делать проверку еще до постановки в очередь.
        // Но не забыть, что условия могут подойти вначале, но не подойти после вынимания из очереди.
        // Сейчас вся очередь уничтожается, если условие не подошло. Это может произойти, только если этот эффект уже сам в очереди, что конечно маловероятно :)
        exit(); // Т.к. _state CREATED, никаких действий не выполнится
        _effected.getEffectList().removeEffect(this); // Удаляем эффект у игрока
        return;
      }
      _state = EffectState.ACTING;
      onStart();
      // Fake Death и Silent Move не отображаются
      // Отображать сообщение только для первого эффекта скилла
      if(_skill.getId() != 60 && _skill.getId() != 221 && getEffected().getEffectList().getEffectsCountForSkill(getSkill().getId()) == 1)
      {
        getEffected().sendPacket(new SystemMessage(SystemMessage.S1_S2S_EFFECT_CAN_BE_FELT).addSkillName(_displayId, _displayLevel));
      }
      updateEffects(); // Обрабатываем отображение статов
      EffectTaskManager.getInstance().addDispelTask(this, (int) (_period / 1000));
      _periodStartTime = System.currentTimeMillis();
      return;
    }
    if(_state == EffectState.ACTING)
    {
      if(_count > 0)
      {
        _count--;
        if((!isActive() || onActionTime()) && _count > 0)
        {
          return;
        }
      }
      _state = EffectState.FINISHING;
    }
    if(_state == EffectState.FINISHING)
    {
      _state = EffectState.FINISHED;
      // Для ускоренной "остановки" эффекта
      _inUse = false;
      // Cancel the effect in the the abnormal effect map of the L2Character
      onExit();
      // If the time left is equal to zero, send the message
      // Отображать сообщение только для последнего оставшегося эффекта скилла
      if(_count <= 0 && getEffected().getEffectList().getEffectsCountForSkill(getSkill().getId()) == 1)
      {
        getEffected().sendPacket(new SystemMessage(SystemMessage.S1_HAS_WORN_OFF).addSkillName(_displayId, _displayLevel));
      }
      // Stop the task of the L2Effect, remove it and update client magic icon
      stopEffectTask();
      if(getSkill().getDelayedEffect() > 0)
      {
        SkillTable.getInstance().getInfo(getSkill().getDelayedEffect(), 1).getEffects(_effector, _effected, false, false);
      }
    }
  }

  public void updateEffects()
  {
    _effected.updateStats();
  }

  public Func[] getStatFuncs()
  {
    if(_funcTemplates == null)
    {
      return _emptyFunctionSet;
    }
    Func[] funcs = new Func[_funcTemplates.length];
    for(int i = 0; i < funcs.length; i++)
    {
      Func f = _funcTemplates[i].getFunc(this); // effect is owner
      funcs[i] = f;
    }
    return funcs;
  }

  public void addIcon(AbnormalStatusUpdate mi)
  {
    if(_state != EffectState.ACTING || _displayId < 0)
    {
      return;
    }
    int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : (int) (getTimeLeft() / 1000);
    mi.addEffect(_displayId, _displayLevel, duration);
  }

  public void addPartySpelledIcon(PartySpelled ps)
  {
    if(_state != EffectState.ACTING || _displayId < 0)
    {
      return;
    }
    int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : (int) (getTimeLeft() / 1000);
    ps.addPartySpelledEffect(_displayId, _displayLevel, duration);
  }

  public void addOlympiadSpelledIcon(L2Player player, ExOlympiadSpelledInfo os)
  {
    if(_state != EffectState.ACTING || _displayId < 0)
    {
      return;
    }
    int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : (int) (getTimeLeft() / 1000);
    os.addSpellRecivedPlayer(player);
    os.addEffect(_displayId, _displayLevel, duration);
  }

  protected int getLevel()
  {
    return _skill.getLevel();
  }

  public boolean containsStat(Stats stat)
  {
    if(_funcTemplates != null)
    {
      for(int i = 0; i < _funcTemplates.length; i++)
      {
        if(_funcTemplates[i]._stat == stat)
        {
          return true;
        }
      }
    }
    return false;
  }

  public EffectType getEffectType()
  {
    return _effectType;
  }

  public boolean isSkillMasteryEffect()
  {
    return _skillMastery;
  }

  public int compareTo(L2Effect obj)
  {
    if(obj.equals(this))
    {
      return 0;
    }
    return 1;
  }

  public void removeNext()
  {
    _next = null;
  }

  public void scheduleNext(L2Effect e)
  {
    if(_next != null && e != null && _next.maybeScheduleNext(e) == 0)
    {
      return;
    }
    _next = e;
    if(_next != null && !_next.isInUse())
    {
      _next.setInUse(true);
    }
  }

  public L2Effect getNext()
  {
    return _next;
  }

  /**
   * @returns 0 - игнорировать новый эффект, 1 - использовать новый эффект
   */
  public int maybeScheduleNext(L2Effect newEffect)
  {
    //231
    if(newEffect.getStackOrder() < getStackOrder()) // новый эффект слабее
    {
      if(newEffect.getTimeLeft() <= getTimeLeft()) // новый эффект не длинее
      {
        return 0;
      } // новый эффект бесполезен
      scheduleNext(newEffect); // пробуем пристроить новый эффект в очередь
      return 0; // если пристроить новый эффект не удалось - сбрасываем за ненадобностью
    }
    if(newEffect.getStackOrder() == getStackOrder()) // эффекты равны
    {
      if(newEffect.getTimeLeft() <= getTimeLeft()) // новый эффект не длиннее
      {
        return 0;
      } // новый эффект бесполезен
      // Чистим все ненужные зашедуленные
      L2Effect next = this, previous = this;
      while((next = next.getNext()) != null)
      {
        if(newEffect.getTimeLeft() > next.getTimeLeft())
        {
          previous.scheduleNext(next.getNext());
          next.removeNext();
          next.exit();
          next = previous;
          continue;
        }
        previous = next;
      }
      // Присоединяем зашедуленные эффекты от старого к новому
      if(getNext() != null && !getNext().isEnded())
      {
        newEffect.scheduleNext(getNext());
      }
      // Отсоединяем зашедуленные от текущего
      removeNext();
      // Останавливаем текущий
      exit();
      return 1;
    }
    if(newEffect.getStackOrder() > getStackOrder())
    {
      // Если старый короче то просто остановить его
      if(newEffect.getTimeLeft() > getTimeLeft())
      {
        // наследуем зашедуленый старому если есть смысл
        if(getNext() != null && getNext().getTimeLeft() > newEffect.getTimeLeft())
        {
          newEffect.scheduleNext(getNext());
          removeNext();
        }
        exit();
        return 1;
      }
      // Если новый короче то зашедулить старый
      setActive(false);
      _effected.removeStatsOwner(this);
      _effected.getEffectList().removeFromList(this);
      newEffect.scheduleNext(this);
      return 1;
    }
    // сюда дойти не может
    return 1;
  }

  public AbnormalEffect getAbnormalEffect()
  {
    return _abnormalEffect;
  }

  public AbnormalEffect getAbnormalEffect2()
  {
    return _abnormalEffect2;
  }

  public boolean isSaveable()
  {
    return getTimeLeft() >= 15000 && getSkill().isSaveable();
  }

  public int getDisplayId()
  {
    return _displayId;
  }

  public int getDisplayLevel()
  {
    return _displayLevel;
  }

  @Override
  public String toString()
  {
    return "Skill: " + _skill + ", state: " + _state.name() + ", inUse: " + _inUse;
  }

  public boolean isFuncEnabled()
  {
    return isInUse();
  }

  public boolean overrideLimits()
  {
    return false;
  }

  public boolean isOffensive()
  {
    Boolean template = _template.getParam().getBool("isOffensive", null);
    if(template != null)
    {
      return template;
    }
    return getSkill().isOffensive();
  }
}
TOP

Related Classes of l2p.gameserver.model.L2Effect$ActionDispelListener

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.