Advertisement
Guest User

L2Attackable.java

a guest
Aug 3rd, 2019
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 61.22 KB | None | 0 0
  1. /*
  2.  * This program is free software: you can redistribute it and/or modify it under
  3.  * the terms of the GNU General Public License as published by the Free Software
  4.  * Foundation, either version 3 of the License, or (at your option) any later
  5.  * version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful, but WITHOUT
  8.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9.  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10.  * details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License along with
  13.  * this program. If not, see <http://www.gnu.org/licenses/>.
  14.  */
  15. package net.sf.l2j.gameserver.model.actor;
  16.  
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.concurrent.ConcurrentHashMap;
  21.  
  22. import net.sf.l2j.commons.config.Config;
  23. import net.sf.l2j.commons.util.Rnd;
  24. import net.sf.l2j.commons.util.security.PrivateAntiBot;
  25. import net.sf.l2j.gameserver.ThreadPoolManager;
  26. import net.sf.l2j.gameserver.ai.CtrlEvent;
  27. import net.sf.l2j.gameserver.ai.CtrlIntention;
  28. import net.sf.l2j.gameserver.ai.L2AttackableAI;
  29. import net.sf.l2j.gameserver.ai.L2CharacterAI;
  30. import net.sf.l2j.gameserver.ai.L2SiegeGuardAI;
  31. import net.sf.l2j.gameserver.datatables.HerbDropTable;
  32. import net.sf.l2j.gameserver.datatables.ItemTable;
  33. import net.sf.l2j.gameserver.instancemanager.CursedWeaponsManager;
  34. import net.sf.l2j.gameserver.instancemanager.EventsDropManager;
  35. import net.sf.l2j.gameserver.model.L2CharPosition;
  36. import net.sf.l2j.gameserver.model.L2CommandChannel;
  37. import net.sf.l2j.gameserver.model.L2Manor;
  38. import net.sf.l2j.gameserver.model.L2Object;
  39. import net.sf.l2j.gameserver.model.L2Party;
  40. import net.sf.l2j.gameserver.model.L2Skill;
  41. import net.sf.l2j.gameserver.model.actor.instance.L2GrandBossInstance;
  42. import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  43. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  44. import net.sf.l2j.gameserver.model.actor.instance.L2SummonInstance;
  45. import net.sf.l2j.gameserver.model.actor.knownlist.AttackableKnownList;
  46. import net.sf.l2j.gameserver.model.actor.status.AttackableStatus;
  47. import net.sf.l2j.gameserver.model.actor.template.NpcTemplate;
  48. import net.sf.l2j.gameserver.model.holder.ItemHolder;
  49. import net.sf.l2j.gameserver.model.item.DropCategory;
  50. import net.sf.l2j.gameserver.model.item.DropData;
  51. import net.sf.l2j.gameserver.model.item.instance.ItemInstance;
  52. import net.sf.l2j.gameserver.model.item.kind.Premium;
  53. import net.sf.l2j.gameserver.model.item.type.EtcItemType;
  54. import net.sf.l2j.gameserver.model.quest.Quest;
  55. import net.sf.l2j.gameserver.model.quest.QuestEventType;
  56. import net.sf.l2j.gameserver.network.SystemMessageId;
  57. import net.sf.l2j.gameserver.network.clientpackets.Say2;
  58. import net.sf.l2j.gameserver.network.serverpackets.CreatureSay;
  59. import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
  60. import net.sf.l2j.gameserver.taskmanager.ItemsAutoDestroyTaskManager;
  61. import net.sf.l2j.gameserver.util.Util;
  62.  
  63. /**
  64.  * This class manages all NPC that can be attacked, such as :
  65.  * <ul>
  66.  * <li>L2ArtefactInstance</li>
  67.  * <li>L2FriendlyMobInstance</li>
  68.  * <li>L2MonsterInstance</li>
  69.  * <li>L2SiegeGuardInstance</li>
  70.  * </ul>
  71.  */
  72. public class L2Attackable extends L2Npc
  73. {
  74.     private boolean _isRaid = false;
  75.     private boolean _isRaidMinion = false;
  76.    
  77.     /**
  78.      * This class contains all AggroInfo of the L2Attackable against the attacker L2Character.
  79.      * <ul>
  80.      * <li>attacker : The attacker L2Character concerned by this AggroInfo of this L2Attackable</li>
  81.      * <li>hate : Hate level of this L2Attackable against the attacker L2Character (hate = damage)</li>
  82.      * <li>damage : Number of damages that the attacker L2Character gave to this L2Attackable</li>
  83.      * </ul>
  84.      */
  85.     public static final class AggroInfo
  86.     {
  87.         private final L2Character _attacker;
  88.         private int _hate = 0;
  89.         private int _damage = 0;
  90.        
  91.         AggroInfo(L2Character pAttacker)
  92.         {
  93.             _attacker = pAttacker;
  94.         }
  95.        
  96.         public final L2Character getAttacker()
  97.         {
  98.             return _attacker;
  99.         }
  100.        
  101.         public final int getHate()
  102.         {
  103.             return _hate;
  104.         }
  105.        
  106.         public final int checkHate(L2Character owner)
  107.         {
  108.             if (_attacker.isAlikeDead() || !_attacker.isVisible() || !owner.getKnownList().knowsObject(_attacker))
  109.             {
  110.                 _hate = 0;
  111.             }
  112.            
  113.             return _hate;
  114.         }
  115.        
  116.         public final void addHate(int value)
  117.         {
  118.             _hate = (int) Math.min(_hate + (long) value, 999999999);
  119.         }
  120.        
  121.         public final void stopHate()
  122.         {
  123.             _hate = 0;
  124.         }
  125.        
  126.         public final int getDamage()
  127.         {
  128.             return _damage;
  129.         }
  130.        
  131.         public final void addDamage(int value)
  132.         {
  133.             _damage = (int) Math.min(_damage + (long) value, 999999999);
  134.         }
  135.        
  136.         @Override
  137.         public final boolean equals(Object obj)
  138.         {
  139.             if (this == obj)
  140.             {
  141.                 return true;
  142.             }
  143.            
  144.             if (obj instanceof AggroInfo)
  145.             {
  146.                 return (((AggroInfo) obj).getAttacker() == _attacker);
  147.             }
  148.            
  149.             return false;
  150.         }
  151.        
  152.         @Override
  153.         public final int hashCode()
  154.         {
  155.             return _attacker.getObjectId();
  156.         }
  157.     }
  158.    
  159.     /**
  160.      * This class contains all RewardInfo of the L2Attackable against the any attacker L2Character, based on amount of damage done.
  161.      */
  162.     protected static final class RewardInfo
  163.     {
  164.         /** The attacker L2Character concerned by this RewardInfo of this L2Attackable. */
  165.         private final L2PcInstance _attacker;
  166.        
  167.         /** Total amount of damage done by the attacker to this L2Attackable (summon + own). */
  168.         private int _damage = 0;
  169.        
  170.         public RewardInfo(L2PcInstance attacker, int damage)
  171.         {
  172.             _attacker = attacker;
  173.             _damage = damage;
  174.         }
  175.        
  176.         public L2PcInstance getAttacker()
  177.         {
  178.             return _attacker;
  179.         }
  180.        
  181.         public void addDamage(int damage)
  182.         {
  183.             _damage += damage;
  184.         }
  185.        
  186.         public int getDamage()
  187.         {
  188.             return _damage;
  189.         }
  190.        
  191.         @Override
  192.         public boolean equals(Object obj)
  193.         {
  194.             if (this == obj)
  195.             {
  196.                 return true;
  197.             }
  198.            
  199.             if (obj instanceof RewardInfo)
  200.             {
  201.                 return (((RewardInfo) obj)._attacker == _attacker);
  202.             }
  203.            
  204.             return false;
  205.         }
  206.        
  207.         @Override
  208.         public int hashCode()
  209.         {
  210.             return _attacker.getObjectId();
  211.         }
  212.     }
  213.    
  214.     /**
  215.      * This class contains all needed infos of the L2Attackable against the absorber L2Character.
  216.      * <ul>
  217.      * <li>_playerObjectId : The id of the attacker concerned by this AbsorberInfo.</li>
  218.      * <li>_absorbedHP : The amount of HP at the moment attacker used the item.</li>
  219.      * <li>_itemObjectId : The item id of the Soul Crystal used.</li>
  220.      * </ul>
  221.      */
  222.     public static final class AbsorbInfo
  223.     {
  224.         public boolean _registered;
  225.         public int _itemObjectId;
  226.         public int _absorbedHpPercent;
  227.        
  228.         AbsorbInfo(int itemObjectId)
  229.         {
  230.             _registered = false;
  231.             _itemObjectId = itemObjectId;
  232.             _absorbedHpPercent = 0;
  233.         }
  234.        
  235.         public boolean isRegistered()
  236.         {
  237.             return _registered;
  238.         }
  239.        
  240.         public boolean isValid(int itemObjectId)
  241.         {
  242.             return _itemObjectId == itemObjectId && _absorbedHpPercent < 50;
  243.         }
  244.     }
  245.    
  246.     private final Map<L2Character, AggroInfo> _aggroList = new ConcurrentHashMap<>();
  247.    
  248.     public final Map<L2Character, AggroInfo> getAggroList()
  249.     {
  250.         return _aggroList;
  251.     }
  252.    
  253.     private boolean _isReturningToSpawnPoint = false;
  254.     private boolean _seeThroughSilentMove = false;
  255.    
  256.     public final boolean isReturningToSpawnPoint()
  257.     {
  258.         return _isReturningToSpawnPoint;
  259.     }
  260.    
  261.     public final void setIsReturningToSpawnPoint(boolean value)
  262.     {
  263.         _isReturningToSpawnPoint = value;
  264.     }
  265.    
  266.     public boolean canSeeThroughSilentMove()
  267.     {
  268.         return _seeThroughSilentMove;
  269.     }
  270.    
  271.     public void seeThroughSilentMove(boolean val)
  272.     {
  273.         _seeThroughSilentMove = val;
  274.     }
  275.    
  276.     private final List<ItemHolder> _sweepItems = new ArrayList<>();
  277.     private final List<ItemHolder> _harvestItems = new ArrayList<>();
  278.    
  279.     private int _seedType = 0;
  280.     private int _seederObjId = 0;
  281.    
  282.     private boolean _overhit;
  283.     private double _overhitDamage;
  284.     private L2Character _overhitAttacker;
  285.    
  286.     private L2CommandChannel _firstCommandChannelAttacked = null;
  287.     private CommandChannelTimer _commandChannelTimer = null;
  288.     private long _commandChannelLastAttack = 0;
  289.    
  290.     private final Map<Integer, AbsorbInfo> _absorbersList = new ConcurrentHashMap<>();
  291.    
  292.     /**
  293.      * Constructor of L2Attackable (use L2Character and L2Npc constructor).
  294.      * <ul>
  295.      * <li>Call the L2Character constructor to set the _template of the L2Attackable (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR)</li>
  296.      * <li>Set the name of the L2Attackable</li>
  297.      * <li>Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it</li>
  298.      * </ul>
  299.      * @param objectId Identifier of the object to initialized
  300.      * @param template Template to apply to the NPC
  301.      */
  302.     public L2Attackable(int objectId, NpcTemplate template)
  303.     {
  304.         super(objectId, template);
  305.     }
  306.    
  307.     @Override
  308.     public void initKnownList()
  309.     {
  310.         setKnownList(new AttackableKnownList(this));
  311.     }
  312.    
  313.     @Override
  314.     public AttackableKnownList getKnownList()
  315.     {
  316.         return (AttackableKnownList) super.getKnownList();
  317.     }
  318.    
  319.     @Override
  320.     public void initCharStatus()
  321.     {
  322.         setStatus(new AttackableStatus(this));
  323.     }
  324.    
  325.     @Override
  326.     public AttackableStatus getStatus()
  327.     {
  328.         return (AttackableStatus) super.getStatus();
  329.     }
  330.    
  331.     /**
  332.      * Return the L2Character AI of the L2Attackable and if its null create a new one.
  333.      */
  334.     @Override
  335.     public L2CharacterAI getAI()
  336.     {
  337.         L2CharacterAI ai = _ai;
  338.         if (ai == null)
  339.         {
  340.             synchronized (this)
  341.             {
  342.                 if (_ai == null)
  343.                 {
  344.                     _ai = new L2AttackableAI(new AIAccessor());
  345.                 }
  346.                
  347.                 return _ai;
  348.             }
  349.         }
  350.         return ai;
  351.     }
  352.    
  353.     public void useMagic(L2Skill skill)
  354.     {
  355.         if (skill == null || isAlikeDead())
  356.         {
  357.             return;
  358.         }
  359.        
  360.         if (skill.isPassive())
  361.         {
  362.             return;
  363.         }
  364.        
  365.         if (isCastingNow())
  366.         {
  367.             return;
  368.         }
  369.        
  370.         if (isSkillDisabled(skill))
  371.         {
  372.             return;
  373.         }
  374.        
  375.         if (getCurrentMp() < getStat().getMpConsume(skill) + getStat().getMpInitialConsume(skill))
  376.         {
  377.             return;
  378.         }
  379.        
  380.         if (getCurrentHp() <= skill.getHpConsume())
  381.         {
  382.             return;
  383.         }
  384.        
  385.         if (skill.isMagic())
  386.         {
  387.             if (isMuted())
  388.             {
  389.                 return;
  390.             }
  391.         }
  392.         else
  393.         {
  394.             if (isPhysicalMuted())
  395.             {
  396.                 return;
  397.             }
  398.         }
  399.        
  400.         L2Object target = skill.getFirstOfTargetList(this);
  401.         if (target == null)
  402.         {
  403.             return;
  404.         }
  405.        
  406.         getAI().setIntention(CtrlIntention.CAST, skill, target);
  407.     }
  408.    
  409.     /**
  410.      * Reduce the current HP of the L2Attackable.
  411.      * @param damage The HP decrease value
  412.      * @param attacker The L2Character who attacks
  413.      */
  414.     @Override
  415.     public void reduceCurrentHp(double damage, L2Character attacker, L2Skill skill)
  416.     {
  417.         reduceCurrentHp(damage, attacker, true, false, skill);
  418.     }
  419.    
  420.     /**
  421.      * Reduce the current HP of the L2Attackable, update its _aggroList and launch the doDie Task if necessary.
  422.      * @param attacker The L2Character who attacks
  423.      * @param awake The awake state (If True : stop sleeping)
  424.      */
  425.     @Override
  426.     public void reduceCurrentHp(double damage, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
  427.     {
  428.         if (isRaid() && !isMinion() && attacker != null && attacker.getParty() != null && attacker.getParty().isInCommandChannel() && attacker.getParty().getCommandChannel().meetRaidWarCondition(this))
  429.         {
  430.             if (_firstCommandChannelAttacked == null) // looting right isn't set
  431.             {
  432.                 synchronized (this)
  433.                 {
  434.                     if (_firstCommandChannelAttacked == null)
  435.                     {
  436.                         _firstCommandChannelAttacked = attacker.getParty().getCommandChannel();
  437.                         if (_firstCommandChannelAttacked != null)
  438.                         {
  439.                             _commandChannelTimer = new CommandChannelTimer(this);
  440.                             _commandChannelLastAttack = System.currentTimeMillis();
  441.                             ThreadPoolManager.getInstance().scheduleGeneral(_commandChannelTimer, 10000); // check for last attack
  442.                             _firstCommandChannelAttacked.broadcastToChannelMembers(new CreatureSay(0, Say2.PARTYROOM_ALL, "", "You have looting rights!")); // TODO: retail msg
  443.                         }
  444.                     }
  445.                 }
  446.             }
  447.             else if (attacker.getParty().getCommandChannel().equals(_firstCommandChannelAttacked))
  448.             {
  449.                 _commandChannelLastAttack = System.currentTimeMillis(); // update last attack time
  450.             }
  451.         }
  452.        
  453.         // Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList
  454.         if (attacker != null)
  455.         {
  456.             addDamage(attacker, (int) damage);
  457.         }
  458.        
  459.         // If this L2Attackable is a L2MonsterInstance and it has spawned minions, call its minions to battle
  460.         if (this instanceof L2MonsterInstance)
  461.         {
  462.             L2MonsterInstance master = (L2MonsterInstance) this;
  463.            
  464.             if (master.hasMinions())
  465.             {
  466.                 master.getMinionList().onAssist(this, attacker);
  467.             }
  468.            
  469.             master = master.getLeader();
  470.             if (master != null && master.hasMinions())
  471.             {
  472.                 master.getMinionList().onAssist(this, attacker);
  473.             }
  474.         }
  475.         // Reduce the current HP of the L2Attackable and launch the doDie Task if necessary
  476.         super.reduceCurrentHp(damage, attacker, awake, isDOT, skill);
  477.     }
  478.    
  479.     /**
  480.      * Kill the L2Attackable (the corpse disappeared after 7 seconds), distribute rewards (EXP, SP, Drops...) and notify Quest Engine.
  481.      * <ul>
  482.      * <li>Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members</li>
  483.      * <li>Notify the Quest Engine of the L2Attackable death if necessary</li>
  484.      * <li>Kill the L2Npc (the corpse disappeared after 7 seconds)</li>
  485.      * </ul>
  486.      * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT>
  487.      * @param killer The L2Character that has killed the L2Attackable
  488.      */
  489.     @Override
  490.     public boolean doDie(L2Character killer)
  491.     {
  492.         // Kill the L2Npc (the corpse disappeared after 7 seconds)
  493.         if (!super.doDie(killer))
  494.         {
  495.             return false;
  496.         }
  497.        
  498.         // Notify the Quest Engine of the L2Attackable death if necessary
  499.         try
  500.         {
  501.             L2PcInstance player = null;
  502.            
  503.             if (killer != null)
  504.             {
  505.                 player = killer.getActingPlayer();
  506.             }
  507.            
  508.             if (player != null)
  509.             {
  510.                 List<Quest> quests = getTemplate().getEventQuests(QuestEventType.ON_KILL);
  511.                 if (quests != null)
  512.                 {
  513.                     for (Quest quest : quests)
  514.                     {
  515.                         ThreadPoolManager.getInstance().scheduleEffect(new OnKillNotifyTask(this, quest, player, killer instanceof L2Summon), 3000);
  516.                     }
  517.                 }
  518.             }
  519.         }
  520.         catch (Exception e)
  521.         {
  522.             _log.warn("", e);
  523.         }
  524.        
  525.         return true;
  526.     }
  527.    
  528.     private static class OnKillNotifyTask implements Runnable
  529.     {
  530.         private final L2Attackable _attackable;
  531.         private final Quest _quest;
  532.         private final L2PcInstance _killer;
  533.         private final boolean _isPet;
  534.        
  535.         public OnKillNotifyTask(L2Attackable attackable, Quest quest, L2PcInstance killer, boolean isPet)
  536.         {
  537.             _attackable = attackable;
  538.             _quest = quest;
  539.             _killer = killer;
  540.             _isPet = isPet;
  541.         }
  542.        
  543.         @Override
  544.         public void run()
  545.         {
  546.             _quest.notifyKill(_attackable, _killer, _isPet);
  547.         }
  548.     }
  549.    
  550.     /**
  551.      * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members.
  552.      * <ul>
  553.      * <li>Get the L2PcInstance owner of the L2SummonInstance (if necessary) and L2Party in progress</li>
  554.      * <li>Calculate the Experience and SP rewards in function of the level difference</li>
  555.      * <li>Add Exp and SP rewards to L2PcInstance (including Summon penalty) and to Party members in the known area of the last attacker</li>
  556.      * </ul>
  557.      * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT>
  558.      * @param lastAttacker The L2Character that has killed the L2Attackable
  559.      */
  560.     @Override
  561.     protected void calculateRewards(L2Character lastAttacker)
  562.     {
  563.         if (_aggroList.isEmpty())
  564.         {
  565.             return;
  566.         }
  567.        
  568.         if (_event != null && _event.isRunning() && !_event.canGaveExp(this))
  569.         {
  570.             return;
  571.         }
  572.        
  573.         // Creates an empty list of rewards.
  574.         final Map<L2Character, RewardInfo> rewards = new ConcurrentHashMap<>();
  575.        
  576.         L2PcInstance maxDealer = null;
  577.         int maxDamage = 0;
  578.         long totalDamage = 0;
  579.        
  580.         // Go through the _aggroList of the L2Attackable.
  581.         for (AggroInfo info : _aggroList.values())
  582.         {
  583.             if (info == null)
  584.             {
  585.                 continue;
  586.             }
  587.            
  588.             // Get the L2Character corresponding to this attacker.
  589.             final L2PcInstance attacker = info.getAttacker().getActingPlayer();
  590.             if (attacker == null)
  591.             {
  592.                 continue;
  593.             }
  594.            
  595.             // Get damages done by this attacker.
  596.             final int damage = info.getDamage();
  597.             if (damage <= 1)
  598.             {
  599.                 continue;
  600.             }
  601.            
  602.             // Check if attacker isn't too far from this.
  603.             if (!Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, attacker, true))
  604.             {
  605.                 continue;
  606.             }
  607.            
  608.             totalDamage += damage;
  609.            
  610.             // Calculate real damages (Summoners should get own damage plus summon's damage).
  611.             RewardInfo reward = rewards.get(attacker);
  612.             if (reward == null)
  613.             {
  614.                 reward = new RewardInfo(attacker, damage);
  615.                 rewards.put(attacker, reward);
  616.             }
  617.             else
  618.             {
  619.                 reward.addDamage(damage);
  620.             }
  621.            
  622.             if (reward.getDamage() > maxDamage)
  623.             {
  624.                 maxDealer = attacker;
  625.                 maxDamage = reward.getDamage();
  626.             }
  627.         }
  628.        
  629.         // Manage Base, Quests and Sweep drops of the L2Attackable.
  630.         doItemDrop(maxDealer != null && maxDealer.isOnline() ? maxDealer : lastAttacker);
  631.        
  632.         for (RewardInfo reward : rewards.values())
  633.         {
  634.             if (reward == null)
  635.             {
  636.                 continue;
  637.             }
  638.            
  639.             // Attacker to be rewarded.
  640.             final L2PcInstance attacker = reward.getAttacker();
  641.            
  642.             // Total amount of damage done.
  643.             final int damage = reward.getDamage();
  644.            
  645.             // Get party.
  646.             final L2Party attackerParty = attacker.getParty();
  647.            
  648.             // Penalty applied to the attacker's XP
  649.             final float penalty = attacker.hasServitor() ? ((L2SummonInstance) attacker.getPet()).getExpPenalty() : 0;
  650.            
  651.             // If there's NO party in progress.
  652.             if (attackerParty == null)
  653.             {
  654.                 // Calculate Exp and SP rewards.
  655.                 if (attacker.getKnownList().knowsObject(this) && !attacker.isDead())
  656.                 {
  657.                     // Calculate the difference of level between this attacker and the L2Attackable.
  658.                     final int levelDiff = attacker.getLevel() - getLevel();
  659.                    
  660.                     final int[] expSp = calculateExpAndSp(levelDiff, damage, totalDamage);
  661.                     long exp = expSp[0];
  662.                     int sp = expSp[1];
  663.                    
  664.                     if (Config.CHAMPION_ENABLE)
  665.                     {
  666.                         if (isBlueChampion())
  667.                         {
  668.                             exp *= Config.CHAMPION_EXP_SP_BLUE;
  669.                             sp *= Config.CHAMPION_EXP_SP_BLUE;
  670.                         }
  671.                         else if (isRedChampion())
  672.                         {
  673.                             exp *= Config.CHAMPION_EXP_SP_RED;
  674.                             sp *= Config.CHAMPION_EXP_SP_RED;
  675.                         }
  676.                     }
  677.                    
  678.                     exp *= attacker.getPremiumAttribute(Premium.MODIFIER_XP);
  679.                     sp *= attacker.getPremiumAttribute(Premium.MODIFIER_SP);
  680.                    
  681.                     exp *= 1 - penalty;
  682.                    
  683.                     if (isOverhit() && getOverhitAttacker().getActingPlayer() != null && attacker == getOverhitAttacker().getActingPlayer())
  684.                     {
  685.                         attacker.sendPacket(SystemMessageId.OVER_HIT);
  686.                         exp += calculateOverhitExp(exp);
  687.                     }
  688.                    
  689.                     // Set new karma.
  690.                     attacker.updateKarmaLoss(Math.round(exp));
  691.                    
  692.                     // Distribute the Exp and SP between the L2PcInstance and its L2Summon.
  693.                     attacker.addExpAndSp(Math.round(exp), sp);
  694.                 }
  695.             }
  696.             // Share with party members.
  697.             else
  698.             {
  699.                 int partyDmg = 0;
  700.                 float partyMul = 1;
  701.                 int partyLvl = 0;
  702.                
  703.                 // Get all L2Character that can be rewarded in the party.
  704.                 final List<L2PcInstance> rewardedMembers = new ArrayList<>();
  705.                
  706.                 // Go through all L2PcInstance in the party.
  707.                 final List<L2PcInstance> groupMembers = (attackerParty.isInCommandChannel()) ? attackerParty.getCommandChannel().getMembers() : attackerParty.getPartyMembers();
  708.                
  709.                 for (L2PcInstance partyPlayer : groupMembers)
  710.                 {
  711.                     if (partyPlayer == null || partyPlayer.isDead())
  712.                     {
  713.                         continue;
  714.                     }
  715.                    
  716.                     // Get the RewardInfo of this L2PcInstance from L2Attackable rewards
  717.                     final RewardInfo reward2 = rewards.get(partyPlayer);
  718.                    
  719.                     // If the L2PcInstance is in the L2Attackable rewards add its damages to party damages
  720.                     if (reward2 != null)
  721.                     {
  722.                         if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, partyPlayer, true))
  723.                         {
  724.                             partyDmg += reward2.getDamage(); // Add L2PcInstance damages to party damages
  725.                             rewardedMembers.add(partyPlayer);
  726.                            
  727.                             if (partyPlayer.getLevel() > partyLvl)
  728.                             {
  729.                                 partyLvl = (attackerParty.isInCommandChannel()) ? attackerParty.getCommandChannel().getLevel() : partyPlayer.getLevel();
  730.                             }
  731.                         }
  732.                         rewards.remove(partyPlayer); // Remove the L2PcInstance from the L2Attackable rewards
  733.                     }
  734.                     // Add L2PcInstance of the party (that have attacked or not) to members that can be rewarded and in range of the monster.
  735.                     else
  736.                     {
  737.                         if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, partyPlayer, true))
  738.                         {
  739.                             rewardedMembers.add(partyPlayer);
  740.                             if (partyPlayer.getLevel() > partyLvl)
  741.                             {
  742.                                 partyLvl = (attackerParty.isInCommandChannel()) ? attackerParty.getCommandChannel().getLevel() : partyPlayer.getLevel();
  743.                             }
  744.                         }
  745.                     }
  746.                 }
  747.                
  748.                 // If the party didn't killed this L2Attackable alone
  749.                 if (partyDmg < totalDamage)
  750.                 {
  751.                     partyMul = ((float) partyDmg / totalDamage);
  752.                 }
  753.                
  754.                 // Calculate the level difference between Party and L2Attackable
  755.                 final int levelDiff = partyLvl - getLevel();
  756.                
  757.                 // Calculate Exp and SP rewards
  758.                 final int[] expSp = calculateExpAndSp(levelDiff, partyDmg, totalDamage);
  759.                 long exp = expSp[0];
  760.                 int sp = expSp[1];
  761.                
  762.                 if (Config.CHAMPION_ENABLE)
  763.                 {
  764.                     if (isBlueChampion())
  765.                     {
  766.                         exp *= Config.CHAMPION_EXP_SP_BLUE;
  767.                         sp *= Config.CHAMPION_EXP_SP_BLUE;
  768.                     }
  769.                     else if (isRedChampion())
  770.                     {
  771.                         exp *= Config.CHAMPION_EXP_SP_RED;
  772.                         sp *= Config.CHAMPION_EXP_SP_RED;
  773.                     }
  774.                 }
  775.                
  776.                 exp *= partyMul;
  777.                 sp *= partyMul;
  778.                
  779.                 // Check for an over-hit enabled strike
  780.                 // (When in party, the over-hit exp bonus is given to the whole party and splitted proportionally through the party members)
  781.                 if (isOverhit() && getOverhitAttacker().getActingPlayer() != null && attacker == getOverhitAttacker().getActingPlayer())
  782.                 {
  783.                     attacker.sendPacket(SystemMessageId.OVER_HIT);
  784.                     exp += calculateOverhitExp(exp);
  785.                 }
  786.                
  787.                 // Distribute Experience and SP rewards to L2PcInstance Party members in the known area of the last attacker
  788.                 if (partyDmg > 0)
  789.                 {
  790.                     attackerParty.distributeXpAndSp(exp, sp, rewardedMembers, partyLvl);
  791.                 }
  792.             }
  793.         }
  794.     }
  795.    
  796.     @Override
  797.     public void addAttackerToAttackByList(L2Character player)
  798.     {
  799.         if (player == null || player == this || getAttackByList().contains(player))
  800.         {
  801.             return;
  802.         }
  803.        
  804.         getAttackByList().add(player);
  805.     }
  806.    
  807.     /**
  808.      * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.
  809.      * @param attacker The L2Character that gave damages to this L2Attackable
  810.      * @param damage The number of damages given by the attacker L2Character
  811.      */
  812.     public void addDamage(L2Character attacker, int damage)
  813.     {
  814.         if (attacker == null || isDead())
  815.         {
  816.             return;
  817.         }
  818.        
  819.         // Notify the L2Attackable AI with EVT_ATTACKED
  820.         L2PcInstance player = attacker.getActingPlayer();
  821.         if (player != null)
  822.         {
  823.             List<Quest> quests = getTemplate().getEventQuests(QuestEventType.ON_ATTACK);
  824.             if (quests != null)
  825.             {
  826.                 for (Quest quest : quests)
  827.                 {
  828.                     quest.notifyAttack(this, player, damage, attacker instanceof L2Summon);
  829.                 }
  830.             }
  831.         }
  832.         // for now hard code damage hate caused by an L2Attackable
  833.         else
  834.         {
  835.             getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, attacker);
  836.             addDamageHate(attacker, damage, (damage * 100) / (getLevel() + 7));
  837.         }
  838.     }
  839.    
  840.     /**
  841.      * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.
  842.      * @param attacker The L2Character that gave damages to this L2Attackable
  843.      * @param damage The number of damages given by the attacker L2Character
  844.      * @param aggro The hate (=damage) given by the attacker L2Character
  845.      */
  846.     public void addDamageHate(L2Character attacker, int damage, int aggro)
  847.     {
  848.         if (attacker == null)
  849.         {
  850.             return;
  851.         }
  852.        
  853.         // Get or create the AggroInfo of the attacker.
  854.         AggroInfo ai = _aggroList.get(attacker);
  855.         if (ai == null)
  856.         {
  857.             ai = new AggroInfo(attacker);
  858.             _aggroList.put(attacker, ai);
  859.         }
  860.         ai.addDamage(damage);
  861.         ai.addHate(aggro);
  862.        
  863.         if (aggro == 0)
  864.         {
  865.             final L2PcInstance targetPlayer = attacker.getActingPlayer();
  866.             if (targetPlayer != null)
  867.             {
  868.                 List<Quest> quests = getTemplate().getEventQuests(QuestEventType.ON_AGGRO_RANGE_ENTER);
  869.                 if (quests != null)
  870.                 {
  871.                     for (Quest quest : quests)
  872.                     {
  873.                         quest.notifyAggroRangeEnter(this, targetPlayer, (attacker instanceof L2Summon));
  874.                     }
  875.                 }
  876.             }
  877.             else
  878.             {
  879.                 aggro = 1;
  880.                 ai.addHate(1);
  881.             }
  882.         }
  883.         else
  884.         {
  885.             // Set the intention to the L2Attackable to ACTIVE
  886.             if (aggro > 0 && getAI().getIntention() == CtrlIntention.IDLE)
  887.             {
  888.                 getAI().setIntention(CtrlIntention.ACTIVE);
  889.             }
  890.         }
  891.     }
  892.    
  893.     /**
  894.      * Reduce hate for the target. If the target is null, decrease the hate for the whole aggrolist.
  895.      * @param target The target to check.
  896.      * @param amount The amount to remove.
  897.      */
  898.     public void reduceHate(L2Character target, int amount)
  899.     {
  900.         if (getAI() instanceof L2SiegeGuardAI)
  901.         {
  902.             stopHating(target);
  903.             setTarget(null);
  904.             getAI().setIntention(CtrlIntention.IDLE);
  905.             return;
  906.         }
  907.        
  908.         if (target == null) // whole aggrolist
  909.         {
  910.             L2Character mostHated = getMostHated();
  911.            
  912.             // If not most hated target is found, makes AI passive for a moment more
  913.             if (mostHated == null)
  914.             {
  915.                 ((L2AttackableAI) getAI()).setGlobalAggro(-25);
  916.                 return;
  917.             }
  918.            
  919.             for (L2Character aggroed : _aggroList.keySet())
  920.             {
  921.                 AggroInfo ai = _aggroList.get(aggroed);
  922.                 if (ai == null)
  923.                 {
  924.                     return;
  925.                 }
  926.                
  927.                 ai.addHate(-amount);
  928.             }
  929.            
  930.             amount = getHating(mostHated);
  931.            
  932.             if (amount <= 0)
  933.             {
  934.                 ((L2AttackableAI) getAI()).setGlobalAggro(-25);
  935.                 clearAggroList();
  936.                 getAI().setIntention(CtrlIntention.ACTIVE);
  937.                 setWalking();
  938.             }
  939.             return;
  940.         }
  941.        
  942.         AggroInfo ai = _aggroList.get(target);
  943.         if (ai == null)
  944.         {
  945.             return;
  946.         }
  947.        
  948.         ai.addHate(-amount);
  949.        
  950.         if (ai.getHate() <= 0)
  951.         {
  952.             if (getMostHated() == null)
  953.             {
  954.                 ((L2AttackableAI) getAI()).setGlobalAggro(-25);
  955.                 clearAggroList();
  956.                 getAI().setIntention(CtrlIntention.ACTIVE);
  957.                 setWalking();
  958.             }
  959.         }
  960.     }
  961.    
  962.     /**
  963.      * Clears _aggroList hate of the L2Character without removing from the list.
  964.      * @param target The target to clean from that L2Attackable _aggroList.
  965.      */
  966.     public void stopHating(L2Character target)
  967.     {
  968.         if (target == null)
  969.         {
  970.             return;
  971.         }
  972.        
  973.         AggroInfo ai = _aggroList.get(target);
  974.         if (ai != null)
  975.         {
  976.             ai.stopHate();
  977.         }
  978.     }
  979.    
  980.     /**
  981.      * @return the most hated L2Character of the L2Attackable _aggroList.
  982.      */
  983.     public L2Character getMostHated()
  984.     {
  985.         if (_aggroList.isEmpty() || isAlikeDead())
  986.         {
  987.             return null;
  988.         }
  989.        
  990.         L2Character mostHated = null;
  991.         int maxHate = 0;
  992.        
  993.         // Go through the aggroList of the L2Attackable
  994.         for (AggroInfo ai : _aggroList.values())
  995.         {
  996.             if (ai == null)
  997.             {
  998.                 continue;
  999.             }
  1000.            
  1001.             if (ai.checkHate(this) > maxHate)
  1002.             {
  1003.                 mostHated = ai.getAttacker();
  1004.                 maxHate = ai.getHate();
  1005.             }
  1006.         }
  1007.         return mostHated;
  1008.     }
  1009.    
  1010.     public List<L2Character> getHateList()
  1011.     {
  1012.         List<L2Character> result = new ArrayList<>();
  1013.        
  1014.         if (_aggroList.isEmpty() || isAlikeDead())
  1015.         {
  1016.             return result;
  1017.         }
  1018.        
  1019.         for (AggroInfo ai : _aggroList.values())
  1020.         {
  1021.             if (ai == null)
  1022.             {
  1023.                 continue;
  1024.             }
  1025.            
  1026.             ai.checkHate(this);
  1027.             result.add(ai.getAttacker());
  1028.         }
  1029.         return result;
  1030.     }
  1031.    
  1032.     /**
  1033.      * @param target The L2Character whose hate level must be returned
  1034.      * @return the hate level of the L2Attackable against this L2Character contained in _aggroList.
  1035.      */
  1036.     public int getHating(final L2Character target)
  1037.     {
  1038.         if (_aggroList.isEmpty() || target == null)
  1039.         {
  1040.             return 0;
  1041.         }
  1042.        
  1043.         final AggroInfo ai = _aggroList.get(target);
  1044.         if (ai == null)
  1045.         {
  1046.             return 0;
  1047.         }
  1048.        
  1049.         if (ai.getAttacker() instanceof L2PcInstance && ((L2PcInstance) ai.getAttacker()).getAppearance().getInvisible())
  1050.         {
  1051.             // Remove Object Should Use This Method and Can be Blocked While Interating
  1052.             _aggroList.remove(target);
  1053.             return 0;
  1054.         }
  1055.        
  1056.         if (!ai.getAttacker().isVisible())
  1057.         {
  1058.             _aggroList.remove(target);
  1059.             return 0;
  1060.         }
  1061.        
  1062.         if (ai.getAttacker().isAlikeDead())
  1063.         {
  1064.             ai.stopHate();
  1065.             return 0;
  1066.         }
  1067.         return ai.getHate();
  1068.     }
  1069.    
  1070.     /**
  1071.      * Calculates quantity of items for specific drop acording to current situation.
  1072.      * @param drop The L2DropData count is being calculated for
  1073.      * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1074.      * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  1075.      * @param isSweep if true, use spoil drop chance.
  1076.      * @return the ItemHolder.
  1077.      */
  1078.     private ItemHolder calculateRewardItem(L2PcInstance lastAttacker, DropData drop, int levelModifier, boolean isSweep)
  1079.     {
  1080.         // Get default drop chance
  1081.         double dropChance = drop.getChance();
  1082.        
  1083.         if (Config.DEEPBLUE_DROP_RULES)
  1084.         {
  1085.             int deepBlueDrop = 1;
  1086.             if (levelModifier > 0)
  1087.             {
  1088.                 // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  1089.                 // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  1090.                 deepBlueDrop = 3;
  1091.                 if (drop.getItemId() == 57)
  1092.                 {
  1093.                     if (isRaid() && !isRaidMinion())
  1094.                     {
  1095.                         deepBlueDrop *= (this instanceof L2GrandBossInstance) ? (int) Config.RATE_DROP_ITEMS_BY_GRAND_RAID : (int) Config.RATE_DROP_ITEMS_BY_RAID;
  1096.                     }
  1097.                     else
  1098.                     {
  1099.                         deepBlueDrop *= (int) Config.RATE_DROP_ITEMS;
  1100.                     }
  1101.                    
  1102.                     if (deepBlueDrop == 0)
  1103.                     {
  1104.                         deepBlueDrop = 1;
  1105.                     }
  1106.                 }
  1107.             }
  1108.            
  1109.             // Check if we should apply our maths so deep blue mobs will not drop that easy
  1110.             dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier) / 100)) / deepBlueDrop);
  1111.         }
  1112.        
  1113.         // Applies Drop rates
  1114.         if (drop.getItemId() == 57)
  1115.         {
  1116.             dropChance *= Config.RATE_DROP_ADENA;
  1117.             dropChance *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_DROP_ADENA);
  1118.         }
  1119.         else if (isSweep)
  1120.         {
  1121.             dropChance *= Config.RATE_DROP_SPOIL;
  1122.             dropChance *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_SPOIL);
  1123.         }
  1124.         else
  1125.         {
  1126.             if (isRaid() && !isRaidMinion())
  1127.             {
  1128.                 dropChance *= (this instanceof L2GrandBossInstance) ? (int) Config.RATE_DROP_ITEMS_BY_GRAND_RAID : (int) Config.RATE_DROP_ITEMS_BY_RAID;
  1129.             }
  1130.             else
  1131.             {
  1132.                 dropChance *= (int) Config.RATE_DROP_ITEMS;
  1133.             }
  1134.            
  1135.             //dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1136.             dropChance *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_DROP_ITEMS);
  1137.         }
  1138.        
  1139.         if (Config.CHAMPION_ENABLE)
  1140.         {
  1141.             if (isBlueChampion())
  1142.             {
  1143.                 dropChance *= Config.CHAMPION_REWARDS_BLUE;
  1144.             }
  1145.             else if (isRedChampion())
  1146.             {
  1147.                 dropChance *= Config.CHAMPION_REWARDS_RED;
  1148.             }
  1149.         }
  1150.        
  1151.         // Set our limits for chance of drop
  1152.         if (dropChance < 1)
  1153.         {
  1154.             dropChance = 1;
  1155.         }
  1156.        
  1157.         // Get min and max Item quantity that can be dropped in one time
  1158.         final int minCount = drop.getMinDrop();
  1159.         final int maxCount = drop.getMaxDrop();
  1160.        
  1161.         // Get the item quantity dropped
  1162.         int itemCount = 0;
  1163.        
  1164.         // Check if the Item must be dropped
  1165.         int random = Rnd.get(DropData.MAX_CHANCE);
  1166.         while (random < dropChance)
  1167.         {
  1168.             // Get the item quantity dropped
  1169.             if (minCount < maxCount)
  1170.             {
  1171.                 itemCount += Rnd.get(minCount, maxCount);
  1172.             }
  1173.             else if (minCount == maxCount)
  1174.             {
  1175.                 itemCount += minCount;
  1176.             }
  1177.             else
  1178.             {
  1179.                 itemCount++;
  1180.             }
  1181.            
  1182.             // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1183.             dropChance -= DropData.MAX_CHANCE;
  1184.         }
  1185.        
  1186.         if (Config.CHAMPION_ENABLE)
  1187.         {
  1188.             if ((drop.getItemId() == 57) || ((drop.getItemId() >= 6360) && (drop.getItemId() <= 6362)))
  1189.             {
  1190.                 if (isBlueChampion())
  1191.                 {
  1192.                     itemCount *= Config.CHAMPION_ADENAS_REWARDS_BLUE;
  1193.                 }
  1194.                 else if (isRedChampion())
  1195.                 {
  1196.                     itemCount *= Config.CHAMPION_ADENAS_REWARDS_RED;
  1197.                 }
  1198.             }
  1199.         }
  1200.        
  1201.         if (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)
  1202.         {
  1203.             itemCount *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_DROP_SEAL_STONES);
  1204.         }
  1205.        
  1206.         if (itemCount > 0)
  1207.         {
  1208.             return new ItemHolder(drop.getItemId(), itemCount);
  1209.         }
  1210.        
  1211.         return null;
  1212.     }
  1213.    
  1214.     /**
  1215.      * Calculates quantity of items for specific drop CATEGORY according to current situation <br>
  1216.      * Only a max of ONE item from a category is allowed to be dropped.
  1217.      * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1218.      * @param categoryDrops The category to make checks on.
  1219.      * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  1220.      * @return the ItemHolder.
  1221.      */
  1222.     private ItemHolder calculateCategorizedRewardItem(L2PcInstance lastAttacker, DropCategory categoryDrops, int levelModifier)
  1223.     {
  1224.         if (categoryDrops == null)
  1225.         {
  1226.             return null;
  1227.         }
  1228.        
  1229.         // Get default drop chance for the category (that's the sum of chances for all items in the category)
  1230.         // keep track of the base category chance as it'll be used later, if an item is drop from the category.
  1231.         // for everything else, use the total "categoryDropChance"
  1232.         int basecategoryDropChance = categoryDrops.getCategoryChance();
  1233.         int categoryDropChance = basecategoryDropChance;
  1234.        
  1235.         if (Config.DEEPBLUE_DROP_RULES)
  1236.         {
  1237.             int deepBlueDrop = (levelModifier > 0) ? 3 : 1;
  1238.            
  1239.             // Check if we should apply our maths so deep blue mobs will not drop that easy
  1240.             categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier) / 100)) / deepBlueDrop);
  1241.         }
  1242.        
  1243.         // Applies Drop rates
  1244.         //categoryDropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1245.         if (isRaid() && !isRaidMinion())
  1246.         {
  1247.             categoryDropChance *= (this instanceof L2GrandBossInstance) ? (int) Config.RATE_DROP_ITEMS_BY_GRAND_RAID : (int) Config.RATE_DROP_ITEMS_BY_RAID;
  1248.         }
  1249.         else
  1250.         {
  1251.             categoryDropChance *= (int) Config.RATE_DROP_ITEMS;
  1252.         }
  1253.        
  1254.         if (Config.CHAMPION_ENABLE)
  1255.         {
  1256.             if (isBlueChampion())
  1257.             {
  1258.                 categoryDropChance *= Config.CHAMPION_REWARDS_BLUE;
  1259.             }
  1260.             else if (isRedChampion())
  1261.             {
  1262.                 categoryDropChance *= Config.CHAMPION_REWARDS_RED;
  1263.             }
  1264.         }
  1265.        
  1266.         // Set our limits for chance of drop
  1267.         if (categoryDropChance < 1)
  1268.         {
  1269.             categoryDropChance = 1;
  1270.         }
  1271.        
  1272.         // Check if an Item from this category must be dropped
  1273.         if (Rnd.get(DropData.MAX_CHANCE) < categoryDropChance)
  1274.         {
  1275.             DropData drop = categoryDrops.dropOne(isRaid() && !isRaidMinion());
  1276.             if (drop == null)
  1277.             {
  1278.                 return null;
  1279.             }
  1280.            
  1281.             // Now decide the quantity to drop based on the rates and penalties. To get this value
  1282.             // simply divide the modified categoryDropChance by the base category chance. This
  1283.             // results in a chance that will dictate the drops amounts: for each amount over 100
  1284.             // that it is, it will give another chance to add to the min/max quantities.
  1285.             //
  1286.             // For example, If the final chance is 120%, then the item should drop between
  1287.             // its min and max one time, and then have 20% chance to drop again. If the final
  1288.             // chance is 330%, it will similarly give 3 times the min and max, and have a 30%
  1289.             // chance to give a 4th time.
  1290.             // At least 1 item will be dropped for sure. So the chance will be adjusted to 100%
  1291.             // if smaller.
  1292.            
  1293.             double dropChance = drop.getChance();
  1294.             if (drop.getItemId() == 57)
  1295.             {
  1296.                 dropChance *= Config.RATE_DROP_ADENA;
  1297.                 // [TODO] Rate Or Chance? x2 double adena gift?
  1298.                 dropChance *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_DROP_ADENA);
  1299.             }
  1300.             else
  1301.             {
  1302.                 //dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1303.                 if (isRaid() && !isRaidMinion())
  1304.                 {
  1305.                     dropChance *= (this instanceof L2GrandBossInstance) ? (int) Config.RATE_DROP_ITEMS_BY_GRAND_RAID : (int) Config.RATE_DROP_ITEMS_BY_RAID;
  1306.                 }
  1307.                 else
  1308.                 {
  1309.                     dropChance *= (int) Config.RATE_DROP_ITEMS;
  1310.                 }
  1311.                 dropChance *= lastAttacker.getPremiumAttribute(Premium.MODIFIER_DROP_ITEMS);
  1312.             }
  1313.            
  1314.             if (Config.CHAMPION_ENABLE)
  1315.             {
  1316.                 if (isBlueChampion())
  1317.                 {
  1318.                     dropChance *= Config.CHAMPION_REWARDS_BLUE;
  1319.                 }
  1320.                 else if (isRedChampion())
  1321.                 {
  1322.                     dropChance *= Config.CHAMPION_REWARDS_RED;
  1323.                 }
  1324.             }
  1325.            
  1326.             if (dropChance < DropData.MAX_CHANCE)
  1327.             {
  1328.                 dropChance = DropData.MAX_CHANCE;
  1329.             }
  1330.            
  1331.             // Get min and max Item quantity that can be dropped in one time
  1332.             final int min = drop.getMinDrop();
  1333.             final int max = drop.getMaxDrop();
  1334.            
  1335.             // Get the item quantity dropped
  1336.             int itemCount = 0;
  1337.            
  1338.             // Check if the Item must be dropped
  1339.             int random = Rnd.get(DropData.MAX_CHANCE);
  1340.             while (random < dropChance)
  1341.             {
  1342.                 // Get the item quantity dropped
  1343.                 if (min < max)
  1344.                 {
  1345.                     itemCount += Rnd.get(min, max);
  1346.                 }
  1347.                 else if (min == max)
  1348.                 {
  1349.                     itemCount += min;
  1350.                 }
  1351.                 else
  1352.                 {
  1353.                     itemCount++;
  1354.                 }
  1355.                
  1356.                 // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1357.                 dropChance -= DropData.MAX_CHANCE;
  1358.             }
  1359.            
  1360.             if (Config.CHAMPION_ENABLE)
  1361.             {
  1362.                 if ((drop.getItemId() == 57) || ((drop.getItemId() >= 6360) && (drop.getItemId() <= 6362)))
  1363.                 {
  1364.                     if (isBlueChampion())
  1365.                     {
  1366.                         itemCount *= Config.CHAMPION_ADENAS_REWARDS_BLUE;
  1367.                     }
  1368.                     else if (isRedChampion())
  1369.                     {
  1370.                         itemCount *= Config.CHAMPION_ADENAS_REWARDS_RED;
  1371.                     }
  1372.                 }
  1373.             }
  1374.            
  1375.             if (itemCount > 0)
  1376.             {
  1377.                 return new ItemHolder(drop.getItemId(), itemCount);
  1378.             }
  1379.         }
  1380.         return null;
  1381.     }
  1382.    
  1383.     /**
  1384.      * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1385.      * @return the level modifier for drop
  1386.      */
  1387.     private int calculateLevelModifierForDrop(L2PcInstance lastAttacker)
  1388.     {
  1389.         if (Config.DEEPBLUE_DROP_RULES)
  1390.         {
  1391.             int highestLevel = lastAttacker.getLevel();
  1392.            
  1393.             // Check to prevent very high level player to nearly kill mob and let low level player do the last hit.
  1394.             if (!getAttackByList().isEmpty())
  1395.             {
  1396.                 for (L2Character atkChar : getAttackByList())
  1397.                 {
  1398.                     if (atkChar != null && atkChar.getLevel() > highestLevel)
  1399.                     {
  1400.                         highestLevel = atkChar.getLevel();
  1401.                     }
  1402.                 }
  1403.             }
  1404.            
  1405.             // According to official data (Prima), deep blue mobs are 9 or more levels below players
  1406.             if (highestLevel - 9 >= getLevel())
  1407.             {
  1408.                 return ((highestLevel - (getLevel() + 8)) * 9);
  1409.             }
  1410.         }
  1411.         return 0;
  1412.     }
  1413.    
  1414.     private static ItemHolder calculateCategorizedHerbItem(L2PcInstance lastAttacker, DropCategory categoryDrops, int levelModifier)
  1415.     {
  1416.         if (categoryDrops == null)
  1417.         {
  1418.             return null;
  1419.         }
  1420.        
  1421.         int categoryDropChance = categoryDrops.getCategoryChance();
  1422.        
  1423.         // Applies Drop rates
  1424.         switch (categoryDrops.getCategoryType())
  1425.         {
  1426.             case 1:
  1427.                 categoryDropChance *= Config.RATE_DROP_HP_HERBS;
  1428.                 break;
  1429.             case 2:
  1430.                 categoryDropChance *= Config.RATE_DROP_MP_HERBS;
  1431.                 break;
  1432.             case 3:
  1433.                 categoryDropChance *= Config.RATE_DROP_SPECIAL_HERBS;
  1434.                 break;
  1435.             default:
  1436.                 categoryDropChance *= Config.RATE_DROP_COMMON_HERBS;
  1437.         }
  1438.        
  1439.         // Drop chance is affected by deep blue drop rule.
  1440.         if (Config.DEEPBLUE_DROP_RULES)
  1441.         {
  1442.             int deepBlueDrop = (levelModifier > 0) ? 3 : 1;
  1443.            
  1444.             // Check if we should apply our maths so deep blue mobs will not drop that easy
  1445.             categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier) / 100)) / deepBlueDrop);
  1446.         }
  1447.        
  1448.         // Check if an Item from this category must be dropped
  1449.         if (Rnd.get(DropData.MAX_CHANCE) < Math.max(1, categoryDropChance))
  1450.         {
  1451.             final DropData drop = categoryDrops.dropOne(false);
  1452.            
  1453.             if (drop == null)
  1454.             {
  1455.                 return null;
  1456.             }
  1457.            
  1458.             /*
  1459.              * Now decide the quantity to drop based on the rates and penalties. To get this value, simply divide the modified categoryDropChance by the base category chance. This results in a chance that will dictate the drops amounts : for each amount over 100 that it is, it will give another
  1460.              * chance to add to the min/max quantities. For example, if the final chance is 120%, then the item should drop between its min and max one time, and then have 20% chance to drop again. If the final chance is 330%, it will similarly give 3 times the min and max, and have a 30% chance to
  1461.              * give a 4th time. At least 1 item will be dropped for sure. So the chance will be adjusted to 100% if smaller.
  1462.              */
  1463.             double dropChance = drop.getChance();
  1464.            
  1465.             switch (categoryDrops.getCategoryType())
  1466.             {
  1467.                 case 1:
  1468.                     dropChance *= Config.RATE_DROP_HP_HERBS;
  1469.                     break;
  1470.                 case 2:
  1471.                     dropChance *= Config.RATE_DROP_MP_HERBS;
  1472.                     break;
  1473.                 case 3:
  1474.                     dropChance *= Config.RATE_DROP_SPECIAL_HERBS;
  1475.                     break;
  1476.                 default:
  1477.                     dropChance *= Config.RATE_DROP_COMMON_HERBS;
  1478.             }
  1479.            
  1480.             if (dropChance < DropData.MAX_CHANCE)
  1481.             {
  1482.                 dropChance = DropData.MAX_CHANCE;
  1483.             }
  1484.            
  1485.             // Get min and max Item quantity that can be dropped in one time
  1486.             final int min = drop.getMinDrop();
  1487.             final int max = drop.getMaxDrop();
  1488.            
  1489.             // Get the item quantity dropped
  1490.             int itemCount = 0;
  1491.            
  1492.             // Check if the Item must be dropped
  1493.             int random = Rnd.get(DropData.MAX_CHANCE);
  1494.             while (random < dropChance)
  1495.             {
  1496.                 // Get the item quantity dropped
  1497.                 if (min < max)
  1498.                 {
  1499.                     itemCount += Rnd.get(min, max);
  1500.                 }
  1501.                 else if (min == max)
  1502.                 {
  1503.                     itemCount += min;
  1504.                 }
  1505.                 else
  1506.                 {
  1507.                     itemCount++;
  1508.                 }
  1509.                
  1510.                 // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1511.                 dropChance -= DropData.MAX_CHANCE;
  1512.             }
  1513.            
  1514.             if (itemCount > 0)
  1515.             {
  1516.                 return new ItemHolder(drop.getItemId(), itemCount);
  1517.             }
  1518.         }
  1519.         return null;
  1520.     }
  1521.    
  1522.     /**
  1523.      * Manage Base & Quests drops of L2Attackable (called by calculateRewards).
  1524.      * <ul>
  1525.      * <li>Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops</li>
  1526.      * <li>For each possible drops (base + quests), calculate which one must be dropped (random)</li>
  1527.      * <li>Get each Item quantity dropped (random)</li>
  1528.      * <li>Create this or these ItemInstance corresponding to each Item Identifier dropped</li>
  1529.      * <li>If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable</li>
  1530.      * <li>If the autoLoot mode isn't actif or if the L2Character that has killed the L2Attackable is not a L2PcInstance, add this or these Item(s) in the world as a visible object at the position where mob was last</li>
  1531.      * </ul>
  1532.      * @param mainDamageDealer The L2Character that made the most damage.
  1533.      */
  1534.     public void doItemDrop(L2Character mainDamageDealer)
  1535.     {
  1536.         doItemDrop(getTemplate(), mainDamageDealer);
  1537.     }
  1538.    
  1539.     public void doItemDrop(NpcTemplate npcTemplate, L2Character mainDamageDealer)
  1540.     {
  1541.         if (mainDamageDealer == null)
  1542.         {
  1543.             return;
  1544.         }
  1545.        
  1546.         // Don't drop anything if the last attacker or owner isn't L2PcInstance
  1547.         L2PcInstance player = mainDamageDealer.getActingPlayer();
  1548.         if (player == null)
  1549.         {
  1550.             return;
  1551.         }
  1552.        
  1553.         if (player.getEvent() != null && player.getEvent() == _event && _event.isRunning())
  1554.         {
  1555.             if (!_event.canDropItems(this, player))
  1556.             {
  1557.                 return;
  1558.             }
  1559.         }
  1560.        
  1561.         // level modifier in %'s (will be subtracted from drop chance)
  1562.         int levelModifier = calculateLevelModifierForDrop(player);
  1563.        
  1564.         CursedWeaponsManager.getInstance().checkDrop(this, player);
  1565.        
  1566.         // now throw all categorized drops and handle spoil.
  1567.         for (DropCategory cat : npcTemplate.getDropData())
  1568.         {
  1569.             ItemHolder item = null;
  1570.             if (cat.isSweep())
  1571.             {
  1572.                 if (getSpoilerId() != 0)
  1573.                 {
  1574.                     for (DropData drop : cat.getAllDrops())
  1575.                     {
  1576.                         item = calculateRewardItem(player, drop, levelModifier, true);
  1577.                         if (item == null)
  1578.                         {
  1579.                             continue;
  1580.                         }
  1581.                        
  1582.                         _sweepItems.add(item);
  1583.                     }
  1584.                 }
  1585.             }
  1586.             else
  1587.             {
  1588.                 if (isSeeded())
  1589.                 {
  1590.                     DropData drop = cat.dropSeedAllowedDropsOnly();
  1591.                     if (drop == null)
  1592.                     {
  1593.                         continue;
  1594.                     }
  1595.                    
  1596.                     item = calculateRewardItem(player, drop, levelModifier, false);
  1597.                 }
  1598.                 else
  1599.                 {
  1600.                     item = calculateCategorizedRewardItem(player, cat, levelModifier);
  1601.                 }
  1602.                
  1603.                 if (item != null)
  1604.                 {
  1605.                     // Check if the autoLoot mode is active
  1606.                     if ((isRaid() && Config.AUTO_LOOT_RAID) || (!isRaid() && Config.AUTO_LOOT && player.isAutoLoot()))
  1607.                     {
  1608.                         player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  1609.                     }
  1610.                     else
  1611.                     {
  1612.                         dropItem(player, item); // drop the item on the ground
  1613.                     }
  1614.                    
  1615.                     // Broadcast message if RaidBoss was defeated
  1616.                     if (isRaid() && !isRaidMinion())
  1617.                     {
  1618.                         broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.S1_DIED_DROPPED_S3_S2).addCharName(this).addItemName(item.getId()).addNumber(item.getCount()));
  1619.                     }
  1620.                 }
  1621.             }
  1622.         }
  1623.         // Apply special item drop for champions.
  1624.         if (Config.CHAMPION_ENABLE)
  1625.         {
  1626.             if (isBlueChampion() && Config.CHAMPION_REWARD_BLUE > 0)
  1627.             {
  1628.                 int dropChance = Config.CHAMPION_REWARD_BLUE;
  1629.                
  1630.                 // Apply level modifier, if any/wanted.
  1631.                 if (Config.DEEPBLUE_DROP_RULES)
  1632.                 {
  1633.                     int deepBlueDrop = (levelModifier > 0) ? 3 : 1;
  1634.                    
  1635.                     //  Check if we should apply our maths so deep blue mobs will not drop that easy.
  1636.                     dropChance = ((Config.CHAMPION_REWARD_BLUE - ((Config.CHAMPION_REWARD_BLUE * levelModifier) / 100)) / deepBlueDrop);
  1637.                 }
  1638.                
  1639.                 if (Rnd.get(100) < dropChance)
  1640.                 {
  1641.                     final ItemHolder item = new ItemHolder(Config.CHAMPION_REWARD_ID_BLUE, Math.max(1, Rnd.get(1, Config.CHAMPION_REWARD_QTY_BLUE)));
  1642.                     if (Config.AUTO_LOOT)
  1643.                     {
  1644.                         player.addItem("ChampionLoot", item.getId(), item.getCount(), this, true);
  1645.                     }
  1646.                     else
  1647.                     {
  1648.                         dropItem(player, item);
  1649.                     }
  1650.                 }
  1651.             }
  1652.             else if (isRedChampion() && Config.CHAMPION_REWARD_RED > 0)
  1653.             {
  1654.                 int dropChance = Config.CHAMPION_REWARD_RED;
  1655.                
  1656.                 // Apply level modifier, if any/wanted.
  1657.                 if (Config.DEEPBLUE_DROP_RULES)
  1658.                 {
  1659.                     int deepBlueDrop = (levelModifier > 0) ? 3 : 1;
  1660.                    
  1661.                     // Check if we should apply our maths so deep blue mobs will not drop that easy.
  1662.                     dropChance = ((Config.CHAMPION_REWARD_RED - ((Config.CHAMPION_REWARD_RED * levelModifier) / 100)) / deepBlueDrop);
  1663.                 }
  1664.                
  1665.                 if (Rnd.get(100) < dropChance)
  1666.                 {
  1667.                     final ItemHolder item = new ItemHolder(Config.CHAMPION_REWARD_ID_RED, Math.max(1, Rnd.get(1, Config.CHAMPION_REWARD_QTY_RED)));
  1668.                     if (Config.AUTO_LOOT)
  1669.                     {
  1670.                         player.addItem("ChampionLoot", item.getId(), item.getCount(), this, true);
  1671.                     }
  1672.                     else
  1673.                     {
  1674.                         dropItem(player, item);
  1675.                     }
  1676.                 }
  1677.                
  1678.             }
  1679.            
  1680.         }
  1681.        
  1682.         // AutoEvent Drop
  1683.         if (EventsDropManager.getInstance().haveActiveEvent())
  1684.         {
  1685.             Map<Integer, Integer> itemsEvent = EventsDropManager.getInstance().calculateRewardItem(npcTemplate, mainDamageDealer);
  1686.             if (!itemsEvent.isEmpty())
  1687.             {
  1688.                 for (Integer itemId : itemsEvent.keySet())
  1689.                 {
  1690.                     if (itemsEvent.get(itemId) > 0)
  1691.                     {
  1692.                         ItemHolder item = new ItemHolder(itemId, itemsEvent.get(itemId));
  1693.                         if (Config.AUTO_LOOT && player.isAutoLoot())
  1694.                         {
  1695.                             player.doAutoLoot(this, item);
  1696.                         }
  1697.                         else
  1698.                         {
  1699.                             dropItem(player, item);
  1700.                         }
  1701.                     }
  1702.                 }
  1703.             }
  1704.         }
  1705.        
  1706.         // Herbs.
  1707.         if (getTemplate().getDropHerbGroup() > 0)
  1708.         {
  1709.             for (DropCategory cat : HerbDropTable.getInstance().getHerbDroplist(getTemplate().getDropHerbGroup()))
  1710.             {
  1711.                 final ItemHolder item = calculateCategorizedHerbItem(player, cat, levelModifier);
  1712.                 if (item != null)
  1713.                 {
  1714.                     // more than one herb cant be auto looted!
  1715.                     if (Config.AUTO_LOOT_HERBS)
  1716.                     {
  1717.                         player.addItem("Loot", item.getId(), 1, this, true);
  1718.                     }
  1719.                     else
  1720.                     {
  1721.                         // If multiple similar herbs drop, split them and make a unique drop per item.
  1722.                         final int count = item.getCount();
  1723.                         if (count > 1)
  1724.                         {
  1725.                             item.setCount(1);
  1726.                             for (int i = 0; i < count; i++)
  1727.                             {
  1728.                                 dropItem(player, item);
  1729.                             }
  1730.                         }
  1731.                         else
  1732.                         {
  1733.                             dropItem(player, item);
  1734.                         }
  1735.                     }
  1736.                 }
  1737.             }
  1738.         }
  1739.        
  1740.         if (Rnd.get(100) <= Config.ENCHANT_BOT_CHANCE && Config.ALLOW_PRIVATE_ANTI_BOT)
  1741.         {
  1742.             PrivateAntiBot.privateantibot(player);//Anti bot security question
  1743.         }
  1744.     }
  1745.    
  1746.     /**
  1747.      * Drop reward item.
  1748.      * @param mainDamageDealer The player who made highest damage.
  1749.      * @param item The ItemHolder.
  1750.      * @return the dropped item instance.
  1751.      */
  1752.     public ItemInstance dropItem(L2PcInstance mainDamageDealer, ItemHolder item)
  1753.     {
  1754.         int randDropLim = 70;
  1755.        
  1756.         ItemInstance ditem = null;
  1757.         for (int i = 0; i < item.getCount(); i++)
  1758.         {
  1759.             // Randomize drop position
  1760.             int newX = getX() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1761.             int newY = getY() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1762.             int newZ = Math.max(getZ(), mainDamageDealer.getZ()) + 20;
  1763.            
  1764.             if (ItemTable.getInstance().getTemplate(item.getId()) != null)
  1765.             {
  1766.                 // Init the dropped ItemInstance and add it in the world as a visible object at the position where mob was last
  1767.                 ditem = ItemTable.getInstance().createItem("Loot", item.getId(), item.getCount(), mainDamageDealer, this);
  1768.                 ditem.getDropProtection().protect(mainDamageDealer);
  1769.                 ditem.dropMe(this, newX, newY, newZ);
  1770.                
  1771.                 // Add drop to auto destroy item task
  1772.                 if (!Config.LIST_PROTECTED_ITEMS.contains(item.getId()))
  1773.                 {
  1774.                     if ((Config.ITEM_AUTO_DESTROY_TIME > 0 && ditem.getItemType() != EtcItemType.HERB) || (Config.HERB_AUTO_DESTROY_TIME > 0 && ditem.getItemType() == EtcItemType.HERB))
  1775.                     {
  1776.                         ItemsAutoDestroyTaskManager.getInstance().addItem(ditem);
  1777.                     }
  1778.                 }
  1779.                 ditem.setProtected(false);
  1780.                
  1781.                 // If stackable, end loop as entire count is included in 1 instance of item
  1782.                 if (ditem.isStackable() || !Config.MULTIPLE_ITEM_DROP)
  1783.                 {
  1784.                     break;
  1785.                 }
  1786.             }
  1787.             else
  1788.             {
  1789.                 _log.warn("Item doesn't exist so cannot be dropped. Item ID: " + item.getId());
  1790.             }
  1791.         }
  1792.         return ditem;
  1793.     }
  1794.    
  1795.     public ItemInstance dropItem(L2PcInstance lastAttacker, int itemId, int itemCount)
  1796.     {
  1797.         return dropItem(lastAttacker, new ItemHolder(itemId, itemCount));
  1798.     }
  1799.    
  1800.     /**
  1801.      * @return the active weapon of this L2Attackable (= null).
  1802.      */
  1803.     public ItemInstance getActiveWeapon()
  1804.     {
  1805.         return null;
  1806.     }
  1807.    
  1808.     /**
  1809.      * @return True if the _aggroList of this L2Attackable is Empty.
  1810.      */
  1811.     public boolean gotNoTarget()
  1812.     {
  1813.         return _aggroList.isEmpty();
  1814.     }
  1815.    
  1816.     /**
  1817.      * @param player The L2Character searched in the _aggroList of the L2Attackable
  1818.      * @return True if the _aggroList of this L2Attackable contains the L2Character.
  1819.      */
  1820.     public boolean containsTarget(L2Character player)
  1821.     {
  1822.         return _aggroList.containsKey(player);
  1823.     }
  1824.    
  1825.     /**
  1826.      * Clear the _aggroList of the L2Attackable.
  1827.      */
  1828.     public void clearAggroList()
  1829.     {
  1830.         _aggroList.clear();
  1831.     }
  1832.    
  1833.     /**
  1834.      * @return true if a Dwarf used Spoil on the L2Attackable.
  1835.      */
  1836.     public boolean isSpoiled()
  1837.     {
  1838.         return !_sweepItems.isEmpty();
  1839.     }
  1840.    
  1841.     /**
  1842.      * @return list containing all ItemHolder that can be spoiled.
  1843.      */
  1844.     public List<ItemHolder> getSweepItems()
  1845.     {
  1846.         return _sweepItems;
  1847.     }
  1848.    
  1849.     /**
  1850.      * @return list containing all ItemHolder that can be harvested.
  1851.      */
  1852.     public List<ItemHolder> getHarvestItems()
  1853.     {
  1854.         return _harvestItems;
  1855.     }
  1856.    
  1857.     /**
  1858.      * Set the over-hit flag on the L2Attackable.
  1859.      * @param status The status of the over-hit flag
  1860.      */
  1861.     public void overhitEnabled(boolean status)
  1862.     {
  1863.         _overhit = status;
  1864.     }
  1865.    
  1866.     /**
  1867.      * Set the over-hit values like the attacker who did the strike and the amount of damage done by the skill.
  1868.      * @param attacker The L2Character who hit on the L2Attackable using the over-hit enabled skill
  1869.      * @param damage The ammount of damage done by the over-hit enabled skill on the L2Attackable
  1870.      */
  1871.     public void setOverhitValues(L2Character attacker, double damage)
  1872.     {
  1873.         // Calculate the over-hit damage
  1874.         // Ex: mob had 10 HP left, over-hit skill did 50 damage total, over-hit damage is 40
  1875.         double overhitDmg = ((getCurrentHp() - damage) * (-1));
  1876.         if (overhitDmg < 0)
  1877.         {
  1878.             // we didn't killed the mob with the over-hit strike. (it wasn't really an over-hit strike)
  1879.             // let's just clear all the over-hit related values
  1880.             overhitEnabled(false);
  1881.             _overhitDamage = 0;
  1882.             _overhitAttacker = null;
  1883.             return;
  1884.         }
  1885.         overhitEnabled(true);
  1886.         _overhitDamage = overhitDmg;
  1887.         _overhitAttacker = attacker;
  1888.     }
  1889.    
  1890.     /**
  1891.      * @return the L2Character who hit on the L2Attackable using an over-hit enabled skill.
  1892.      */
  1893.     public L2Character getOverhitAttacker()
  1894.     {
  1895.         return _overhitAttacker;
  1896.     }
  1897.    
  1898.     /**
  1899.      * @return the amount of damage done on the L2Attackable using an over-hit enabled skill.
  1900.      */
  1901.     public double getOverhitDamage()
  1902.     {
  1903.         return _overhitDamage;
  1904.     }
  1905.    
  1906.     /**
  1907.      * @return True if the L2Attackable was hit by an over-hit enabled skill.
  1908.      */
  1909.     public boolean isOverhit()
  1910.     {
  1911.         return _overhit;
  1912.     }
  1913.    
  1914.     /**
  1915.      * Adds an attacker that successfully absorbed the soul of this L2Attackable into the _absorbersList.
  1916.      * @param user : The L2PcInstance who attacked the monster.
  1917.      * @param crystal : The ItemInstance which was used to register.
  1918.      */
  1919.     public void addAbsorber(L2PcInstance user, ItemInstance crystal)
  1920.     {
  1921.         // If the L2Character attacker isn't already in the _absorbersList of this L2Attackable, add it
  1922.         AbsorbInfo ai = _absorbersList.get(user.getObjectId());
  1923.         if (ai == null)
  1924.         {
  1925.             // Create absorb info.
  1926.             _absorbersList.put(user.getObjectId(), new AbsorbInfo(crystal.getObjectId()));
  1927.         }
  1928.         else
  1929.         {
  1930.             // Add absorb info, unless already registered.
  1931.             if (!ai._registered)
  1932.             {
  1933.                 ai._itemObjectId = crystal.getObjectId();
  1934.             }
  1935.         }
  1936.     }
  1937.    
  1938.     public void registerAbsorber(L2PcInstance user)
  1939.     {
  1940.         // Get AbsorbInfo for user.
  1941.         AbsorbInfo ai = _absorbersList.get(user.getObjectId());
  1942.         if (ai == null)
  1943.         {
  1944.             return;
  1945.         }
  1946.        
  1947.         // Check item being used and register player to mob's absorber list.
  1948.         if (user.getInventory().getItemByObjectId(ai._itemObjectId) == null)
  1949.         {
  1950.             return;
  1951.         }
  1952.        
  1953.         // Register AbsorbInfo.
  1954.         if (!ai._registered)
  1955.         {
  1956.             ai._absorbedHpPercent = (int) ((100 * getCurrentHp()) / getMaxHp());
  1957.             ai._registered = true;
  1958.         }
  1959.     }
  1960.    
  1961.     public void resetAbsorberList()
  1962.     {
  1963.         _absorbersList.clear();
  1964.     }
  1965.    
  1966.     public AbsorbInfo getAbsorbInfo(int npcObjectId)
  1967.     {
  1968.         return _absorbersList.get(npcObjectId);
  1969.     }
  1970.    
  1971.     /**
  1972.      * Calculate the Experience and SP to distribute to attacker (L2PcInstance, L2SummonInstance or L2Party) of the L2Attackable.
  1973.      * @param diff The difference of level between attacker (L2PcInstance, L2SummonInstance or L2Party) and the L2Attackable
  1974.      * @param damage The damages given by the attacker (L2PcInstance, L2SummonInstance or L2Party)
  1975.      * @param totalDamage The total damage done.
  1976.      * @return an array consisting of xp and sp values.
  1977.      */
  1978.     private int[] calculateExpAndSp(int diff, int damage, long totalDamage)
  1979.     {
  1980.         if (diff < -5)
  1981.         {
  1982.             diff = -5;
  1983.         }
  1984.        
  1985.         double xp = (double) getExpReward() * damage / totalDamage;
  1986.         double sp = (double) getSpReward() * damage / totalDamage;
  1987.        
  1988.         final L2Skill hpSkill = getKnownSkill(4408);
  1989.         if (hpSkill != null)
  1990.         {
  1991.             xp *= hpSkill.getPower();
  1992.             sp *= hpSkill.getPower();
  1993.         }
  1994.        
  1995.         if (diff > 5) // formula revised May 07
  1996.         {
  1997.             double pow = Math.pow((double) 5 / 6, diff - 5);
  1998.             xp = xp * pow;
  1999.             sp = sp * pow;
  2000.         }
  2001.        
  2002.         if (xp <= 0)
  2003.         {
  2004.             xp = 0;
  2005.             sp = 0;
  2006.         }
  2007.         else if (sp <= 0)
  2008.         {
  2009.             sp = 0;
  2010.         }
  2011.        
  2012.         int[] tmp =
  2013.         {
  2014.             (int) xp,
  2015.             (int) sp
  2016.         };
  2017.        
  2018.         return tmp;
  2019.     }
  2020.    
  2021.     public long calculateOverhitExp(long normalExp)
  2022.     {
  2023.         // Get the percentage based on the total of extra (over-hit) damage done relative to the total (maximum) ammount of HP on the L2Attackable
  2024.         double overhitPercentage = ((getOverhitDamage() * 100) / getMaxHp());
  2025.        
  2026.         // Over-hit damage percentages are limited to 25% max
  2027.         if (overhitPercentage > 25)
  2028.         {
  2029.             overhitPercentage = 25;
  2030.         }
  2031.        
  2032.         // Get the overhit exp bonus according to the above over-hit damage percentage
  2033.         // (1/1 basis - 13% of over-hit damage, 13% of extra exp is given, and so on...)
  2034.         double overhitExp = ((overhitPercentage / 100) * normalExp);
  2035.        
  2036.         // Return the rounded ammount of exp points to be added to the player's normal exp reward
  2037.         return Math.round(overhitExp);
  2038.     }
  2039.    
  2040.     @Override
  2041.     public void onSpawn()
  2042.     {
  2043.         super.onSpawn();
  2044.        
  2045.         // Clear mob spoil/seed state
  2046.         setSpoilerId(0);
  2047.        
  2048.         // Clear all aggro char from list
  2049.         clearAggroList();
  2050.        
  2051.         // Clear Harvester Reward List
  2052.         _harvestItems.clear();
  2053.        
  2054.         // Clear mod Seeded stat
  2055.         _seedType = 0;
  2056.         _seederObjId = 0;
  2057.        
  2058.         // Clear overhit value
  2059.         overhitEnabled(false);
  2060.        
  2061.         _sweepItems.clear();
  2062.         resetAbsorberList();
  2063.        
  2064.         setWalking();
  2065.        
  2066.         // check the region where this mob is, do not activate the AI if region is inactive.
  2067.         if (!isInActiveRegion())
  2068.         {
  2069.             if (hasAI())
  2070.             {
  2071.                 getAI().stopAITask();
  2072.             }
  2073.         }
  2074.     }
  2075.    
  2076.     /**
  2077.      * Sets state of the mob to seeded.
  2078.      * @param objectId : The player object id to check.
  2079.      */
  2080.     public void setSeeded(int objectId)
  2081.     {
  2082.         if (_seedType != 0 && _seederObjId == objectId)
  2083.         {
  2084.             int count = 1;
  2085.            
  2086.             for (int skillId : getTemplate().getSkills().keySet())
  2087.             {
  2088.                 switch (skillId)
  2089.                 {
  2090.                     case 4303: // Strong type x2
  2091.                         count *= 2;
  2092.                         break;
  2093.                     case 4304: // Strong type x3
  2094.                         count *= 3;
  2095.                         break;
  2096.                     case 4305: // Strong type x4
  2097.                         count *= 4;
  2098.                         break;
  2099.                     case 4306: // Strong type x5
  2100.                         count *= 5;
  2101.                         break;
  2102.                     case 4307: // Strong type x6
  2103.                         count *= 6;
  2104.                         break;
  2105.                     case 4308: // Strong type x7
  2106.                         count *= 7;
  2107.                         break;
  2108.                     case 4309: // Strong type x8
  2109.                         count *= 8;
  2110.                         break;
  2111.                     case 4310: // Strong type x9
  2112.                         count *= 9;
  2113.                         break;
  2114.                 }
  2115.             }
  2116.            
  2117.             final int diff = (getLevel() - (L2Manor.getInstance().getSeedLevel(_seedType) - 5));
  2118.             if (diff > 0)
  2119.             {
  2120.                 count += diff;
  2121.             }
  2122.            
  2123.             _harvestItems.add(new ItemHolder(L2Manor.getInstance().getCropType(_seedType), count * Config.RATE_DROP_MANOR));
  2124.         }
  2125.     }
  2126.    
  2127.     /**
  2128.      * Sets the seed parameters, but not the seed state.
  2129.      * @param id - id of the seed.
  2130.      * @param objectId - the player objectId who is sowing the seed.
  2131.      */
  2132.     public void setSeeded(int id, int objectId)
  2133.     {
  2134.         if (_seedType == 0)
  2135.         {
  2136.             _seedType = id;
  2137.             _seederObjId = objectId;
  2138.         }
  2139.     }
  2140.    
  2141.     public int getSeederId()
  2142.     {
  2143.         return _seederObjId;
  2144.     }
  2145.    
  2146.     public int getSeedType()
  2147.     {
  2148.         return _seedType;
  2149.     }
  2150.    
  2151.     public boolean isSeeded()
  2152.     {
  2153.         return _seedType > 0;
  2154.     }
  2155.    
  2156.     /**
  2157.      * Check if the server allows Random Animation.<BR>
  2158.      * <BR>
  2159.      * This is located here because L2Monster and L2FriendlyMob both extend this class. The other non-pc instances extend either L2Npc or L2MonsterInstance.
  2160.      */
  2161.     @Override
  2162.     public boolean hasRandomAnimation()
  2163.     {
  2164.         return ((Config.MAX_MONSTER_ANIMATION > 0) && !isRaid());
  2165.     }
  2166.    
  2167.     @Override
  2168.     public boolean isMob()
  2169.     {
  2170.         return true; // This means we use MAX_MONSTER_ANIMATION instead of MAX_NPC_ANIMATION
  2171.     }
  2172.    
  2173.     protected void setCommandChannelTimer(CommandChannelTimer commandChannelTimer)
  2174.     {
  2175.         _commandChannelTimer = commandChannelTimer;
  2176.     }
  2177.    
  2178.     public CommandChannelTimer getCommandChannelTimer()
  2179.     {
  2180.         return _commandChannelTimer;
  2181.     }
  2182.    
  2183.     public L2CommandChannel getFirstCommandChannelAttacked()
  2184.     {
  2185.         return _firstCommandChannelAttacked;
  2186.     }
  2187.    
  2188.     public void setFirstCommandChannelAttacked(L2CommandChannel firstCommandChannelAttacked)
  2189.     {
  2190.         _firstCommandChannelAttacked = firstCommandChannelAttacked;
  2191.     }
  2192.    
  2193.     public long getCommandChannelLastAttack()
  2194.     {
  2195.         return _commandChannelLastAttack;
  2196.     }
  2197.    
  2198.     public void setCommandChannelLastAttack(long channelLastAttack)
  2199.     {
  2200.         _commandChannelLastAttack = channelLastAttack;
  2201.     }
  2202.    
  2203.     private static class CommandChannelTimer implements Runnable
  2204.     {
  2205.         private final L2Attackable _monster;
  2206.        
  2207.         public CommandChannelTimer(L2Attackable monster)
  2208.         {
  2209.             _monster = monster;
  2210.         }
  2211.        
  2212.         @Override
  2213.         public void run()
  2214.         {
  2215.             if ((System.currentTimeMillis() - _monster.getCommandChannelLastAttack()) > 900000)
  2216.             {
  2217.                 _monster.setCommandChannelTimer(null);
  2218.                 _monster.setFirstCommandChannelAttacked(null);
  2219.                 _monster.setCommandChannelLastAttack(0);
  2220.             }
  2221.             else
  2222.             {
  2223.                 ThreadPoolManager.getInstance().scheduleGeneral(this, 10000); // 10sec
  2224.             }
  2225.         }
  2226.     }
  2227.    
  2228.     public void returnHome()
  2229.     {
  2230.         clearAggroList();
  2231.        
  2232.         if (hasAI() && getSpawn() != null)
  2233.         {
  2234.             getAI().setIntention(CtrlIntention.MOVE_TO, new L2CharPosition(getSpawn().getLocx(), getSpawn().getLocy(), getSpawn().getLocz(), 0));
  2235.         }
  2236.     }
  2237.    
  2238.     /** Return True if the L2Character is RaidBoss or his minion. */
  2239.     @Override
  2240.     public boolean isRaid()
  2241.     {
  2242.         return _isRaid;
  2243.     }
  2244.    
  2245.     /**
  2246.      * Set this Npc as a Raid instance.
  2247.      * @param isRaid
  2248.      */
  2249.     @Override
  2250.     public void setIsRaid(boolean isRaid)
  2251.     {
  2252.         _isRaid = isRaid;
  2253.     }
  2254.    
  2255.     /**
  2256.      * Set this Npc as a Minion instance.
  2257.      * @param val
  2258.      */
  2259.     public void setIsRaidMinion(boolean val)
  2260.     {
  2261.         _isRaid = val;
  2262.         _isRaidMinion = val;
  2263.     }
  2264.    
  2265.     @Override
  2266.     public boolean isRaidMinion()
  2267.     {
  2268.         return _isRaidMinion;
  2269.     }
  2270.    
  2271.     @Override
  2272.     public boolean isMinion()
  2273.     {
  2274.         return getLeader() != null;
  2275.     }
  2276.    
  2277.     /**
  2278.      * @return leader of this minion or null.
  2279.      */
  2280.     public L2Attackable getLeader()
  2281.     {
  2282.         return null;
  2283.     }
  2284.    
  2285.     @Override
  2286.     protected void moveToLocation(int x, int y, int z, int offset)
  2287.     {
  2288.         if (isAttackingNow())
  2289.         {
  2290.             return;
  2291.         }
  2292.        
  2293.         super.moveToLocation(x, y, z, offset);
  2294.     }
  2295.    
  2296.     public boolean isGuard()
  2297.     {
  2298.         return false;
  2299.     }
  2300. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement