Package lineage2.gameserver.model.instances

Source Code of lineage2.gameserver.model.instances.MonsterInstance

/*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package lineage2.gameserver.model.instances;

import gnu.trove.set.hash.TIntHashSet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import lineage2.commons.threading.RunnableImpl;
import lineage2.commons.util.Rnd;
import lineage2.gameserver.Config;
import lineage2.gameserver.ThreadPoolManager;
import lineage2.gameserver.cache.Msg;
import lineage2.gameserver.instancemanager.CursedWeaponsManager;
import lineage2.gameserver.model.AggroList.HateInfo;
import lineage2.gameserver.model.Creature;
import lineage2.gameserver.model.Effect;
import lineage2.gameserver.model.Manor;
import lineage2.gameserver.model.MinionList;
import lineage2.gameserver.model.Party;
import lineage2.gameserver.model.Playable;
import lineage2.gameserver.model.Player;
import lineage2.gameserver.model.Skill;
import lineage2.gameserver.model.base.Experience;
import lineage2.gameserver.model.base.TeamType;
import lineage2.gameserver.model.entity.Reflection;
import lineage2.gameserver.model.pledge.Clan;
import lineage2.gameserver.model.quest.Quest;
import lineage2.gameserver.model.quest.QuestEventType;
import lineage2.gameserver.model.quest.QuestState;
import lineage2.gameserver.model.reward.RewardItem;
import lineage2.gameserver.model.reward.RewardList;
import lineage2.gameserver.model.reward.RewardType;
import lineage2.gameserver.network.serverpackets.SocialAction;
import lineage2.gameserver.network.serverpackets.SystemMessage;
import lineage2.gameserver.stats.Stats;
import lineage2.gameserver.tables.SkillTable;
import lineage2.gameserver.templates.npc.Faction;
import lineage2.gameserver.templates.npc.NpcTemplate;
import lineage2.gameserver.utils.Location;

/**
* @author Mobius
* @version $Revision: 1.0 $
*/
public class MonsterInstance extends NpcInstance
{
  /**
   *
   */
  private static final long serialVersionUID = 1L;
 
  /**
   * @author Mobius
   */
  protected static final class RewardInfo
  {
    /**
     * Field _attacker.
     */
    protected Creature _attacker;
    /**
     * Field _dmg.
     */
    protected int _dmg = 0;
   
    /**
     * Constructor for RewardInfo.
     * @param attacker Creature
     * @param dmg int
     */
    public RewardInfo(final Creature attacker, final int dmg)
    {
      _attacker = attacker;
      _dmg = dmg;
    }
   
    /**
     * Method addDamage.
     * @param dmg int
     */
    public void addDamage(int dmg)
    {
      if (dmg < 0)
      {
        dmg = 0;
      }
      _dmg += dmg;
    }
   
    /**
     * Method hashCode.
     * @return int
     */
    @Override
    public int hashCode()
    {
      return _attacker.getObjectId();
    }
  }
 
  /**
   * Field minionMaintainTask.
   */
  private ScheduledFuture<?> minionMaintainTask;
  /**
   * Field minionList.
   */
  private final MinionList minionList;
  /**
   * Field _isSeeded.
   */
  private boolean _isSeeded;
  /**
   * Field _seederId.
   */
  private int _seederId;
  /**
   * Field _altSeed.
   */
  private boolean _altSeed;
  /**
   * Field _harvestItem.
   */
  private RewardItem _harvestItem;
  /**
   * Field harvestLock.
   */
  private final Lock harvestLock = new ReentrantLock();
  /**
   * Field overhitAttackerId.
   */
  private int overhitAttackerId;
  /**
   * Field _overhitDamage.
   */
  private double _overhitDamage;
  /**
   * Field _absorbersIds.
   */
  private TIntHashSet _absorbersIds;
  /**
   * Field absorbLock.
   */
  private final Lock absorbLock = new ReentrantLock();
  /**
   * Field _isSpoiled.
   */
  private boolean _isSpoiled;
  /**
   * Field spoilerId.
   */
  private int spoilerId;
  /**
   * Field _sweepItems.
   */
  private List<RewardItem> _sweepItems;
  /**
   * Field sweepLock.
   */
  private final Lock sweepLock = new ReentrantLock();
  /**
   * Field _isChampion.
   */
  private int _isChampion;
 
  /**
   * Constructor for MonsterInstance.
   * @param objectId int
   * @param template NpcTemplate
   */
  public MonsterInstance(int objectId, NpcTemplate template)
  {
    super(objectId, template);
    minionList = new MinionList(this);
  }
 
  /**
   * Method isMovementDisabled.
   * @return boolean
   */
  @Override
  public boolean isMovementDisabled()
  {
    return (getNpcId() == 18344) || (getNpcId() == 18345) || super.isMovementDisabled();
  }
 
  /**
   * Method isLethalImmune.
   * @return boolean
   */
  @Override
  public boolean isLethalImmune()
  {
    return (_isChampion > 0) || (getNpcId() == 22215) || (getNpcId() == 22216) || (getNpcId() == 22217) || super.isLethalImmune();
  }
 
  /**
   * Method isFearImmune.
   * @return boolean
   */
  @Override
  public boolean isFearImmune()
  {
    return (_isChampion > 0) || super.isFearImmune();
  }
 
  /**
   * Method isParalyzeImmune.
   * @return boolean
   */
  @Override
  public boolean isParalyzeImmune()
  {
    return (_isChampion > 0) || super.isParalyzeImmune();
  }
 
  /**
   * Method isAutoAttackable.
   * @param attacker Creature
   * @return boolean
   */
  @Override
  public boolean isAutoAttackable(Creature attacker)
  {
    return !attacker.isMonster();
  }
 
  /**
   * Method getChampion.
   * @return int
   */
  public int getChampion()
  {
    return _isChampion;
  }
 
  /**
   * Method setChampion.
   */
  public void setChampion()
  {
    if (getReflection().canChampions() && canChampion())
    {
      double random = Rnd.nextDouble();
      if ((Config.ALT_CHAMPION_CHANCE2 / 100.) >= random)
      {
        setChampion(2);
      }
      else if (((Config.ALT_CHAMPION_CHANCE1 + Config.ALT_CHAMPION_CHANCE2) / 100.) >= random)
      {
        setChampion(1);
      }
      else
      {
        setChampion(0);
      }
    }
    else
    {
      setChampion(0);
    }
  }
 
  /**
   * Method setChampion.
   * @param level int
   */
  public void setChampion(int level)
  {
    if (level == 0)
    {
      removeSkillById(4407);
      _isChampion = 0;
    }
    else
    {
      addSkill(SkillTable.getInstance().getInfo(4407, level));
      _isChampion = level;
    }
  }
 
  /**
   * Method canChampion.
   * @return boolean
   */
  public boolean canChampion()
  {
    return (getTemplate().rewardExp > 0) && (getTemplate().level <= Config.ALT_CHAMPION_TOP_LEVEL);
  }
 
  /**
   * Method getTeam.
   * @return TeamType
   */
  @Override
  public TeamType getTeam()
  {
    return getChampion() == 2 ? TeamType.RED : getChampion() == 1 ? TeamType.BLUE : TeamType.NONE;
  }
 
  /**
   * Method onSpawn.
   */
  @Override
  protected void onSpawn()
  {
    super.onSpawn();
    setCurrentHpMp(getMaxHp(), getMaxMp(), true);
    if (getMinionList().hasMinions())
    {
      if (minionMaintainTask != null)
      {
        minionMaintainTask.cancel(false);
        minionMaintainTask = null;
      }
      minionMaintainTask = ThreadPoolManager.getInstance().schedule(new MinionMaintainTask(), 1000L);
    }
  }
 
  /**
   * Method onDespawn.
   */
  @Override
  protected void onDespawn()
  {
    setOverhitDamage(0);
    setOverhitAttacker(null);
    clearSweep();
    clearHarvest();
    clearAbsorbers();
    super.onDespawn();
  }
 
  /**
   * Method getMinionList.
   * @return MinionList
   */
  @Override
  public MinionList getMinionList()
  {
    return minionList;
  }
 
  /**
   * @author Mobius
   */
  public class MinionMaintainTask extends RunnableImpl
  {
    /**
     * Method runImpl.
     */
    @Override
    public void runImpl()
    {
      if (isDead())
      {
        return;
      }
      getMinionList().spawnMinions();
    }
  }
 
  /**
   * Method getMinionPosition.
   * @return Location
   */
  public Location getMinionPosition()
  {
    return Location.findPointToStay(this, 100, 150);
  }
 
  /**
   * Method notifyMinionDied.
   * @param minion MinionInstance
   */
  public void notifyMinionDied(MinionInstance minion)
  {
  }
 
  /**
   * Method spawnMinion.
   * @param minion MonsterInstance
   */
  public void spawnMinion(MonsterInstance minion)
  {
    minion.setReflection(getReflection());
    if (getChampion() == 2)
    {
      minion.setChampion(1);
    }
    else
    {
      minion.setChampion(0);
    }
    minion.setHeading(getHeading());
    minion.setCurrentHpMp(minion.getMaxHp(), minion.getMaxMp(), true);
    minion.spawnMe(getMinionPosition());
  }
 
  /**
   * Method hasMinions.
   * @return boolean
   */
  @Override
  public boolean hasMinions()
  {
    return getMinionList().hasMinions();
  }
 
  /**
   * Method setReflection.
   * @param reflection Reflection
   */
  @Override
  public void setReflection(Reflection reflection)
  {
    super.setReflection(reflection);
    if (hasMinions())
    {
      for (MinionInstance m : getMinionList().getAliveMinions())
      {
        m.setReflection(reflection);
      }
    }
  }
 
  /**
   * Method onDelete.
   */
  @Override
  protected void onDelete()
  {
    if (minionMaintainTask != null)
    {
      minionMaintainTask.cancel(false);
      minionMaintainTask = null;
    }
    getMinionList().deleteMinions();
    super.onDelete();
  }
 
  /**
   * Method onDeath.
   * @param killer Creature
   */
  @Override
  protected void onDeath(Creature killer)
  {
    if (minionMaintainTask != null)
    {
      minionMaintainTask.cancel(false);
      minionMaintainTask = null;
    }
    calculateRewards(killer);
    super.onDeath(killer);
  }
 
  /**
   * Method onReduceCurrentHp.
   * @param damage double
   * @param attacker Creature
   * @param skill Skill
   * @param awake boolean
   * @param standUp boolean
   * @param directHp boolean
   */
  @Override
  protected void onReduceCurrentHp(double damage, Creature attacker, Skill skill, boolean awake, boolean standUp, boolean directHp)
  {
    if ((skill != null) && skill.isOverhit())
    {
      double overhitDmg = (getCurrentHp() - damage) * -1;
      if (overhitDmg <= 0)
      {
        setOverhitDamage(0);
        setOverhitAttacker(null);
      }
      else
      {
        setOverhitDamage(overhitDmg);
        setOverhitAttacker(attacker);
      }
    }
    super.onReduceCurrentHp(damage, attacker, skill, awake, standUp, directHp);
  }
 
  /**
   * Method calculateRewards.
   * @param lastAttacker Creature
   */
  public void calculateRewards(Creature lastAttacker)
  {
    Creature topDamager = getAggroList().getTopDamager();
    if ((lastAttacker == null) || !lastAttacker.isPlayable())
    {
      lastAttacker = topDamager;
    }
    if ((lastAttacker == null) || !lastAttacker.isPlayable())
    {
      return;
    }
    Player killer = lastAttacker.getPlayer();
    if (killer == null)
    {
      return;
    }
    Map<Playable, HateInfo> aggroMap = getAggroList().getPlayableMap();
    Quest[] quests = getTemplate().getEventQuests(QuestEventType.MOB_KILLED_WITH_QUEST);
    if ((quests != null) && (quests.length > 0))
    {
      List<Player> players = null;
      if (isRaid() && Config.ALT_NO_LASTHIT)
      {
        players = new ArrayList<>();
        for (Playable pl : aggroMap.keySet())
        {
          if (!pl.isDead() && (isInRangeZ(pl, Config.ALT_PARTY_DISTRIBUTION_RANGE) || killer.isInRangeZ(pl, Config.ALT_PARTY_DISTRIBUTION_RANGE)))
          {
            if (!players.contains(pl.getPlayer()))
            {
              players.add(pl.getPlayer());
            }
          }
        }
      }
      else if (killer.getParty() != null)
      {
        players = new ArrayList<>(killer.getParty().getMemberCount());
        for (Player pl : killer.getParty().getPartyMembers())
        {
          if (!pl.isDead() && (isInRangeZ(pl, Config.ALT_PARTY_DISTRIBUTION_RANGE) || killer.isInRangeZ(pl, Config.ALT_PARTY_DISTRIBUTION_RANGE)))
          {
            players.add(pl);
          }
        }
      }
      for (Quest quest : quests)
      {
        Player toReward = killer;
        if ((quest.getParty() != Quest.PARTY_NONE) && (players != null))
        {
          if (isRaid() || (quest.getParty() == Quest.PARTY_ALL))
          {
            for (Player pl : players)
            {
              QuestState qs = pl.getQuestState(quest.getName());
              if ((qs != null) && !qs.isCompleted())
              {
                quest.notifyKill(this, qs);
              }
            }
            toReward = null;
          }
          else
          {
            List<Player> interested = new ArrayList<>(players.size());
            for (Player pl : players)
            {
              QuestState qs = pl.getQuestState(quest.getName());
              if ((qs != null) && !qs.isCompleted())
              {
                interested.add(pl);
              }
            }
            if (interested.isEmpty())
            {
              continue;
            }
            toReward = interested.get(Rnd.get(interested.size()));
            if (toReward == null)
            {
              toReward = killer;
            }
          }
        }
        if (toReward != null)
        {
          QuestState qs = toReward.getQuestState(quest.getName());
          if ((qs != null) && !qs.isCompleted())
          {
            quest.notifyKill(this, qs);
          }
        }
      }
    }
    Map<Player, RewardInfo> rewards = new HashMap<>();
    for (HateInfo info : aggroMap.values())
    {
      if (info.damage <= 1)
      {
        continue;
      }
      Playable attacker = (Playable) info.attacker;
      Player player = attacker.getPlayer();
      RewardInfo reward = rewards.get(player);
      if (reward == null)
      {
        rewards.put(player, new RewardInfo(player, info.damage));
      }
      else
      {
        reward.addDamage(info.damage);
      }
    }
    Player[] attackers = rewards.keySet().toArray(new Player[rewards.size()]);
    double[] xpsp = new double[2];
    for (Player attacker : attackers)
    {
      if (attacker.isDead())
      {
        continue;
      }
      RewardInfo reward = rewards.get(attacker);
      if (reward == null)
      {
        continue;
      }
      Party party = attacker.getParty();
      int maxHp = getMaxHp();
      xpsp[0] = 0.;
      xpsp[1] = 0.;
      if (party == null)
      {
        int damage = Math.min(reward._dmg, maxHp);
        if (damage > 0)
        {
          if (isInRangeZ(attacker, Config.ALT_PARTY_DISTRIBUTION_RANGE))
          {
            xpsp = calculateExpAndSp(attacker.getLevel(), damage);
          }
          xpsp[0] = applyOverhit(killer, xpsp[0]);
          attacker.addExpAndCheckBonus(this, (long) xpsp[0], (long) xpsp[1], 1.);
        }
        rewards.remove(attacker);
      }
      else
      {
        int partyDmg = 0;
        int partylevel = 1;
        List<Player> rewardedMembers = new ArrayList<>();
        for (Player partyMember : party.getPartyMembers())
        {
          RewardInfo ai = rewards.remove(partyMember);
          if (partyMember.isDead() || !isInRangeZ(partyMember, Config.ALT_PARTY_DISTRIBUTION_RANGE))
          {
            continue;
          }
          if (ai != null)
          {
            partyDmg += ai._dmg;
          }
          rewardedMembers.add(partyMember);
          if (partyMember.getLevel() > partylevel)
          {
            partylevel = partyMember.getLevel();
          }
        }
        partyDmg = Math.min(partyDmg, maxHp);
        if (partyDmg > 0)
        {
          xpsp = calculateExpAndSp(partylevel, partyDmg);
          double partyMul = (double) partyDmg / maxHp;
          xpsp[0] *= partyMul;
          xpsp[1] *= partyMul;
          xpsp[0] = applyOverhit(killer, xpsp[0]);
          party.distributeXpAndSp(xpsp[0], xpsp[1], rewardedMembers, lastAttacker, this);
        }
      }
    }
    CursedWeaponsManager.getInstance().dropAttackable(this, killer);
    if ((topDamager == null) || !topDamager.isPlayable())
    {
      return;
    }
    for (Map.Entry<RewardType, RewardList> entry : getTemplate().getRewards().entrySet())
    {
      rollRewards(entry, lastAttacker, topDamager);
    }
  }
 
  /**
   * Method onRandomAnimation.
   */
  @Override
  public void onRandomAnimation()
  {
    if ((System.currentTimeMillis() - _lastSocialAction) > 10000L)
    {
      broadcastPacket(new SocialAction(getObjectId(), 1));
      _lastSocialAction = System.currentTimeMillis();
    }
  }
 
  /**
   * Method startRandomAnimation.
   */
  @Override
  public void startRandomAnimation()
  {
  }
 
  /**
   * Method getKarma.
   * @return int
   */
  @Override
  public int getKarma()
  {
    return 0;
  }
 
  /**
   * Method addAbsorber.
   * @param attacker Player
   */
  public void addAbsorber(final Player attacker)
  {
    if (attacker == null)
    {
      return;
    }
    if (getCurrentHpPercents() > 50)
    {
      return;
    }
    absorbLock.lock();
    try
    {
      if (_absorbersIds == null)
      {
        _absorbersIds = new TIntHashSet();
      }
      _absorbersIds.add(attacker.getObjectId());
    }
    finally
    {
      absorbLock.unlock();
    }
  }
 
  /**
   * Method isAbsorbed.
   * @param player Player
   * @return boolean
   */
  public boolean isAbsorbed(Player player)
  {
    absorbLock.lock();
    try
    {
      if (_absorbersIds == null)
      {
        return false;
      }
      if (!_absorbersIds.contains(player.getObjectId()))
      {
        return false;
      }
    }
    finally
    {
      absorbLock.unlock();
    }
    return true;
  }
 
  /**
   * Method clearAbsorbers.
   */
  public void clearAbsorbers()
  {
    absorbLock.lock();
    try
    {
      if (_absorbersIds != null)
      {
        _absorbersIds.clear();
      }
    }
    finally
    {
      absorbLock.unlock();
    }
  }
 
  /**
   * Method takeHarvest.
   * @return RewardItem
   */
  public RewardItem takeHarvest()
  {
    harvestLock.lock();
    try
    {
      RewardItem harvest;
      harvest = _harvestItem;
      clearHarvest();
      return harvest;
    }
    finally
    {
      harvestLock.unlock();
    }
  }
 
  /**
   * Method clearHarvest.
   */
  public void clearHarvest()
  {
    harvestLock.lock();
    try
    {
      _harvestItem = null;
      _altSeed = false;
      _seederId = 0;
      _isSeeded = false;
    }
    finally
    {
      harvestLock.unlock();
    }
  }
 
  /**
   * Method setSeeded.
   * @param player Player
   * @param seedId int
   * @param altSeed boolean
   * @return boolean
   */
  public boolean setSeeded(Player player, int seedId, boolean altSeed)
  {
    harvestLock.lock();
    try
    {
      if (isSeeded())
      {
        return false;
      }
      _isSeeded = true;
      _altSeed = altSeed;
      _seederId = player.getObjectId();
      _harvestItem = new RewardItem(Manor.getInstance().getCropType(seedId));
      if (getTemplate().rateHp > 1)
      {
        _harvestItem.count = Rnd.get(Math.round(getTemplate().rateHp), Math.round(1.5 * getTemplate().rateHp));
      }
    }
    finally
    {
      harvestLock.unlock();
    }
    return true;
  }
 
  /**
   * Method isSeeded.
   * @param player Player
   * @return boolean
   */
  public boolean isSeeded(Player player)
  {
    return isSeeded() && (_seederId == player.getObjectId()) && (getDeadTime() < 20000L);
  }
 
  /**
   * Method isSeeded.
   * @return boolean
   */
  public boolean isSeeded()
  {
    return _isSeeded;
  }
 
  /**
   * Method isSpoiled.
   * @return boolean
   */
  public boolean isSpoiled()
  {
    return _isSpoiled;
  }
 
  /**
   * Method isSpoiled.
   * @param player Player
   * @return boolean
   */
  public boolean isSpoiled(Player player)
  {
    if (!isSpoiled())
    {
      return false;
    }
    if ((player.getObjectId() == spoilerId) && (getDeadTime() < 20000L))
    {
      return true;
    }
    if (player.isInParty())
    {
      for (Player pm : player.getParty().getPartyMembers())
      {
        if ((pm.getObjectId() == spoilerId) && (getDistance(pm) < Config.ALT_PARTY_DISTRIBUTION_RANGE))
        {
          return true;
        }
      }
    }
    return false;
  }
 
  /**
   * Method setSpoiled.
   * @param player Player
   * @return boolean
   */
  public boolean setSpoiled(Player player)
  {
    sweepLock.lock();
    try
    {
      if (isSpoiled())
      {
        return false;
      }
      _isSpoiled = true;
      spoilerId = player.getObjectId();
    }
    finally
    {
      sweepLock.unlock();
    }
    return true;
  }
 
  /**
   * Method isSweepActive.
   * @return boolean
   */
  public boolean isSweepActive()
  {
    sweepLock.lock();
    try
    {
      return (_sweepItems != null) && (_sweepItems.size() > 0);
    }
    finally
    {
      sweepLock.unlock();
    }
  }
 
  /**
   * Method takeSweep.
   * @return List<RewardItem>
   */
  public List<RewardItem> takeSweep()
  {
    sweepLock.lock();
    try
    {
      List<RewardItem> sweep = _sweepItems;
      clearSweep();
      return sweep;
    }
    finally
    {
      sweepLock.unlock();
    }
  }
 
  /**
   * Method clearSweep.
   */
  public void clearSweep()
  {
    sweepLock.lock();
    try
    {
      _isSpoiled = false;
      spoilerId = 0;
      _sweepItems = null;
    }
    finally
    {
      sweepLock.unlock();
    }
  }
 
  /**
   * Method rollRewards.
   * @param entry Map.Entry<RewardType,RewardList>
   * @param lastAttacker Creature
   * @param topDamager Creature
   */
  public void rollRewards(Map.Entry<RewardType, RewardList> entry, final Creature lastAttacker, Creature topDamager)
  {
    RewardType type = entry.getKey();
    RewardList list = entry.getValue();
    if ((type == RewardType.SWEEP) && !isSpoiled())
    {
      return;
    }
    final Creature activeChar = type == RewardType.SWEEP ? lastAttacker : topDamager;
    final Player activePlayer = activeChar.getPlayer();
    if (activePlayer == null)
    {
      return;
    }
    final int diff = calculateLevelDiffForDrop(topDamager.getLevel());
    double mod = calcStat(Stats.REWARD_MULTIPLIER, 1., activeChar, null);
    mod *= Experience.penaltyModifier(diff, 9);
    List<RewardItem> rewardItems = list.roll(activePlayer, mod, this instanceof RaidBossInstance);
    switch (type)
    {
      case SWEEP:
        _sweepItems = rewardItems;
        break;
      default:
        for (RewardItem drop : rewardItems)
        {
          if (isSeeded() && !_altSeed && !drop.isAdena)
          {
            continue;
          }
          dropItem(activePlayer, drop.itemId, drop.count);
        }
        break;
    }
  }
 
  /**
   * Method calculateExpAndSp.
   * @param level int
   * @param damage long
   * @return double[]
   */
  private double[] calculateExpAndSp(int level, long damage)
  {
    int diff = level - getLevel();
    if ((level > 77) && (diff > 3) && (diff <= 5))
    {
      diff += 3;
    }
    double xp = (getExpReward() * damage) / getMaxHp();
    double sp = (getSpReward() * damage) / getMaxHp();
    if (diff > 5)
    {
      double mod = Math.pow(.83, diff - 5);
      xp *= mod;
      sp *= mod;
    }
    if ((level > 84) && (diff < -2))
    {
      double mod = Math.pow(.83, Math.abs(diff + 3));
      xp *= mod;
      sp *= mod;
    }
    if (diff > 10)
    {
      xp = 0.;
    }
    xp = Math.max(0., xp);
    sp = Math.max(0., sp);
    return new double[]
    {
      xp,
      sp
    };
  }
 
  /**
   * Method applyOverhit.
   * @param killer Player
   * @param xp double
   * @return double
   */
  private double applyOverhit(Player killer, double xp)
  {
    if ((xp > 0) && (killer.getObjectId() == overhitAttackerId))
    {
      int overHitExp = calculateOverhitExp(xp);
      killer.sendPacket(Msg.OVER_HIT, new SystemMessage(SystemMessage.ACQUIRED_S1_BONUS_EXPERIENCE_THROUGH_OVER_HIT).addNumber(overHitExp));
      xp += overHitExp;
    }
    return xp;
  }
 
  /**
   * Method setOverhitAttacker.
   * @param attacker Creature
   */
  @Override
  public void setOverhitAttacker(Creature attacker)
  {
    overhitAttackerId = attacker == null ? 0 : attacker.getObjectId();
  }
 
  /**
   * Method getOverhitDamage.
   * @return double
   */
  public double getOverhitDamage()
  {
    return _overhitDamage;
  }
 
  /**
   * Method setOverhitDamage.
   * @param damage double
   */
  @Override
  public void setOverhitDamage(double damage)
  {
    _overhitDamage = damage;
  }
 
  /**
   * Method calculateOverhitExp.
   * @param normalExp double
   * @return int
   */
  public int calculateOverhitExp(final double normalExp)
  {
    double overhitPercentage = (getOverhitDamage() * 100) / getMaxHp();
    if (overhitPercentage > 25)
    {
      overhitPercentage = 25;
    }
    double overhitExp = (overhitPercentage / 100) * normalExp;
    setOverhitAttacker(null);
    setOverhitDamage(0);
    return (int) Math.round(overhitExp);
  }
 
  /**
   * Method isAggressive.
   * @return boolean
   */
  @Override
  public boolean isAggressive()
  {
    return (Config.ALT_CHAMPION_CAN_BE_AGGRO || (getChampion() == 0)) && super.isAggressive();
  }
 
  /**
   * Method getFaction.
   * @return Faction
   */
  @Override
  public Faction getFaction()
  {
    return Config.ALT_CHAMPION_CAN_BE_SOCIAL || (getChampion() == 0) ? super.getFaction() : Faction.NONE;
  }
 
  /**
   * Method reduceCurrentHp.
   * @param i double
   * @param reflectableDamage double
   * @param attacker Creature
   * @param skill Skill
   * @param awake boolean
   * @param standUp boolean
   * @param directHp boolean
   * @param canReflect boolean
   * @param transferDamage boolean
   * @param isDot boolean
   * @param sendMessage boolean
   */
  @Override
  public void reduceCurrentHp(double i, double reflectableDamage, Creature attacker, Skill skill, boolean awake, boolean standUp, boolean directHp, boolean canReflect, boolean transferDamage, boolean isDot, boolean sendMessage)
  {
    checkUD(attacker, i);
    super.reduceCurrentHp(i, reflectableDamage, attacker, skill, awake, standUp, directHp, canReflect, transferDamage, isDot, sendMessage);
  }
 
  /**
   * Field MIN_DISTANCE_FOR_USE_UD.
   */
  private final double MIN_DISTANCE_FOR_USE_UD = 200.0;
  /**
   * Field MIN_DISTANCE_FOR_CANCEL_UD.
   */
  private final double MIN_DISTANCE_FOR_CANCEL_UD = 50.0;
  /**
   * Field UD_USE_CHANCE.
   */
  private final double UD_USE_CHANCE = 30.0;
 
  /**
   * Method checkUD.
   * @param attacker Creature
   * @param damage double
   */
  private void checkUD(Creature attacker, double damage)
  {
    if ((getTemplate().getBaseAtkRange() > MIN_DISTANCE_FOR_USE_UD) || (getLevel() < 20) || (getLevel() > 78) || ((attacker.getLevel() - getLevel()) > 9) || ((getLevel() - attacker.getLevel()) > 9))
    {
      return;
    }
    if (isMinion() || (getMinionList() != null) || isRaid() || (this instanceof ReflectionBossInstance) || (this instanceof ChestInstance) || (getChampion() > 0))
    {
      return;
    }
    int skillId = 5044;
    int skillLvl = 1;
    if ((getLevel() >= 41) || (getLevel() <= 60))
    {
      skillLvl = 2;
    }
    else if (getLevel() > 60)
    {
      skillLvl = 3;
    }
    double distance = getDistance(attacker);
    if (distance <= MIN_DISTANCE_FOR_CANCEL_UD)
    {
      if ((getEffectList() != null) && (getEffectList().getEffectsBySkillId(skillId) != null))
      {
        for (Effect e : getEffectList().getEffectsBySkillId(skillId))
        {
          e.exit();
        }
      }
    }
    else if (distance >= MIN_DISTANCE_FOR_USE_UD)
    {
      double chance = UD_USE_CHANCE / (getMaxHp() / damage);
      if (Rnd.chance(chance))
      {
        Skill skill = SkillTable.getInstance().getInfo(skillId, skillLvl);
        if (skill != null)
        {
          skill.getEffects(this, this, false, false);
        }
      }
    }
  }
 
  /**
   * Method isMonster.
   * @return boolean
   */
  @Override
  public boolean isMonster()
  {
    return true;
  }
 
  /**
   * Method getClan.
   * @return Clan
   */
  @Override
  public Clan getClan()
  {
    return null;
  }
 
  /**
   * Method isInvul.
   * @return boolean
   */
  @Override
  public boolean isInvul()
  {
    return _isInvul;
  }
}
TOP

Related Classes of lineage2.gameserver.model.instances.MonsterInstance

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.