Guest User

Untitled

a guest
Jul 24th, 2016
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 76.01 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.List;
  18. import java.util.Map;
  19. import java.util.logging.Level;
  20.  
  21. import javolution.util.FastList;
  22. import javolution.util.FastMap;
  23. import net.sf.l2j.Config;
  24. import net.sf.l2j.gameserver.ItemsAutoDestroy;
  25. import net.sf.l2j.gameserver.ThreadPoolManager;
  26. import net.sf.l2j.gameserver.ai.CtrlIntention;
  27. import net.sf.l2j.gameserver.ai.L2AttackableAI;
  28. import net.sf.l2j.gameserver.ai.L2CharacterAI;
  29. import net.sf.l2j.gameserver.ai.L2FortSiegeGuardAI;
  30. import net.sf.l2j.gameserver.ai.L2SiegeGuardAI;
  31. import net.sf.l2j.gameserver.datatables.EventDroplist;
  32. import net.sf.l2j.gameserver.datatables.ItemTable;
  33. import net.sf.l2j.gameserver.datatables.SkillTable;
  34. import net.sf.l2j.gameserver.datatables.EventDroplist.DateDrop;
  35. import net.sf.l2j.gameserver.instancemanager.CursedWeaponsManager;
  36. import net.sf.l2j.gameserver.model.L2CharPosition;
  37. import net.sf.l2j.gameserver.model.L2CommandChannel;
  38. import net.sf.l2j.gameserver.model.L2DropCategory;
  39. import net.sf.l2j.gameserver.model.L2DropData;
  40. import net.sf.l2j.gameserver.model.L2ItemInstance;
  41. import net.sf.l2j.gameserver.model.L2Manor;
  42. import net.sf.l2j.gameserver.model.L2Party;
  43. import net.sf.l2j.gameserver.model.L2Skill;
  44. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  45. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  46. import net.sf.l2j.gameserver.model.actor.instance.L2FortSiegeGuardInstance;
  47. import net.sf.l2j.gameserver.model.actor.instance.L2GrandBossInstance;
  48. import net.sf.l2j.gameserver.model.actor.instance.L2MinionInstance;
  49. import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  50. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  51. import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance;
  52. import net.sf.l2j.gameserver.model.actor.instance.L2SiegeGuardInstance;
  53. import net.sf.l2j.gameserver.model.actor.instance.L2SummonInstance;
  54. import net.sf.l2j.gameserver.model.actor.knownlist.AttackableKnownList;
  55. import net.sf.l2j.gameserver.model.actor.status.AttackableStatus;
  56. import net.sf.l2j.gameserver.model.base.SoulCrystal;
  57. import net.sf.l2j.gameserver.model.quest.Quest;
  58. import net.sf.l2j.gameserver.model.quest.QuestState;
  59. import net.sf.l2j.gameserver.model.quest.State;
  60. import net.sf.l2j.gameserver.network.SystemMessageId;
  61. import net.sf.l2j.gameserver.network.clientpackets.Say2;
  62. import net.sf.l2j.gameserver.network.serverpackets.CreatureSay;
  63. import net.sf.l2j.gameserver.network.serverpackets.InventoryUpdate;
  64. import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
  65. import net.sf.l2j.gameserver.skills.Stats;
  66. import net.sf.l2j.gameserver.templates.chars.L2NpcTemplate;
  67. import net.sf.l2j.gameserver.templates.item.L2EtcItemType;
  68. import net.sf.l2j.gameserver.util.Util;
  69. import net.sf.l2j.util.Rnd;
  70.  
  71. public class L2Attackable extends L2Npc
  72. {
  73. /**
  74. * This class contains all AggroInfo of the L2Attackable against the attacker L2Character.
  75. *
  76. * Data:
  77. * attacker : The attacker L2Character concerned by this AggroInfo of this L2Attackable
  78. * hate : Hate level of this L2Attackable against the attacker L2Character (hate = damage)
  79. * damage : Number of damages that the attacker L2Character gave to this L2Attackable
  80. *
  81. */
  82. public final class AggroInfo
  83. {
  84. protected L2Character _attacker;
  85.  
  86. protected int _hate;
  87.  
  88. protected int _damage;
  89.  
  90. AggroInfo(L2Character pAttacker)
  91. {
  92. _attacker = pAttacker;
  93. }
  94.  
  95. public boolean equals(Object obj)
  96. {
  97. if (this == obj)
  98. return true;
  99.  
  100. if (obj instanceof AggroInfo)
  101. return (((AggroInfo)obj)._attacker == _attacker);
  102.  
  103. return false;
  104. }
  105.  
  106. @Override
  107. public int hashCode()
  108. {
  109. return _attacker.getObjectId();
  110. }
  111. }
  112.  
  113. /**
  114. * This class contains all RewardInfo of the L2Attackable against the any attacker L2Character, based on amount of damage done.
  115. *
  116. * Data:
  117. * attacker : The attacker L2Character concerned by this RewardInfo of this L2Attackable
  118. * dmg : Total amount of damage done by the attacker to this L2Attackable (summon + own)
  119. *
  120. */
  121. protected final class RewardInfo
  122. {
  123. protected L2Character _attacker;
  124.  
  125. protected int _dmg = 0;
  126.  
  127. public RewardInfo(L2Character pAttacker, int pDmg)
  128. {
  129. _attacker = pAttacker;
  130. _dmg = pDmg;
  131. }
  132.  
  133. public void addDamage(int pDmg)
  134. {
  135. _dmg += pDmg;
  136. }
  137.  
  138. @Override
  139. public boolean equals(Object obj)
  140. {
  141. if (this == obj)
  142. return true;
  143.  
  144. if (obj instanceof RewardInfo)
  145. return (((RewardInfo)obj)._attacker == _attacker);
  146.  
  147. return false;
  148. }
  149.  
  150. @Override
  151. public int hashCode()
  152. {
  153. return _attacker.getObjectId();
  154. }
  155. }
  156.  
  157. /**
  158. * This class contains all AbsorberInfo of the L2Attackable against the absorber L2Character.
  159. *
  160. * Data:
  161. * absorber : The attacker L2Character concerned by this AbsorberInfo of this L2Attackable
  162. */
  163. public final class AbsorberInfo
  164. {
  165. protected L2PcInstance _absorber;
  166.  
  167. protected int _crystalId;
  168.  
  169. protected double _absorbedHP;
  170.  
  171. AbsorberInfo(L2PcInstance attacker, int pCrystalId, double pAbsorbedHP)
  172. {
  173. _absorber = attacker;
  174. _crystalId = pCrystalId;
  175. _absorbedHP = pAbsorbedHP;
  176. }
  177.  
  178. @Override
  179. public boolean equals(Object obj)
  180. {
  181. if (this == obj)
  182. return true;
  183.  
  184. if (obj instanceof AbsorberInfo)
  185. return (((AbsorberInfo)obj)._absorber == _absorber);
  186.  
  187. return false;
  188. }
  189.  
  190. @Override
  191. public int hashCode()
  192. {
  193. return _absorber.getObjectId();
  194. }
  195. }
  196.  
  197. public final class RewardItem
  198. {
  199. protected int _itemId;
  200.  
  201. protected int _count;
  202.  
  203. public RewardItem(int itemId, int count)
  204. {
  205. _itemId = itemId;
  206. _count = count;
  207. }
  208.  
  209. public int getItemId() { return _itemId;}
  210.  
  211. public int getCount() { return _count;}
  212. }
  213.  
  214. private FastMap<L2Character, AggroInfo> _aggroList = new FastMap<L2Character, AggroInfo>().setShared(true);
  215.  
  216. public final FastMap<L2Character, AggroInfo> getAggroList()
  217. {
  218. return _aggroList;
  219. }
  220.  
  221. private boolean _isReturningToSpawnPoint = false;
  222.  
  223. public final boolean isReturningToSpawnPoint()
  224. {
  225. return _isReturningToSpawnPoint;
  226. }
  227.  
  228. public final void setisReturningToSpawnPoint(boolean value)
  229. {
  230. _isReturningToSpawnPoint = value;
  231. }
  232.  
  233. private boolean _canReturnToSpawnPoint = true;
  234.  
  235. public final boolean canReturnToSpawnPoint()
  236. {
  237. return _canReturnToSpawnPoint;
  238. }
  239.  
  240. public final void setCanReturnToSpawnPoint(boolean value)
  241. {
  242. _canReturnToSpawnPoint = value;
  243. }
  244.  
  245. private RewardItem[] _sweepItems;
  246.  
  247. private RewardItem[] _harvestItems;
  248. private boolean _seeded;
  249. private int _seedType = 0;
  250. private L2PcInstance _seeder = null;
  251.  
  252. private boolean _overhit;
  253.  
  254. private double _overhitDamage;
  255.  
  256. private L2Character _overhitAttacker;
  257.  
  258. private L2CommandChannel _firstCommandChannelAttacked = null;
  259. private CommandChannelTimer _commandChannelTimer = null;
  260.  
  261. private boolean _absorbed;
  262.  
  263. private FastMap<L2PcInstance, AbsorberInfo> _absorbersList = new FastMap<L2PcInstance, AbsorberInfo>().setShared(true);
  264.  
  265. private boolean _mustGiveExpSp;
  266.  
  267. /**
  268. * Constructor of L2Attackable (use L2Character and L2NpcInstance constructor).
  269. *
  270. * Actions:
  271. * Call the L2Character constructor to set the _template of the L2Attackable (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR)
  272. * Set the name of the L2Attackable
  273. * Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it
  274. *
  275. * @param objectId Identifier of the object to initialized
  276. * @param L2NpcTemplate Template to apply to the NPC
  277. */
  278. public L2Attackable(int objectId, L2NpcTemplate template)
  279. {
  280. super(objectId, template);
  281. setIsInvul(false);
  282. _mustGiveExpSp = true;
  283. }
  284.  
  285. @Override
  286. public AttackableKnownList getKnownList()
  287. {
  288. return (AttackableKnownList)super.getKnownList();
  289. }
  290.  
  291. @Override
  292. public void initKnownList()
  293. {
  294. setKnownList(new AttackableKnownList(this));
  295. }
  296.  
  297. @Override
  298. public AttackableStatus getStatus()
  299. {
  300. return (AttackableStatus) super.getStatus();
  301. }
  302.  
  303. @Override
  304. public void initCharStatus()
  305. {
  306. setStatus(new AttackableStatus(this));
  307. }
  308.  
  309. /**
  310. * Return the L2Character AI of the L2Attackable and if its null create a new one.
  311. */
  312. @Override
  313. public L2CharacterAI getAI()
  314. {
  315. L2CharacterAI ai = _ai;
  316.  
  317. if (ai == null)
  318. {
  319. synchronized(this)
  320. {
  321. if (_ai == null) _ai = new L2AttackableAI(new AIAccessor());
  322. return _ai;
  323. }
  324. }
  325. return ai;
  326. }
  327.  
  328. /**
  329. * Not used.
  330. * get condition to hate, actually isAggressive() is checked by monster and karma by guards in motheds that overwrite this one.
  331. *
  332. * @deprecated
  333. */
  334. @Deprecated
  335. public boolean getCondition2(L2Character target)
  336. {
  337. if (target instanceof L2NpcInstance || target instanceof L2DoorInstance)
  338. return false;
  339.  
  340. if
  341. (
  342. target.isAlikeDead()
  343. || !isInsideRadius(target, getAggroRange(), false, false)
  344. || Math.abs(getZ()-target.getZ()) > 100
  345. )
  346. return false;
  347.  
  348. return !target.isInvul();
  349. }
  350.  
  351. /**
  352. * Reduce the current HP of the L2Attackable.
  353. *
  354. * @param damage The HP decrease value
  355. * @param attacker The L2Character who attacks
  356. */
  357. @Override
  358. public void reduceCurrentHp(double damage, L2Character attacker, L2Skill skill)
  359. {
  360. reduceCurrentHp(damage, attacker, true, false, skill);
  361. }
  362.  
  363. /**
  364. * Reduce the current HP of the L2Attackable, update its _aggroList and launch the doDie Task if necessary.
  365. *
  366. * @param i The HP decrease value
  367. * @param attacker The L2Character who attacks
  368. * @param awake The awake state (If True : stop sleeping)
  369. */
  370. @Override
  371. public void reduceCurrentHp(double damage, L2Character attacker, boolean awake, boolean isDOT, L2Skill skill)
  372. {
  373. if (_commandChannelTimer == null && this.isRaid())
  374. {
  375. if (attacker != null && attacker.getParty()!= null && attacker.getParty().isInCommandChannel()&& attacker.getParty().getCommandChannel().meetRaidWarCondition(this))
  376. {
  377. _firstCommandChannelAttacked = attacker.getParty().getCommandChannel();
  378. _commandChannelTimer = new CommandChannelTimer(this, attacker.getParty().getCommandChannel());
  379. ThreadPoolManager.getInstance().scheduleGeneral(_commandChannelTimer, 300000); // 5 min
  380. _firstCommandChannelAttacked.broadcastToChannelMembers(new CreatureSay(0, Say2.PARTYROOM_ALL, "", "You have looting rights!"));
  381. }
  382. }
  383.  
  384. if (isEventMob) return;
  385.  
  386. // Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList
  387. if (attacker != null)
  388. addDamage(attacker, (int)damage, skill);
  389.  
  390. // If this L2Attackable is a L2MonsterInstance and it has spawned minions, call its minions to battle
  391. if (this instanceof L2MonsterInstance)
  392. {
  393. L2MonsterInstance master = (L2MonsterInstance) this;
  394.  
  395. if (this instanceof L2MinionInstance)
  396. {
  397. master = ((L2MinionInstance)this).getLeader();
  398.  
  399. if (master != null && !master.isInCombat() && !master.isDead())
  400. {
  401. master.addDamage(attacker, 1, null);
  402. master.callMinionsToAssist(attacker);
  403. }
  404. }
  405. else if (master.hasMinions())
  406. master.callMinionsToAssist(attacker);
  407. }
  408. // Reduce the current HP of the L2Attackable and launch the doDie Task if necessary
  409. super.reduceCurrentHp(damage, attacker, awake, isDOT, skill);
  410. }
  411.  
  412. public synchronized void setMustRewardExpSp(boolean value)
  413. {
  414. _mustGiveExpSp = value;
  415. }
  416.  
  417. public synchronized boolean getMustRewardExpSP()
  418. {
  419. return _mustGiveExpSp;
  420. }
  421.  
  422. /**
  423. * Kill the L2Attackable (the corpse disappeared after 7 seconds), distribute rewards (EXP, SP, Drops...) and notify Quest Engine.
  424. *
  425. * Actions:
  426. * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members
  427. * Notify the Quest Engine of the L2Attackable death if necessary
  428. * Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
  429. *
  430. * Caution: This method DOESN'T GIVE rewards to L2PetInstance
  431. *
  432. * @param killer The L2Character that has killed the L2Attackable
  433. */
  434. @Override
  435. public boolean doDie(L2Character killer)
  436. {
  437. // Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
  438. if (!super.doDie(killer))
  439. return false;
  440.  
  441. // Enhance soul crystals of the attacker if this L2Attackable had its soul absorbed
  442. try
  443. {
  444. levelSoulCrystals(killer);
  445. }
  446. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  447.  
  448. // Notify the Quest Engine of the L2Attackable death if necessary
  449. try
  450. {
  451. L2PcInstance player = null;
  452.  
  453. if (killer != null)
  454. player = killer.getActingPlayer();
  455.  
  456. if (player != null)
  457. {
  458. if (getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL) != null)
  459. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.ON_KILL))
  460. ThreadPoolManager.getInstance().scheduleEffect(new OnKillNotifyTask(this, quest, player, killer instanceof L2Summon), 5000);
  461. }
  462. }
  463. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  464. return true;
  465. }
  466.  
  467. class OnKillNotifyTask implements Runnable
  468. {
  469. private L2Attackable _attackable;
  470. private Quest _quest;
  471. private L2PcInstance _killer;
  472. private boolean _isPet;
  473.  
  474. public OnKillNotifyTask(L2Attackable attackable, Quest quest, L2PcInstance killer, boolean isPet)
  475. {
  476. _attackable = attackable;
  477. _quest = quest;
  478. _killer = killer;
  479. _isPet = isPet;
  480. }
  481. public void run()
  482. {
  483. _quest.notifyKill(_attackable, _killer, _isPet);
  484. }
  485. }
  486.  
  487. /**
  488. * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members.
  489. *
  490. * Actions:
  491. * Get the L2PcInstance owner of the L2SummonInstance (if necessary) and L2Party in progress
  492. * Calculate the Experience and SP rewards in function of the level difference
  493. * Add Exp and SP rewards to L2PcInstance (including Summon penalty) and to Party members in the known area of the last attacker
  494. *
  495. * Caution : This method DOESN'T GIVE rewards to L2PetInstance
  496. *
  497. * @param lastAttacker The L2Character that has killed the L2Attackable
  498. */
  499. @Override
  500. protected void calculateRewards(L2Character lastAttacker)
  501. {
  502. // Creates an empty list of rewards
  503. FastMap<L2Character, RewardInfo> rewards = new FastMap<L2Character, RewardInfo>().setShared(true);
  504. try
  505. {
  506. if (getAggroList().isEmpty())
  507. return;
  508.  
  509. // Manage Base, Quests and Sweep drops of the L2Attackable
  510. doItemDrop(lastAttacker);
  511.  
  512. // Manage drop of Special Events created by GM for a defined period
  513. doEventDrop(lastAttacker);
  514.  
  515. if (!getMustRewardExpSP())
  516. return;
  517.  
  518. int damage;
  519. L2Character attacker, ddealer;
  520. RewardInfo reward;
  521.  
  522. // While Interating over This Map Removing Object is Not Allowed
  523. synchronized (getAggroList())
  524. {
  525. // Go through the _aggroList of the L2Attackable
  526. for (AggroInfo info : getAggroList().values())
  527. {
  528. if (info == null)
  529. continue;
  530.  
  531. // Get the L2Character corresponding to this attacker
  532. attacker = info._attacker;
  533.  
  534. // Get damages done by this attacker
  535. damage = info._damage;
  536.  
  537. // Prevent unwanted behavior
  538. if (damage > 1)
  539. {
  540. if ((attacker instanceof L2SummonInstance) || ((attacker instanceof L2PetInstance) && ((L2PetInstance)attacker).getPetData().getOwnerExpTaken() > 0))
  541. ddealer = ((L2Summon)attacker).getOwner();
  542. else
  543. ddealer = info._attacker;
  544.  
  545. // Check if ddealer isn't too far from this (killed monster)
  546. if (!Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, ddealer, true))
  547. continue;
  548.  
  549. // Calculate real damages (Summoners should get own damage plus summon's damage)
  550. reward = rewards.get(ddealer);
  551.  
  552. if (reward == null)
  553. reward = new RewardInfo(ddealer, damage);
  554. else
  555. reward.addDamage(damage);
  556.  
  557. rewards.put(ddealer, reward);
  558. }
  559. }
  560. }
  561. if (!rewards.isEmpty())
  562. {
  563. L2Party attackerParty;
  564. long exp;
  565. int levelDiff, partyDmg, partyLvl, sp;
  566. float partyMul, penalty;
  567. RewardInfo reward2;
  568. int[] tmp;
  569.  
  570. for (FastMap.Entry<L2Character, RewardInfo> entry = rewards.head(), end = rewards.tail(); (entry = entry.getNext()) != end;)
  571. {
  572. if (entry == null)
  573. continue;
  574.  
  575. reward = entry.getValue();
  576.  
  577. if (reward == null)
  578. continue;
  579.  
  580. // Penalty applied to the attacker's XP
  581. penalty = 0;
  582.  
  583. // Attacker to be rewarded
  584. attacker = reward._attacker;
  585.  
  586. // Total amount of damage done
  587. damage = reward._dmg;
  588.  
  589. // If the attacker is a Pet, get the party of the owner
  590. if (attacker instanceof L2PetInstance)
  591. attackerParty = ((L2PetInstance)attacker).getParty();
  592. else if (attacker instanceof L2PcInstance)
  593. attackerParty = ((L2PcInstance)attacker).getParty();
  594. else
  595. return;
  596.  
  597. // If this attacker is a L2PcInstance with a summoned L2SummonInstance, get Exp Penalty applied for the current summoned L2SummonInstance
  598. if (attacker instanceof L2PcInstance && ((L2PcInstance)attacker).getPet() instanceof L2SummonInstance)
  599. penalty = ((L2SummonInstance)((L2PcInstance)attacker).getPet()).getExpPenalty();
  600.  
  601. // We must avoid "over damage", if any
  602. if (damage > getMaxHp())
  603. damage = getMaxHp();
  604.  
  605. // If there's NO party in progress
  606. if (attackerParty == null)
  607. {
  608. // Calculate Exp and SP rewards
  609. if (attacker.getKnownList().knowsObject(this))
  610. {
  611. // Calculate the difference of level between this attacker (L2PcInstance or L2SummonInstance owner) and the L2Attackable
  612. // mob = 24, atk = 10, diff = -14 (full xp)
  613. // mob = 24, atk = 28, diff = 4 (some xp)
  614. // mob = 24, atk = 50, diff = 26 (no xp)
  615. levelDiff = attacker.getLevel() - getLevel();
  616.  
  617. tmp = calculateExpAndSp(levelDiff, damage);
  618. exp = tmp[0];
  619. exp *= 1 - penalty;
  620. sp = tmp[1];
  621.  
  622. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  623. {
  624. exp *= Config.L2JMOD_CHAMPION_REWARDS;
  625. sp *= Config.L2JMOD_CHAMPION_REWARDS;
  626. }
  627.  
  628. // Check for an over-hit enabled strike
  629. if (attacker instanceof L2PcInstance)
  630. {
  631. L2PcInstance player = (L2PcInstance)attacker;
  632. if (isOverhit() && attacker == getOverhitAttacker())
  633. {
  634. player.sendPacket(new SystemMessage(SystemMessageId.OVER_HIT));
  635. exp += calculateOverhitExp(exp);
  636. }
  637. }
  638.  
  639. // Distribute the Exp and SP between the L2PcInstance and its L2Summon
  640. if (!attacker.isDead())
  641. {
  642. long addexp = Math.round(attacker.calcStat(Stats.EXPSP_RATE, exp, null, null));
  643. int addsp = (int)attacker.calcStat(Stats.EXPSP_RATE, sp, null, null);
  644.  
  645. if (attacker instanceof L2PcInstance)
  646. {
  647. if (((L2PcInstance)attacker).getSkillLevel(467) > 0)
  648. {
  649. L2Skill skill = SkillTable.getInstance().getInfo(467,((L2PcInstance)attacker).getSkillLevel(467));
  650.  
  651. if (skill.getExpNeeded() <= addexp)
  652. ((L2PcInstance)attacker).absorbSoul(skill,this);
  653. }
  654. ((L2PcInstance)attacker).addExpAndSp(addexp,addsp, useVitalityRate());
  655. if (addexp > 0)
  656. ((L2PcInstance)attacker).updateVitalityPoints(getVitalityPoints(damage), true, false);
  657. }
  658. else
  659. attacker.addExpAndSp(addexp,addsp);
  660. }
  661. }
  662. }
  663. else
  664. {
  665. //share with party members
  666. partyDmg = 0;
  667. partyMul = 1.f;
  668. partyLvl = 0;
  669.  
  670. // Get all L2Character that can be rewarded in the party
  671. List<L2Playable> rewardedMembers = new FastList<L2Playable>();
  672. // Go through all L2PcInstance in the party
  673. List<L2PcInstance> groupMembers;
  674.  
  675. if (attackerParty.isInCommandChannel())
  676. groupMembers = attackerParty.getCommandChannel().getMembers();
  677. else
  678. groupMembers = attackerParty.getPartyMembers();
  679.  
  680. for (L2PcInstance pl : groupMembers)
  681. {
  682. if (pl == null || pl.isDead())
  683. continue;
  684.  
  685. // Get the RewardInfo of this L2PcInstance from L2Attackable rewards
  686. reward2 = rewards.get(pl);
  687.  
  688. // If the L2PcInstance is in the L2Attackable rewards add its damages to party damages
  689. if (reward2 != null)
  690. {
  691. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, pl, true))
  692. {
  693. partyDmg += reward2._dmg; // Add L2PcInstance damages to party damages
  694. rewardedMembers.add(pl);
  695.  
  696. if (pl.getLevel() > partyLvl)
  697. {
  698. if (attackerParty.isInCommandChannel())
  699. partyLvl = attackerParty.getCommandChannel().getLevel();
  700. else
  701. partyLvl = pl.getLevel();
  702. }
  703. }
  704. rewards.remove(pl); // Remove the L2PcInstance from the L2Attackable rewards
  705. }
  706. else
  707. {
  708. // Add L2PcInstance of the party (that have attacked or not) to members that can be rewarded
  709. // and in range of the monster.
  710. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, pl, true))
  711. {
  712. rewardedMembers.add(pl);
  713. if (pl.getLevel() > partyLvl)
  714. {
  715. if (attackerParty.isInCommandChannel())
  716. partyLvl = attackerParty.getCommandChannel().getLevel();
  717. else
  718. partyLvl = pl.getLevel();
  719. }
  720. }
  721. }
  722. L2Playable summon = pl.getPet();
  723.  
  724. if (summon != null && summon instanceof L2PetInstance)
  725. {
  726. reward2 = rewards.get(summon);
  727.  
  728. if (reward2 != null) // Pets are only added if they have done damage
  729. {
  730. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, summon, true))
  731. {
  732. partyDmg += reward2._dmg; // Add summon damages to party damages
  733. rewardedMembers.add(summon);
  734.  
  735. if (summon.getLevel() > partyLvl)
  736. partyLvl = summon.getLevel();
  737. }
  738. rewards.remove(summon); // Remove the summon from the L2Attackable rewards
  739. }
  740. }
  741. }
  742.  
  743. // If the party didn't killed this L2Attackable alone
  744. if (partyDmg < getMaxHp())
  745. partyMul = ((float)partyDmg / (float)getMaxHp());
  746.  
  747. // Avoid "over damage"
  748. if (partyDmg > getMaxHp())
  749. partyDmg = getMaxHp();
  750.  
  751. // Calculate the level difference between Party and L2Attackable
  752. levelDiff = partyLvl - getLevel();
  753.  
  754. // Calculate Exp and SP rewards
  755. tmp = calculateExpAndSp(levelDiff, partyDmg);
  756. exp = tmp[0];
  757. sp = tmp[1];
  758.  
  759. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  760. {
  761. exp *= Config.L2JMOD_CHAMPION_REWARDS;
  762. sp *= Config.L2JMOD_CHAMPION_REWARDS;
  763. }
  764.  
  765. exp *= partyMul;
  766. sp *= partyMul;
  767.  
  768. // Check for an over-hit enabled strike
  769. // (When in party, the over-hit exp bonus is given to the whole party and splitted proportionally through the party members)
  770. if (attacker instanceof L2PcInstance)
  771. {
  772. L2PcInstance player = (L2PcInstance)attacker;
  773.  
  774. if (isOverhit() && attacker == getOverhitAttacker())
  775. {
  776. player.sendPacket(new SystemMessage(SystemMessageId.OVER_HIT));
  777. exp += calculateOverhitExp(exp);
  778. }
  779. }
  780. // Distribute Experience and SP rewards to L2PcInstance Party members in the known area of the last attacker
  781. if (partyDmg > 0)
  782. attackerParty.distributeXpAndSp(exp, sp, rewardedMembers, partyLvl, partyDmg, this);
  783. }
  784. }
  785. }
  786. rewards = null;
  787. }
  788. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  789. }
  790.  
  791.  
  792. /**
  793. * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.
  794. *
  795. * @param attacker The L2Character that gave damages to this L2Attackable
  796. * @param damage The number of damages given by the attacker L2Character
  797. *
  798. */
  799. public void addDamage(L2Character attacker, int damage, L2Skill skill)
  800. {
  801. // Notify the L2Attackable AI with EVT_ATTACKED
  802. if (!isDead())
  803. {
  804. try
  805. {
  806. L2PcInstance player = attacker.getActingPlayer();
  807. if (player != null)
  808. {
  809. if (getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK) !=null)
  810. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.ON_ATTACK))
  811. quest.notifyAttack(this, player, damage, attacker instanceof L2Summon, skill);
  812. }
  813. }
  814. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  815. }
  816. }
  817.  
  818. /**
  819. * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.
  820. *
  821. * @param attacker The L2Character that gave damages to this L2Attackable
  822. * @param damage The number of damages given by the attacker L2Character
  823. * @param aggro The hate (=damage) given by the attacker L2Character
  824. *
  825. */
  826. public void addDamageHate(L2Character attacker, int damage, int aggro)
  827. {
  828. if (attacker == null)
  829. return;
  830. // Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable
  831. AggroInfo ai = getAggroList().get(attacker);
  832.  
  833. if (ai == null)
  834. {
  835. ai = new AggroInfo(attacker);
  836. getAggroList().put(attacker, ai);
  837.  
  838. ai._damage = 0;
  839. ai._hate = 0;
  840. }
  841. ai._damage += damage;
  842. ai._hate += aggro;
  843.  
  844. L2PcInstance targetPlayer = attacker.getActingPlayer();
  845. if (targetPlayer != null && aggro == 0)
  846. {
  847. if (getTemplate().getEventQuests(Quest.QuestEventType.ON_AGGRO_RANGE_ENTER) !=null)
  848. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.ON_AGGRO_RANGE_ENTER))
  849. quest.notifyAggroRangeEnter(this, targetPlayer, (attacker instanceof L2Summon));
  850. }
  851.  
  852. // Set the intention to the L2Attackable to AI_INTENTION_ACTIVE
  853. if (aggro > 0 && getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)
  854. getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  855. }
  856.  
  857. public void reduceHate(L2Character target, int amount)
  858. {
  859. if (getAI() instanceof L2SiegeGuardAI || getAI() instanceof L2FortSiegeGuardAI)
  860. {
  861. // TODO: this just prevents error until siege guards are handled properly
  862. stopHating(target);
  863. setTarget(null);
  864. getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
  865. return;
  866. }
  867.  
  868. if (target == null) // whole aggrolist
  869. {
  870. L2Character mostHated = getMostHated();
  871.  
  872. if (mostHated == null) // makes target passive for a moment more
  873. {
  874. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  875. return;
  876. }
  877. else
  878. {
  879. for(L2Character aggroed : getAggroList().keySet())
  880. {
  881. AggroInfo ai = getAggroList().get(aggroed);
  882.  
  883. if (ai == null)
  884. return;
  885. ai._hate -= amount;
  886. }
  887. }
  888.  
  889. amount = getHating(mostHated);
  890.  
  891. if (amount <= 0)
  892. {
  893. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  894. clearAggroList();
  895. getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  896. setWalking();
  897. }
  898. return;
  899. }
  900. AggroInfo ai = getAggroList().get(target);
  901.  
  902. if (ai == null)
  903. return;
  904. ai._hate -= amount;
  905.  
  906. if (ai._hate <= 0)
  907. {
  908. if (getMostHated() == null)
  909. {
  910. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  911. clearAggroList();
  912. getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  913. setWalking();
  914. }
  915. }
  916. }
  917.  
  918. /**
  919. * Clears _aggroList hate of the L2Character without removing from the list.
  920. */
  921. public void stopHating(L2Character target)
  922. {
  923. if (target == null)
  924. return;
  925. AggroInfo ai = getAggroList().get(target);
  926.  
  927. if (ai == null)
  928. return;
  929. ai._hate = 0;
  930. }
  931.  
  932. /**
  933. * Return the most hated L2Character of the L2Attackable _aggroList.
  934. */
  935. public L2Character getMostHated()
  936. {
  937. if (getAggroList().isEmpty() || isAlikeDead()) return null;
  938.  
  939. L2Character mostHated = null;
  940. int maxHate = 0;
  941.  
  942. // While Interating over This Map Removing Object is Not Allowed
  943. synchronized (getAggroList())
  944. {
  945. // Go through the aggroList of the L2Attackable
  946. for (AggroInfo ai : getAggroList().values())
  947. {
  948. if (ai == null)
  949. continue;
  950.  
  951. if
  952. (
  953. ai._attacker.isAlikeDead()
  954. || !getKnownList().knowsObject(ai._attacker)
  955. || !ai._attacker.isVisible()
  956. )
  957. ai._hate = 0;
  958.  
  959. if (ai._hate > maxHate)
  960. {
  961. mostHated = ai._attacker;
  962. maxHate = ai._hate;
  963. }
  964. }
  965. }
  966. return mostHated;
  967. }
  968.  
  969. /**
  970. * Return the 2 most hated L2Character of the L2Attackable _aggroList.
  971. */
  972. public List<L2Character> get2MostHated()
  973. {
  974. if (getAggroList().isEmpty() || isAlikeDead())
  975. return null;
  976.  
  977. L2Character mostHated = null;
  978. L2Character secondMostHated = null;
  979. int maxHate = 0;
  980. List<L2Character> result = new FastList<L2Character>();
  981.  
  982. // While iterating over this map removing objects is not allowed
  983. synchronized (getAggroList())
  984. {
  985. // Go through the aggroList of the L2Attackable
  986. for (AggroInfo ai : getAggroList().values())
  987. {
  988. if (ai == null)
  989. continue;
  990.  
  991. if
  992. (
  993. ai._attacker.isAlikeDead()
  994. || !getKnownList().knowsObject(ai._attacker)
  995. || !ai._attacker.isVisible()
  996. )
  997. ai._hate = 0;
  998.  
  999. if (ai._hate > maxHate)
  1000. {
  1001. secondMostHated = mostHated;
  1002. mostHated = ai._attacker;
  1003. maxHate = ai._hate;
  1004. }
  1005. }
  1006. }
  1007. result.add(mostHated);
  1008.  
  1009. if (getAttackByList().contains(secondMostHated))
  1010. result.add(secondMostHated);
  1011. else
  1012. result.add(null);
  1013. return result;
  1014. }
  1015.  
  1016. /**
  1017. * Return the hate level of the L2Attackable against this L2Character contained in _aggroList.
  1018. *
  1019. * @param target The L2Character whose hate level must be returned
  1020. */
  1021. public int getHating(L2Character target)
  1022. {
  1023. if (getAggroList().isEmpty())
  1024. return 0;
  1025.  
  1026. AggroInfo ai = getAggroList().get(target);
  1027.  
  1028. if (ai == null)
  1029. return 0;
  1030.  
  1031. if (ai._attacker instanceof L2PcInstance && (((L2PcInstance)ai._attacker).getAppearance().getInvisible() || ai._attacker.isInvul()))
  1032. {
  1033. //Remove Object Should Use This Method and Can be Blocked While Interating
  1034. getAggroList().remove(target);
  1035. return 0;
  1036. }
  1037.  
  1038. if (!ai._attacker.isVisible())
  1039. {
  1040. getAggroList().remove(target);
  1041. return 0;
  1042. }
  1043.  
  1044. if (ai._attacker.isAlikeDead())
  1045. {
  1046. ai._hate = 0;
  1047. return 0;
  1048. }
  1049. return ai._hate;
  1050. }
  1051.  
  1052. /**
  1053. * Calculates quantity of items for specific drop acording to current situation
  1054. *
  1055. * @param drop The L2DropData count is being calculated for
  1056. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1057. * @param deepBlueDrop Factor to divide the drop chance
  1058. * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  1059. */
  1060. private RewardItem calculateRewardItem(L2PcInstance lastAttacker, L2DropData drop, int levelModifier, boolean isSweep)
  1061. {
  1062. // Get default drop chance
  1063. float dropChance = drop.getChance();
  1064.  
  1065. int deepBlueDrop = 1;
  1066.  
  1067. if ((!isRaid() && Config.DEEPBLUE_DROP_RULES)
  1068. || (isRaid() && Config.DEEPBLUE_DROP_RULES_RAID))
  1069. {
  1070. if (levelModifier > 0)
  1071. {
  1072. // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  1073. // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  1074. deepBlueDrop = 3;
  1075. if (drop.getItemId() == 57)
  1076. deepBlueDrop *= isRaid() && !isRaidMinion()? (int)Config.RATE_DROP_ITEMS_BY_RAID : (int)Config.RATE_DROP_ITEMS;
  1077. }
  1078. }
  1079.  
  1080. // Avoid dividing by 0
  1081. if (deepBlueDrop == 0)
  1082. deepBlueDrop = 1;
  1083.  
  1084. // Check if we should apply our maths so deep blue mobs will not drop that easy
  1085. if ((!isRaid() && Config.DEEPBLUE_DROP_RULES)
  1086. || (isRaid() && Config.DEEPBLUE_DROP_RULES_RAID))
  1087. dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier)/100)) / deepBlueDrop);
  1088.  
  1089. // Applies Drop rates
  1090. if (drop.getItemId() == 57)
  1091. dropChance *= Config.RATE_DROP_ADENA;
  1092. else if (isSweep)
  1093. dropChance *= Config.RATE_DROP_SPOIL;
  1094. else
  1095. dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1096.  
  1097. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  1098. dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  1099.  
  1100. // Round drop chance
  1101. dropChance = Math.round(dropChance);
  1102.  
  1103. // Set our limits for chance of drop
  1104. if (dropChance < 1)
  1105. dropChance = 1;
  1106.  
  1107. // Get min and max Item quantity that can be dropped in one time
  1108. int minCount = drop.getMinDrop();
  1109. int maxCount = drop.getMaxDrop();
  1110. int itemCount = 0;
  1111.  
  1112. // Count and chance adjustment for high rate servers
  1113. if (dropChance > L2DropData.MAX_CHANCE && !Config.PRECISE_DROP_CALCULATION)
  1114. {
  1115. int multiplier = (int)dropChance / L2DropData.MAX_CHANCE;
  1116.  
  1117. if (minCount < maxCount)
  1118. itemCount += Rnd.get(minCount * multiplier, maxCount * multiplier);
  1119. else if (minCount == maxCount)
  1120. itemCount += minCount * multiplier;
  1121. else
  1122. itemCount += multiplier;
  1123.  
  1124. dropChance = dropChance % L2DropData.MAX_CHANCE;
  1125. }
  1126. // Check if the Item must be dropped
  1127. int random = Rnd.get(L2DropData.MAX_CHANCE);
  1128. while (random < dropChance)
  1129. {
  1130. // Get the item quantity dropped
  1131. if (minCount < maxCount)
  1132. itemCount += Rnd.get(minCount, maxCount);
  1133. else if (minCount == maxCount)
  1134. itemCount += minCount;
  1135. else itemCount++;
  1136.  
  1137. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1138. dropChance -= L2DropData.MAX_CHANCE;
  1139. }
  1140. if (Config.L2JMOD_CHAMPION_ENABLE)
  1141. // TODO (April 11, 2009): Find a way not to hardcode these values.
  1142. if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion())
  1143. itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  1144.  
  1145. if (itemCount > 0)
  1146. return new RewardItem(drop.getItemId(), itemCount);
  1147. else if (itemCount == 0 && Config.DEBUG)
  1148. _log.fine("Roll produced no drops.");
  1149.  
  1150. return null;
  1151. }
  1152.  
  1153. /**
  1154. * Calculates quantity of items for specific drop CATEGORY according to current situation
  1155. * Only a max of ONE item from a category is allowed to be dropped.
  1156. *
  1157. * @param drop The L2DropData count is being calculated for
  1158. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1159. * @param deepBlueDrop Factor to divide the drop chance
  1160. * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  1161. */
  1162. private RewardItem calculateCategorizedRewardItem(L2PcInstance lastAttacker, L2DropCategory categoryDrops, int levelModifier)
  1163. {
  1164. if (categoryDrops == null)
  1165. return null;
  1166.  
  1167. // Get default drop chance for the category (that's the sum of chances for all items in the category)
  1168. // keep track of the base category chance as it'll be used later, if an item is drop from the category.
  1169. // for everything else, use the total "categoryDropChance"
  1170. int basecategoryDropChance = categoryDrops.getCategoryChance() ;
  1171. int categoryDropChance = basecategoryDropChance;
  1172.  
  1173. int deepBlueDrop = 1;
  1174.  
  1175. if ((!isRaid() && Config.DEEPBLUE_DROP_RULES)
  1176. || (isRaid() && Config.DEEPBLUE_DROP_RULES_RAID))
  1177. {
  1178. // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  1179. // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  1180. if (levelModifier > 0)
  1181. deepBlueDrop = 3;
  1182. }
  1183.  
  1184. // Avoid dividing by 0
  1185. if (deepBlueDrop == 0)
  1186. deepBlueDrop = 1;
  1187.  
  1188. // Check if we should apply our maths so deep blue mobs will not drop that easy
  1189. if ((!isRaid() && Config.DEEPBLUE_DROP_RULES)
  1190. || (isRaid() && Config.DEEPBLUE_DROP_RULES_RAID))
  1191. categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier)/100)) / deepBlueDrop);
  1192.  
  1193. // Applies Drop rates
  1194. categoryDropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1195.  
  1196. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  1197. categoryDropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  1198.  
  1199. // Round drop chance
  1200. categoryDropChance = Math.round(categoryDropChance);
  1201.  
  1202. // Set our limits for chance of drop
  1203. if (categoryDropChance < 1)
  1204. categoryDropChance = 1;
  1205.  
  1206. // Check if an Item from this category must be dropped
  1207. if (Rnd.get(L2DropData.MAX_CHANCE) < categoryDropChance)
  1208. {
  1209. L2DropData drop = categoryDrops.dropOne(isRaid() && !isRaidMinion());
  1210.  
  1211. if (drop == null)
  1212. return null;
  1213.  
  1214. // Now decide the quantity to drop based on the rates and penalties. To get this value
  1215. // simply divide the modified categoryDropChance by the base category chance. This
  1216. // results in a chance that will dictate the drops amounts: for each amount over 100
  1217. // that it is, it will give another chance to add to the min/max quantities.
  1218.  
  1219. // For example, If the final chance is 120%, then the item should drop between
  1220. // its min and max one time, and then have 20% chance to drop again. If the final
  1221. // chance is 330%, it will similarly give 3 times the min and max, and have a 30%
  1222. // chance to give a 4th time.
  1223. // At least 1 item will be dropped for sure. So the chance will be adjusted to 100%
  1224. // if smaller.
  1225.  
  1226. int dropChance = drop.getChance();
  1227.  
  1228. if (drop.getItemId() == 57)
  1229. dropChance *= Config.RATE_DROP_ADENA;
  1230. else
  1231. dropChance *= isRaid() && !isRaidMinion() ? Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS;
  1232.  
  1233. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  1234. dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  1235.  
  1236. dropChance = Math.round(dropChance);
  1237.  
  1238. if (dropChance < L2DropData.MAX_CHANCE)
  1239. dropChance = L2DropData.MAX_CHANCE;
  1240.  
  1241. // Get min and max Item quantity that can be dropped in one time
  1242. int min = drop.getMinDrop();
  1243. int max = drop.getMaxDrop();
  1244.  
  1245. // Get the item quantity dropped
  1246. int itemCount = 0;
  1247.  
  1248. // Count and chance adjustment for high rate servers
  1249. if (dropChance > L2DropData.MAX_CHANCE && !Config.PRECISE_DROP_CALCULATION)
  1250. {
  1251. int multiplier = dropChance / L2DropData.MAX_CHANCE;
  1252.  
  1253. if (min < max)
  1254. itemCount += Rnd.get(min * multiplier, max * multiplier);
  1255. else if (min == max)
  1256. itemCount += min * multiplier;
  1257. else
  1258. itemCount += multiplier;
  1259.  
  1260. dropChance = dropChance % L2DropData.MAX_CHANCE;
  1261. }
  1262.  
  1263. // Check if the Item must be dropped
  1264. int random = Rnd.get(L2DropData.MAX_CHANCE);
  1265. while (random < dropChance)
  1266. {
  1267. // Get the item quantity dropped
  1268. if (min < max)
  1269. itemCount += Rnd.get(min, max);
  1270. else if (min == max)
  1271. itemCount += min;
  1272. else
  1273. itemCount++;
  1274.  
  1275. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1276. dropChance -= L2DropData.MAX_CHANCE;
  1277. }
  1278. if (Config.L2JMOD_CHAMPION_ENABLE)
  1279. // TODO (April 11, 2009): Find a way not to hardcode these values.
  1280. if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion())
  1281. itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  1282.  
  1283. if (!Config.MULTIPLE_ITEM_DROP && !ItemTable.getInstance().getTemplate(drop.getItemId()).isStackable() && itemCount > 1)
  1284. itemCount = 1;
  1285.  
  1286. if (itemCount > 0)
  1287. return new RewardItem(drop.getItemId(), itemCount);
  1288. else if (itemCount == 0 && Config.DEBUG)
  1289. _log.fine("Roll produced no drops.");
  1290. }
  1291. return null;
  1292. }
  1293.  
  1294. /**
  1295. * Calculates the level modifier for drop
  1296. *
  1297. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1298. */
  1299. private int calculateLevelModifierForDrop(L2PcInstance lastAttacker)
  1300. {
  1301. if ((!isRaid() && Config.DEEPBLUE_DROP_RULES)
  1302. || (isRaid() && Config.DEEPBLUE_DROP_RULES_RAID))
  1303. {
  1304. int highestLevel = lastAttacker.getLevel();
  1305.  
  1306. // Check to prevent very high level player to nearly kill mob and let low level player do the last hit.
  1307. if (getAttackByList() != null && !getAttackByList().isEmpty())
  1308. {
  1309. for (L2Character atkChar: getAttackByList())
  1310. if (atkChar != null && atkChar.getLevel() > highestLevel)
  1311. highestLevel = atkChar.getLevel();
  1312. }
  1313.  
  1314. // According to official data (Prima), deep blue mobs are 9 or more levels below players
  1315. if (highestLevel - 9 >= getLevel())
  1316. return ((highestLevel - (getLevel() + 8)) * 9);
  1317. }
  1318. return 0;
  1319. }
  1320.  
  1321. public void doItemDrop(L2Character lastAttacker)
  1322. {
  1323. doItemDrop(getTemplate(),lastAttacker);
  1324. }
  1325.  
  1326. /**
  1327. * Manage Base, Quests and Special Events drops of L2Attackable (called by calculateRewards).
  1328. *
  1329. * Concept:
  1330. * During a Special Event all L2Attackable can drop extra Items.
  1331. * Those extra Items are defined in the table allNpcDateDrops of the EventDroplist.
  1332. * Each Special Event has a start and end date to stop to drop extra Items automaticaly.
  1333. *
  1334. * Actions:
  1335. * Manage drop of Special Events created by GM for a defined period
  1336. * Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops
  1337. * For each possible drops (base + quests), calculate which one must be dropped (random)
  1338. * Get each Item quantity dropped (random)
  1339. * Create this or these L2ItemInstance corresponding to each Item Identifier dropped
  1340. * If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1341. * 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
  1342. *
  1343. * @param lastAttacker The L2Character that has killed the L2Attackable
  1344. */
  1345. public void doItemDrop(L2NpcTemplate npcTemplate, L2Character lastAttacker)
  1346. {
  1347. L2PcInstance player = lastAttacker.getActingPlayer();
  1348.  
  1349. // Don't drop anything if the last attacker or owner isn't L2PcInstance
  1350. if (player == null)
  1351. return;
  1352.  
  1353. // level modifier in %'s (will be subtracted from drop chance)
  1354. int levelModifier = calculateLevelModifierForDrop(player);
  1355.  
  1356. CursedWeaponsManager.getInstance().checkDrop(this, player);
  1357.  
  1358. // now throw all categorized drops and handle spoil.
  1359. if (npcTemplate.getDropData()!=null)
  1360. {
  1361. for(L2DropCategory cat:npcTemplate.getDropData())
  1362. {
  1363. RewardItem item = null;
  1364. if (cat.isSweep())
  1365. {
  1366. // according to sh1ny, seeded mobs CAN be spoiled and swept.
  1367. if ( isSpoil()/* && !isSeeded() */)
  1368. {
  1369. FastList<RewardItem> sweepList = new FastList<RewardItem>();
  1370.  
  1371. for(L2DropData drop: cat.getAllDrops() )
  1372. {
  1373. item = calculateRewardItem(player, drop, levelModifier, true);
  1374. if (item == null)
  1375. continue;
  1376.  
  1377. if (Config.DEBUG)
  1378. _log.fine("Item id to spoil: " + item.getItemId() + " amount: " + item.getCount());
  1379. sweepList.add(item);
  1380. }
  1381. // Set the table _sweepItems of this L2Attackable
  1382. if (!sweepList.isEmpty())
  1383. _sweepItems = sweepList.toArray(new RewardItem[sweepList.size()]);
  1384. }
  1385. }
  1386. else
  1387. {
  1388. if (isSeeded())
  1389. {
  1390. L2DropData drop = cat.dropSeedAllowedDropsOnly();
  1391.  
  1392. if (drop == null)
  1393. continue;
  1394.  
  1395. item = calculateRewardItem(player, drop, levelModifier, false);
  1396. }
  1397. else
  1398. item = calculateCategorizedRewardItem(player, cat, levelModifier);
  1399.  
  1400. if (item != null)
  1401. {
  1402. if (Config.DEBUG)
  1403. _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  1404.  
  1405. // Check if the autoLoot mode is active
  1406. if (isFlying()
  1407. || (!isRaid() && Config.AUTO_LOOT)
  1408. || (isRaid() && Config.AUTO_LOOT_RAIDS))
  1409. player.doAutoLoot(this, item); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1410. else
  1411. dropItem(player, item); // drop the item on the ground
  1412.  
  1413. // Broadcast message if RaidBoss was defeated
  1414. if (isRaid() && !isRaidMinion())
  1415. {
  1416. SystemMessage sm;
  1417. sm = new SystemMessage(SystemMessageId.C1_DIED_DROPPED_S3_S2);
  1418. sm.addCharName(this);
  1419. sm.addItemName(item.getItemId());
  1420. sm.addItemNumber(item.getCount());
  1421. broadcastPacket(sm);
  1422. }
  1423. }
  1424. }
  1425. }
  1426. }
  1427. // Apply Special Item drop with random(rnd) quantity(qty) for champions.
  1428. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && (Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE > 0 || Config.L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE > 0))
  1429. {
  1430. int champqty = Rnd.get(Config.L2JMOD_CHAMPION_REWARD_QTY);
  1431. RewardItem item = new RewardItem(Config.L2JMOD_CHAMPION_REWARD_ID,++champqty);
  1432.  
  1433. if (player.getLevel() <= getLevel() && (Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD_LOWER_LVL_ITEM_CHANCE))
  1434. {
  1435. if (Config.AUTO_LOOT || isFlying())
  1436. player.addItem("ChampionLoot", item.getItemId(), item.getCount(), this, true); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1437. else
  1438. dropItem(player, item);
  1439. }
  1440. else if (player.getLevel() > getLevel() && (Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD_HIGHER_LVL_ITEM_CHANCE))
  1441. {
  1442. if (Config.AUTO_LOOT || isFlying())
  1443. player.addItem("ChampionLoot", item.getItemId(), item.getCount(), this, true); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1444. else
  1445. dropItem(player, item);
  1446. }
  1447. }
  1448.  
  1449. //Instant Item Drop :>
  1450. // TODO (April 11, 2009): Try to change herb drop to switch/case. Very ugly code right now.
  1451. if (getTemplate().dropherb)
  1452. {
  1453. boolean _hp = false;
  1454. boolean _mp = false;
  1455. boolean _spec = false;
  1456. // Herb of Warrior
  1457. int random = Rnd.get(1000);
  1458.  
  1459. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec)
  1460. {
  1461. RewardItem item = new RewardItem(8612, 1);
  1462.  
  1463. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1464. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1465. else
  1466. dropItem(player, item);
  1467. _spec = true;
  1468. }
  1469. else for (int i = 0; i < 5; i++)
  1470. {
  1471. random = Rnd.get(100);
  1472.  
  1473. if (random < Config.RATE_DROP_COMMON_HERBS)
  1474. {
  1475. RewardItem item = null;
  1476. if (i == 0) item = new RewardItem(8606, 1); // Herb of Power
  1477. if (i == 1) item = new RewardItem(8608, 1); // Herb of Atk. Spd.
  1478. if (i == 2) item = new RewardItem(8610, 1); // Herb of Critical Attack - Rate
  1479. if (i == 3) item = new RewardItem(10655, 1); // Herb of Life Force Absorption
  1480. if (i == 4) item = new RewardItem(10656, 1); // Herb of Critical Attack - Power
  1481.  
  1482. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1483. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1484. else
  1485. dropItem(player, item);
  1486. break;
  1487. }
  1488. }
  1489. // Herb of Mystic
  1490. random = Rnd.get(1000);
  1491.  
  1492. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec)
  1493. {
  1494. RewardItem item = new RewardItem(8613, 1);
  1495.  
  1496. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1497. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1498. else
  1499. dropItem(player, item);
  1500. _spec = true;
  1501. }
  1502. else for (int i = 0; i < 2; i++)
  1503. {
  1504. random = Rnd.get(100);
  1505.  
  1506. if (random < Config.RATE_DROP_COMMON_HERBS)
  1507. {
  1508. RewardItem item = null;
  1509.  
  1510. if (i == 0) item = new RewardItem(8607, 1); // Herb of Magic
  1511. if (i == 1) item = new RewardItem(8609, 1); // Herb of Casting Speed
  1512.  
  1513. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1514. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1515. else
  1516. dropItem(player, item);
  1517. break;
  1518. }
  1519. }
  1520. // Herb of Recovery
  1521. random = Rnd.get(1000);
  1522.  
  1523. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec)
  1524. {
  1525. RewardItem item = new RewardItem(8614, 1);
  1526.  
  1527. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1528. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1529. else
  1530. dropItem(player, item);
  1531. _mp = true;
  1532. _hp = true;
  1533. _spec = true;
  1534. }
  1535. // Herb of Life
  1536. if (!_hp)
  1537. {
  1538. random = Rnd.get(100);
  1539.  
  1540. if (random < Config.RATE_DROP_MP_HP_HERBS)
  1541. {
  1542. RewardItem item = new RewardItem(8600, 1);
  1543.  
  1544. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1545. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1546. else
  1547. dropItem(player, item);
  1548. _hp = true;
  1549. }
  1550. }
  1551. // Greater Herb of Life
  1552. if (!_hp)
  1553. {
  1554. random = Rnd.get(100);
  1555.  
  1556. if (random < Config.RATE_DROP_GREATER_HERBS)
  1557. {
  1558. RewardItem item = new RewardItem(8601, 1);
  1559.  
  1560. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1561. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1562. else
  1563. dropItem(player, item);
  1564. _hp = true;
  1565. }
  1566. }
  1567. // Superior Herb of Life
  1568. if (!_hp)
  1569. {
  1570. random = Rnd.get(1000);
  1571.  
  1572. if (random < Config.RATE_DROP_SUPERIOR_HERBS)
  1573. {
  1574. RewardItem item = new RewardItem(8602, 1);
  1575.  
  1576. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1577. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1578. else
  1579. dropItem(player, item);
  1580. }
  1581. }
  1582. // Herb of Mana
  1583. if (!_mp)
  1584. {
  1585. random = Rnd.get(100);
  1586.  
  1587. if (random < Config.RATE_DROP_MP_HP_HERBS)
  1588. {
  1589. RewardItem item = new RewardItem(8603, 1);
  1590.  
  1591. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1592. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1593. else
  1594. dropItem(player, item);
  1595. _mp = true;
  1596. }
  1597. }
  1598. // Greater Herb of Mana
  1599. if (!_mp)
  1600. {
  1601. random = Rnd.get(100);
  1602.  
  1603. if (random < Config.RATE_DROP_GREATER_HERBS)
  1604. {
  1605. RewardItem item = new RewardItem(8604, 1);
  1606.  
  1607. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1608. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1609. else
  1610. dropItem(player, item);
  1611. _mp = true;
  1612. }
  1613. }
  1614. // Superior Herb of Mana
  1615. if (!_mp)
  1616. {
  1617. random = Rnd.get(1000);
  1618.  
  1619. if (random < Config.RATE_DROP_SUPERIOR_HERBS)
  1620. {
  1621. RewardItem item = new RewardItem(8605, 1);
  1622.  
  1623. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1624. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1625. else
  1626. dropItem(player, item);
  1627. }
  1628. }
  1629. // speed enhance type
  1630. random = Rnd.get(100);
  1631.  
  1632. if (random < Config.RATE_DROP_COMMON_HERBS)
  1633. {
  1634. RewardItem item = new RewardItem(8611, 1); // Herb of Speed
  1635.  
  1636. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1637. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1638. else
  1639. dropItem(player, item);
  1640. }
  1641.  
  1642. // Enlarge Head type
  1643. random = Rnd.get(100);
  1644.  
  1645. if (random < Config.RATE_DROP_COMMON_HERBS)
  1646. {
  1647. RewardItem item = new RewardItem(10657, 1); // Herb of Doubt
  1648.  
  1649. if ((Config.AUTO_LOOT || isFlying()) && Config.AUTO_LOOT_HERBS)
  1650. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1651. else
  1652. dropItem(player, item);
  1653. }
  1654. // Vitality Herb
  1655. if (Config.ENABLE_VITALITY && Config.ENABLE_DROP_VITALITY_HERBS)
  1656. {
  1657. random = Rnd.get(100);
  1658. if (random < Config.RATE_DROP_VITALITY_HERBS)
  1659. {
  1660. RewardItem item = new RewardItem(13028, 1);
  1661. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS)
  1662. player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1663. else
  1664. dropItem(player, item);
  1665. }
  1666. }
  1667. }
  1668. }
  1669.  
  1670. /**
  1671. * Manage Special Events drops created by GM for a defined period.
  1672. *
  1673. * Concept:
  1674. * During a Special Event all L2Attackable can drop extra Items.
  1675. * Those extra Items are defined in the table allNpcDateDrops of the EventDroplist.
  1676. * Each Special Event has a start and end date to stop to drop extra Items automaticaly.
  1677. *
  1678. * Actions: <I>If an extra drop must be generated</I>
  1679. * Get an Item Identifier (random) from the DateDrop Item table of this Event
  1680. * Get the Item quantity dropped (random)
  1681. * Create this or these L2ItemInstance corresponding to this Item Identifier
  1682. * If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1683. * 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
  1684. *
  1685. * @param lastAttacker The L2Character that has killed the L2Attackable
  1686. */
  1687. public void doEventDrop(L2Character lastAttacker)
  1688. {
  1689. L2PcInstance player = null;
  1690.  
  1691. if (lastAttacker instanceof L2PcInstance)
  1692. player = (L2PcInstance)lastAttacker;
  1693. else if (lastAttacker instanceof L2Summon)
  1694. player = ((L2Summon)lastAttacker).getOwner();
  1695. else if (lastAttacker instanceof L2Trap)
  1696. player = ((L2Trap)lastAttacker).getOwner();
  1697.  
  1698. // Don't drop anything if the last attacker or owner isn't L2PcInstance
  1699. if (player == null)
  1700. return;
  1701.  
  1702. if (player.getLevel() - getLevel() > 9)
  1703. return;
  1704.  
  1705. // Go through DateDrop of EventDroplist allNpcDateDrops within the date range
  1706. for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
  1707. {
  1708. if (Rnd.get(L2DropData.MAX_CHANCE) < drop.chance)
  1709. {
  1710. RewardItem item = new RewardItem(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
  1711.  
  1712. if (Config.AUTO_LOOT || isFlying())
  1713. player.doAutoLoot(this, item); // Give the item(s) to the L2PcInstance that has killed the L2Attackable
  1714. else
  1715. dropItem(player, item); // drop the item on the ground
  1716. }
  1717. }
  1718. }
  1719.  
  1720. /**
  1721. * Drop reward item.
  1722. */
  1723. public L2ItemInstance dropItem(L2PcInstance lastAttacker, RewardItem item)
  1724. {
  1725. int randDropLim = 70;
  1726.  
  1727. L2ItemInstance ditem = null;
  1728. for (int i = 0; i < item.getCount(); i++)
  1729. {
  1730. // Randomize drop position
  1731. int newX = getX() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1732. int newY = getY() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1733. int newZ = Math.max(getZ(), lastAttacker.getZ()) + 20; // TODO: temp hack, do somethign nicer when we have geodatas
  1734.  
  1735. if (ItemTable.getInstance().getTemplate(item.getItemId()) != null)
  1736. {
  1737. // Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last
  1738. ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), lastAttacker, this);
  1739. ditem.dropMe(this, newX, newY, newZ);
  1740.  
  1741. // Add drop to auto destroy item task
  1742. if (!Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
  1743. {
  1744. if ((Config.AUTODESTROY_ITEM_AFTER > 0 && ditem.getItemType() != L2EtcItemType.HERB) || (Config.HERB_AUTO_DESTROY_TIME > 0 && ditem.getItemType() == L2EtcItemType.HERB))
  1745. ItemsAutoDestroy.getInstance().addItem(ditem);
  1746. }
  1747. ditem.setProtected(false);
  1748.  
  1749. // If stackable, end loop as entire count is included in 1 instance of item
  1750. if (ditem.isStackable() || !Config.MULTIPLE_ITEM_DROP)
  1751. break;
  1752. }
  1753. else
  1754. _log.log(Level.SEVERE, "Item doesn't exist so cannot be dropped. Item ID: " + item.getItemId());
  1755. }
  1756. return ditem;
  1757. }
  1758.  
  1759. public L2ItemInstance dropItem(L2PcInstance lastAttacker, int itemId, int itemCount)
  1760. {
  1761. return dropItem(lastAttacker, new RewardItem(itemId, itemCount));
  1762. }
  1763.  
  1764. /**
  1765. * Return the active weapon of this L2Attackable (= null).
  1766. */
  1767. public L2ItemInstance getActiveWeapon()
  1768. {
  1769. return null;
  1770. }
  1771.  
  1772. /**
  1773. * Return True if the _aggroList of this L2Attackable is Empty.
  1774. */
  1775. public boolean noTarget()
  1776. {
  1777. return getAggroList().isEmpty();
  1778. }
  1779.  
  1780. /**
  1781. * Return True if the _aggroList of this L2Attackable contains the L2Character.
  1782. *
  1783. * @param player The L2Character searched in the _aggroList of the L2Attackable
  1784. */
  1785. public boolean containsTarget(L2Character player)
  1786. {
  1787. return getAggroList().containsKey(player);
  1788. }
  1789.  
  1790. /**
  1791. * Clear the _aggroList of the L2Attackable.
  1792. */
  1793. public void clearAggroList()
  1794. {
  1795. getAggroList().clear();
  1796. }
  1797.  
  1798. /**
  1799. * Return True if a Dwarf use Sweep on the L2Attackable and if item can be spoiled.
  1800. */
  1801. public boolean isSweepActive()
  1802. {
  1803. return _sweepItems != null;
  1804. }
  1805.  
  1806. /**
  1807. * Return table containing all L2ItemInstance that can be spoiled.
  1808. */
  1809. public synchronized RewardItem[] takeSweep()
  1810. {
  1811. RewardItem[] sweep = _sweepItems;
  1812. _sweepItems = null;
  1813. return sweep;
  1814. }
  1815.  
  1816. /**
  1817. * Return table containing all L2ItemInstance that can be harvested.
  1818. */
  1819. public synchronized RewardItem[] takeHarvest()
  1820. {
  1821. RewardItem[] harvest = _harvestItems;
  1822. _harvestItems = null;
  1823. return harvest;
  1824. }
  1825.  
  1826. /**
  1827. * Set the over-hit flag on the L2Attackable.
  1828. *
  1829. * @param status The status of the over-hit flag
  1830. *
  1831. */
  1832. public void overhitEnabled(boolean status)
  1833. {
  1834. _overhit = status;
  1835. }
  1836.  
  1837. /**
  1838. * Set the over-hit values like the attacker who did the strike and the amount of damage done by the skill.
  1839. *
  1840. * @param attacker The L2Character who hit on the L2Attackable using the over-hit enabled skill
  1841. * @param damage The ammount of damage done by the over-hit enabled skill on the L2Attackable
  1842. *
  1843. */
  1844. public void setOverhitValues(L2Character attacker, double damage)
  1845. {
  1846. // Calculate the over-hit damage
  1847. // Ex: mob had 10 HP left, over-hit skill did 50 damage total, over-hit damage is 40
  1848. double overhitDmg = ((getCurrentHp() - damage) * (-1));
  1849. if (overhitDmg < 0)
  1850. {
  1851. // we didn't killed the mob with the over-hit strike. (it wasn't really an over-hit strike)
  1852. // let's just clear all the over-hit related values
  1853. overhitEnabled(false);
  1854. _overhitDamage = 0;
  1855. _overhitAttacker = null;
  1856. return;
  1857. }
  1858. overhitEnabled(true);
  1859. _overhitDamage = overhitDmg;
  1860. _overhitAttacker = attacker;
  1861. }
  1862.  
  1863. /**
  1864. * Return the L2Character who hit on the L2Attackable using an over-hit enabled skill.
  1865. *
  1866. * @return L2Character attacker
  1867. */
  1868. public L2Character getOverhitAttacker()
  1869. {
  1870. return _overhitAttacker;
  1871. }
  1872.  
  1873. /**
  1874. * Return the ammount of damage done on the L2Attackable using an over-hit enabled skill.
  1875. *
  1876. * @return double damage
  1877. */
  1878. public double getOverhitDamage()
  1879. {
  1880. return _overhitDamage;
  1881. }
  1882.  
  1883. /**
  1884. * Return True if the L2Attackable was hit by an over-hit enabled skill.
  1885. */
  1886. public boolean isOverhit()
  1887. {
  1888. return _overhit;
  1889. }
  1890.  
  1891. /**
  1892. * Activate the absorbed soul condition on the L2Attackable.
  1893. */
  1894. public void absorbSoul()
  1895. {
  1896. _absorbed = true;
  1897. }
  1898.  
  1899. /**
  1900. * Return True if the L2Attackable had his soul absorbed.
  1901. */
  1902. public boolean isAbsorbed()
  1903. {
  1904. return _absorbed;
  1905. }
  1906.  
  1907. /**
  1908. * Adds an attacker that successfully absorbed the soul of this L2Attackable into the _absorbersList.
  1909. *
  1910. * Params:
  1911. * attacker - a valid L2PcInstance
  1912. * condition - an integer indicating the event when mob dies. This should be:
  1913. * = 0 - "the crystal scatters";
  1914. * = 1 - "the crystal failed to absorb. nothing happens";
  1915. * = 2 - "the crystal resonates because you got more than 1 crystal on you";
  1916. * = 3 - "the crystal cannot absorb the soul because the mob level is too low";
  1917. * = 4 - "the crystal successfuly absorbed the soul";
  1918. */
  1919. public void addAbsorber(L2PcInstance attacker, int crystalId)
  1920. {
  1921. // This just works for targets like L2MonsterInstance
  1922. if (!(this instanceof L2MonsterInstance))
  1923. return;
  1924.  
  1925. // The attacker must not be null
  1926. if (attacker == null)
  1927. return;
  1928.  
  1929. // This L2Attackable must be of one type in the _absorbingMOBS_levelXX tables.
  1930. // OBS: This is done so to avoid triggering the absorbed conditions for mobs that can't be absorbed.
  1931. if (getAbsorbLevel() == 0)
  1932. return;
  1933.  
  1934. // If we have no _absorbersList initiated, do it
  1935. AbsorberInfo ai = _absorbersList.get(attacker);
  1936.  
  1937. // If the L2Character attacker isn't already in the _absorbersList of this L2Attackable, add it
  1938. if (ai == null)
  1939. {
  1940. ai = new AbsorberInfo(attacker, crystalId, getCurrentHp());
  1941. _absorbersList.put(attacker, ai);
  1942. }
  1943. else
  1944. {
  1945. ai._absorber = attacker;
  1946. ai._crystalId = crystalId;
  1947. ai._absorbedHP = getCurrentHp();
  1948. }
  1949.  
  1950. // Set this L2Attackable as absorbed
  1951. absorbSoul();
  1952. }
  1953.  
  1954. /**
  1955. * Calculate the leveling chance of Soul Crystals based on the attacker that killed this L2Attackable
  1956. *
  1957. * @param attacker The player that last killed this L2Attackable
  1958. * $ Rewrite 06.12.06 - Yesod
  1959. */
  1960. private void levelSoulCrystals(L2Character attacker)
  1961. {
  1962. // Only L2PcInstance can absorb a soul
  1963. if (!(attacker instanceof L2PcInstance) && !(attacker instanceof L2Summon))
  1964. {
  1965. resetAbsorbList(); return;
  1966. }
  1967.  
  1968. int maxAbsorbLevel = getAbsorbLevel();
  1969. int minAbsorbLevel = 0;
  1970.  
  1971. // If this is not a valid L2Attackable, clears the _absorbersList and just return
  1972. if (maxAbsorbLevel == 0)
  1973. {
  1974. resetAbsorbList(); return;
  1975. }
  1976.  
  1977. // All boss mobs with maxAbsorbLevel 13 have minAbsorbLevel of 12 else 10
  1978. if (maxAbsorbLevel > 10)
  1979. minAbsorbLevel = maxAbsorbLevel > 12 ? 12 : 10;
  1980.  
  1981. //Init some useful vars
  1982. boolean isSuccess = true;
  1983. boolean doLevelup = true;
  1984. boolean isBossMob = maxAbsorbLevel > 10 ? true : false;
  1985.  
  1986. L2NpcTemplate.AbsorbCrystalType absorbType = getTemplate().absorbType;
  1987.  
  1988. L2PcInstance killer = (attacker instanceof L2Summon)? ((L2Summon)attacker).getOwner() : (L2PcInstance)attacker;
  1989.  
  1990. // If this mob is a boss, then skip some checkings
  1991. if (!isBossMob)
  1992. {
  1993. // Fail if this L2Attackable isn't absorbed or there's no one in its _absorbersList
  1994. if (!isAbsorbed() /*|| _absorbersList == null*/)
  1995. {
  1996. resetAbsorbList();
  1997. return;
  1998. }
  1999.  
  2000. // Fail if the killer isn't in the _absorbersList of this L2Attackable and mob is not boss
  2001. AbsorberInfo ai = _absorbersList.get(killer);
  2002. if (ai == null || ai._absorber.getObjectId() != killer.getObjectId())
  2003. isSuccess = false;
  2004.  
  2005. // Check if the soul crystal was used when HP of this L2Attackable wasn't higher than half of it
  2006. if (ai != null && ai._absorbedHP > (getMaxHp()/2.0))
  2007. isSuccess = false;
  2008.  
  2009. if (!isSuccess)
  2010. {
  2011. resetAbsorbList();
  2012. return;
  2013. }
  2014. }
  2015.  
  2016. String[] crystalNFO = null;
  2017.  
  2018. int dice = Rnd.get(100);
  2019. int crystalQTY = 0;
  2020. int crystalLVL = 0;
  2021. int crystalOLD = 0;
  2022. int crystalNEW = 0;
  2023.  
  2024. // Now we have four choices:
  2025. // 1- The Monster level is too low for the crystal. Nothing happens.
  2026. // 2- Everything is correct, but it failed. Nothing happens. (57.5%)
  2027. // 3- Everything is correct, the crystal level up. A sound event is played. (32.5%)
  2028. List<L2PcInstance> players = new FastList<L2PcInstance>();
  2029.  
  2030. if (absorbType == L2NpcTemplate.AbsorbCrystalType.FULL_PARTY && killer.isInParty())
  2031. players = killer.getParty().getPartyMembers();
  2032. else if (absorbType == L2NpcTemplate.AbsorbCrystalType.PARTY_ONE_RANDOM && killer.isInParty())
  2033. {
  2034. // This is a naive method for selecting a random member. It gets any random party member and
  2035. // then checks if the member has a valid crystal. It does not select the random party member
  2036. // among those who have crystals, only. However, this might actually be correct (same as retail).
  2037. players.add(killer.getParty().getPartyMembers().get(Rnd.get(killer.getParty().getMemberCount())));
  2038. }
  2039. else
  2040. players.add(killer);
  2041.  
  2042. for (L2PcInstance player : players)
  2043. {
  2044. if (player == null)
  2045. continue;
  2046.  
  2047. QuestState st = player.getQuestState("350_EnhanceYourWeapon");
  2048.  
  2049. if (st == null)
  2050. continue;
  2051.  
  2052. if (st.getState() != State.STARTED)
  2053. continue;
  2054.  
  2055. crystalQTY = 0;
  2056.  
  2057. L2ItemInstance[] inv = player.getInventory().getItems();
  2058. for (L2ItemInstance item : inv)
  2059. {
  2060. int itemId = item.getItemId();
  2061. for (int id : SoulCrystal.SoulCrystalTable)
  2062. {
  2063. if (id == itemId)
  2064. {
  2065. // Keep count but make sure the player has no more than 1 crystal
  2066. if (++crystalQTY > 1)
  2067. {
  2068. isSuccess = false;break;
  2069. }
  2070.  
  2071. // Validate if the crystal has already leveled
  2072. if (id != SoulCrystal.RED_NEW_CRYSTAL && id != SoulCrystal.GRN_NEW_CYRSTAL && id != SoulCrystal.BLU_NEW_CRYSTAL)
  2073. {
  2074. try
  2075. {
  2076. if (item.getItem().getName().contains("Grade"))
  2077. {
  2078. // Split the name of the crystal into 'name' & 'level'
  2079. crystalNFO = item.getItem().getName().trim().replace(" Grade ", "-").split("-");
  2080. // Set Level to 13
  2081. crystalLVL = 13;
  2082. }
  2083. else
  2084. {
  2085. // Split the name of the crystal into 'name' & 'level'
  2086. crystalNFO = item.getItem().getName().trim().replace(" Stage ", "").split("-");
  2087. // Get Level
  2088. crystalLVL = Integer.parseInt(crystalNFO[1].trim());
  2089. }
  2090. // Allocate current and levelup ids' for higher level crystals
  2091. if (crystalLVL > 9)
  2092. {
  2093. for(int i = 0; i < SoulCrystal.HighSoulConvert.length; i++)
  2094. // Get the next stage above 10 using array.
  2095. if (id == SoulCrystal.HighSoulConvert[i][0])
  2096. {
  2097. crystalNEW = SoulCrystal.HighSoulConvert[i][1]; break;
  2098. }
  2099. }
  2100. else
  2101. crystalNEW = id+1;
  2102. }
  2103. catch (NumberFormatException nfe)
  2104. {
  2105. _log.log(Level.WARNING, "An attempt to identify a soul crystal failed, verify the names have not changed in etcitem table.", nfe);
  2106. player.sendMessage("There has been an error handling your soul crystal. Please notify your server admin.");
  2107. isSuccess = false;
  2108. break;
  2109. }
  2110. catch (Exception e) { e.printStackTrace(); isSuccess = false; break; }
  2111. }
  2112. else
  2113. crystalNEW = id+1;
  2114.  
  2115. // Done
  2116. crystalOLD = id;
  2117. break;
  2118. }
  2119. }
  2120. if (!isSuccess)
  2121. break;
  2122. }
  2123.  
  2124. // If the crystal level is way too high for this mob, say that we can't increase it
  2125. if ((crystalLVL < minAbsorbLevel) || (crystalLVL >= maxAbsorbLevel))
  2126. doLevelup = false;
  2127.  
  2128. // The player doesn't have any crystals with him get to the next player.
  2129. if (crystalQTY < 1 || crystalQTY > 1 || !isSuccess || !doLevelup)
  2130. {
  2131. // Too many crystals in inventory.
  2132. if (crystalQTY > 1)
  2133. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_FAILED_RESONATION));
  2134.  
  2135. // The soul crystal stage of the player is way too high
  2136. else if (!doLevelup && crystalQTY > 0)
  2137. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_REFUSED));
  2138.  
  2139. crystalQTY = 0;
  2140. continue;
  2141. }
  2142.  
  2143. /* TODO: Confirm boss chance for crystal level up and for crystal breaking.
  2144. * It is known that bosses with FULL_PARTY crystal level ups have 100% success rate, but this is not
  2145. * the case for the other bosses (one-random or last-hit).
  2146. * While not confirmed, it is most reasonable that crystals leveled up at bosses will never break.
  2147. * Also, the chance to level up is guessed as around 70% if not higher.
  2148. */
  2149. int chanceLevelUp = isBossMob? 70:SoulCrystal.LEVEL_CHANCE;
  2150.  
  2151. // If succeeds or it is a full party absorb, level up the crystal.
  2152. if (((absorbType == L2NpcTemplate.AbsorbCrystalType.FULL_PARTY) && doLevelup) || (dice <= chanceLevelUp))
  2153. exchangeCrystal(player, crystalOLD, crystalNEW, false);
  2154.  
  2155. else
  2156. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_FAILED));
  2157. }
  2158. }
  2159.  
  2160. private void exchangeCrystal(L2PcInstance player, int takeid, int giveid, boolean broke)
  2161. {
  2162. L2ItemInstance Item = player.getInventory().destroyItemByItemId("SoulCrystal", takeid, 1, player, this);
  2163.  
  2164. if (Item != null)
  2165. {
  2166. // Prepare inventory update packet
  2167. InventoryUpdate playerIU = new InventoryUpdate();
  2168. playerIU.addRemovedItem(Item);
  2169.  
  2170. // Add new crystal to the killer's inventory
  2171. Item = player.getInventory().addItem("SoulCrystal", giveid, 1, player, this);
  2172. playerIU.addItem(Item);
  2173.  
  2174. // Send a sound event and text message to the player
  2175. if (broke)
  2176. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_BROKE));
  2177.  
  2178. else
  2179. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_SUCCEEDED));
  2180.  
  2181. // Send system message
  2182. SystemMessage sms = new SystemMessage(SystemMessageId.EARNED_ITEM);
  2183. sms.addItemName(giveid);
  2184. player.sendPacket(sms);
  2185.  
  2186. // Send inventory update packet
  2187. player.sendPacket(playerIU);
  2188. }
  2189. }
  2190.  
  2191. private void resetAbsorbList()
  2192. {
  2193. _absorbed = false;
  2194. _absorbersList.clear();
  2195. }
  2196.  
  2197. /**
  2198. * Calculate the Experience and SP to distribute to attacker (L2PcInstance, L2SummonInstance or L2Party) of the L2Attackable.
  2199. *
  2200. * @param diff The difference of level between attacker (L2PcInstance, L2SummonInstance or L2Party) and the L2Attackable
  2201. * @param damage The damages given by the attacker (L2PcInstance, L2SummonInstance or L2Party)
  2202. *
  2203. */
  2204. private int[] calculateExpAndSp(int diff, int damage)
  2205. {
  2206. double xp;
  2207. double sp;
  2208.  
  2209. if (diff < -5)
  2210. diff = -5; // makes possible to use ALT_GAME_EXPONENT configuration
  2211.  
  2212. xp = (double)getExpReward() * damage / getMaxHp();
  2213. if (Config.ALT_GAME_EXPONENT_XP != 0)
  2214. xp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_XP);
  2215.  
  2216. sp = (double)getSpReward() * damage / getMaxHp();
  2217. if (Config.ALT_GAME_EXPONENT_SP != 0)
  2218. sp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_SP);
  2219.  
  2220. if (Config.ALT_GAME_EXPONENT_XP == 0 && Config.ALT_GAME_EXPONENT_SP == 0)
  2221. {
  2222. if (diff > 5) // formula revised May 07
  2223. {
  2224. double pow = Math.pow((double)5/6, diff-5);
  2225. xp = xp*pow;
  2226. sp = sp*pow;
  2227. }
  2228.  
  2229. if (xp <= 0)
  2230. {
  2231. xp = 0;
  2232. sp = 0;
  2233. }
  2234. else if (sp <= 0)
  2235. sp = 0;
  2236. }
  2237. int[] tmp = { (int)xp, (int)sp };
  2238. return tmp;
  2239. }
  2240.  
  2241. public long calculateOverhitExp(long normalExp)
  2242. {
  2243. // Get the percentage based on the total of extra (over-hit) damage done relative to the total (maximum) ammount of HP on the L2Attackable
  2244. double overhitPercentage = ((getOverhitDamage() * 100) / getMaxHp());
  2245.  
  2246. // Over-hit damage percentages are limited to 25% max
  2247. if (overhitPercentage > 25)
  2248. overhitPercentage = 25;
  2249.  
  2250. // Get the overhit exp bonus according to the above over-hit damage percentage
  2251. // (1/1 basis - 13% of over-hit damage, 13% of extra exp is given, and so on...)
  2252. double overhitExp = ((overhitPercentage / 100) * normalExp);
  2253.  
  2254. // Return the rounded ammount of exp points to be added to the player's normal exp reward
  2255. long bonusOverhit = Math.round(overhitExp);
  2256. return bonusOverhit;
  2257. }
  2258.  
  2259. /**
  2260. * Return True.
  2261. */
  2262. @Override
  2263. public boolean isAttackable()
  2264. {
  2265. return true;
  2266. }
  2267.  
  2268. @Override
  2269. public void onSpawn()
  2270. {
  2271. setChampion(false);
  2272. if (Config.L2JMOD_CHAMPION_ENABLE)
  2273. {
  2274. // Set champion on next spawn
  2275. if
  2276. (
  2277. this instanceof L2MonsterInstance
  2278. && !getTemplate().isQuestMonster
  2279. && !this.isRaid()
  2280. && !this.isRaidMinion()
  2281. && Config.L2JMOD_CHAMPION_FREQUENCY > 0
  2282. && getLevel()>=Config.L2JMOD_CHAMP_MIN_LVL
  2283. && getLevel()<=Config.L2JMOD_CHAMP_MAX_LVL
  2284. )
  2285. {
  2286. int random = Rnd.get(100);
  2287.  
  2288. if (random < Config.L2JMOD_CHAMPION_FREQUENCY)
  2289. setChampion(true);
  2290. }
  2291. }
  2292. super.onSpawn();
  2293. // Clear mob spoil, seed
  2294. setSpoil(false);
  2295. // Clear all aggro char from list
  2296. clearAggroList();
  2297. // Clear Harvester Rewrard List
  2298. _harvestItems = null;
  2299. // Clear mod Seeded stat
  2300. setSeeded(false);
  2301.  
  2302. _sweepItems = null;
  2303. resetAbsorbList();
  2304.  
  2305. setWalking();
  2306.  
  2307. // check the region where this mob is, do not activate the AI if region is inactive.
  2308. if (!isInActiveRegion())
  2309. {
  2310. if (this instanceof L2SiegeGuardInstance)
  2311. ((L2SiegeGuardAI) getAI()).stopAITask();
  2312. else if (this instanceof L2FortSiegeGuardInstance)
  2313. ((L2FortSiegeGuardAI) getAI()).stopAITask();
  2314. else
  2315. ((L2AttackableAI) getAI()).stopAITask();
  2316. }
  2317. }
  2318.  
  2319. /**
  2320. * Sets state of the mob to seeded. Paramets needed to be set before.
  2321. */
  2322. public void setSeeded()
  2323. {
  2324. if (_seedType != 0 && _seeder != null)
  2325. setSeeded(_seedType, _seeder.getLevel());
  2326. }
  2327.  
  2328. /**
  2329. * Sets the seed parametrs, but not the seed state
  2330. * @param id - id of the seed
  2331. * @param seeder - player who is sowind the seed
  2332. */
  2333. public void setSeeded(int id, L2PcInstance seeder)
  2334. {
  2335. if (!_seeded)
  2336. {
  2337. _seedType = id;
  2338. _seeder = seeder;
  2339. }
  2340. }
  2341.  
  2342. public void setSeeded(int id, int seederLvl)
  2343. {
  2344. _seeded = true;
  2345. _seedType = id;
  2346. int count = 1;
  2347.  
  2348. Map<Integer, L2Skill> skills = getTemplate().getSkills();
  2349.  
  2350. if (skills != null)
  2351. {
  2352. for (int skillId : skills.keySet())
  2353. {
  2354. switch (skillId)
  2355. {
  2356. case 4303: //Strong type x2
  2357. count *= 2;
  2358. break;
  2359. case 4304: //Strong type x3
  2360. count *= 3;
  2361. break;
  2362. case 4305: //Strong type x4
  2363. count *= 4;
  2364. break;
  2365. case 4306: //Strong type x5
  2366. count *= 5;
  2367. break;
  2368. case 4307: //Strong type x6
  2369. count *= 6;
  2370. break;
  2371. case 4308: //Strong type x7
  2372. count *= 7;
  2373. break;
  2374. case 4309: //Strong type x8
  2375. count *= 8;
  2376. break;
  2377. case 4310: //Strong type x9
  2378. count *= 9;
  2379. break;
  2380. }
  2381. }
  2382. }
  2383.  
  2384. int diff = (getLevel() - (L2Manor.getInstance().getSeedLevel(_seedType) - 5));
  2385.  
  2386. // hi-lvl mobs bonus
  2387. if (diff > 0)
  2388. count += diff;
  2389.  
  2390. FastList<RewardItem> harvested = new FastList<RewardItem>();
  2391.  
  2392. harvested.add(new RewardItem(L2Manor.getInstance().getCropType(_seedType), count* Config.RATE_DROP_MANOR));
  2393.  
  2394. _harvestItems = harvested.toArray(new RewardItem[harvested.size()]);
  2395. }
  2396.  
  2397. public void setSeeded(boolean seeded)
  2398. {
  2399. _seeded = seeded;
  2400. }
  2401.  
  2402. public L2PcInstance getSeeder()
  2403. {
  2404. return _seeder;
  2405. }
  2406.  
  2407. public int getSeedType()
  2408. {
  2409. return _seedType;
  2410. }
  2411.  
  2412. public boolean isSeeded()
  2413. {
  2414. return _seeded;
  2415. }
  2416.  
  2417. private int getAbsorbLevel()
  2418. {
  2419. return getTemplate().absorbLevel;
  2420. }
  2421.  
  2422. /**
  2423. * Check if the server allows Random Animation.
  2424. */
  2425. // This is located here because L2Monster and L2FriendlyMob both extend this class. The other non-pc instances extend either L2NpcInstance or L2MonsterInstance.
  2426. @Override
  2427. public boolean hasRandomAnimation()
  2428. {
  2429. return ((Config.MAX_MONSTER_ANIMATION > 0) && !(this instanceof L2GrandBossInstance));
  2430. }
  2431.  
  2432. @Override
  2433. public boolean isMob()
  2434. {
  2435. return true; // This means we use MAX_MONSTER_ANIMATION instead of MAX_NPC_ANIMATION
  2436. }
  2437.  
  2438. protected void setCommandChannelTimer(CommandChannelTimer commandChannelTimer)
  2439. {
  2440. _commandChannelTimer = commandChannelTimer;
  2441. }
  2442.  
  2443. public CommandChannelTimer getCommandChannelTimer()
  2444. {
  2445. return _commandChannelTimer;
  2446. }
  2447.  
  2448. public L2CommandChannel getFirstCommandChannelAttacked()
  2449. {
  2450. return _firstCommandChannelAttacked;
  2451. }
  2452.  
  2453. public void setFirstCommandChannelAttacked(L2CommandChannel firstCommandChannelAttacked)
  2454. {
  2455. _firstCommandChannelAttacked = firstCommandChannelAttacked;
  2456. }
  2457.  
  2458. private class CommandChannelTimer implements Runnable
  2459. {
  2460. private L2Attackable _monster;
  2461. private L2CommandChannel _channel;
  2462.  
  2463. public CommandChannelTimer(L2Attackable monster, L2CommandChannel channel)
  2464. {
  2465. _monster = monster;
  2466. _channel = channel;
  2467. }
  2468.  
  2469. /**
  2470. * @see java.lang.Runnable#run()
  2471. */
  2472. public void run()
  2473. {
  2474. _monster.setCommandChannelTimer(null);
  2475. _monster.setFirstCommandChannelAttacked(null);
  2476. for (L2Character player : _monster.getAggroList().keySet())
  2477. {
  2478. if (player.isInParty() && player.getParty().isInCommandChannel())
  2479. {
  2480. if (player.getParty().getCommandChannel().equals(_channel))
  2481. {
  2482. // if a player which is in first attacked CommandChannel, restart the timer ;)
  2483. _monster.setCommandChannelTimer(this);
  2484. _monster.setFirstCommandChannelAttacked(_channel);
  2485. ThreadPoolManager.getInstance().scheduleGeneral(this, 300000); // 5 min
  2486. break;
  2487. }
  2488. }
  2489. }
  2490. }
  2491. }
  2492.  
  2493. public void returnHome()
  2494. {
  2495. clearAggroList();
  2496.  
  2497. if (hasAI() && getSpawn() != null)
  2498. getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(getSpawn().getLocx(), getSpawn().getLocy(), getSpawn().getLocz(), 0));
  2499. }
  2500.  
  2501. /*
  2502. * Return vitality points decrease (if positive)
  2503. * or increase (if negative) based on damage.
  2504. * Maximum for damage = maxHp.
  2505. */
  2506. public float getVitalityPoints(int damage)
  2507. {
  2508. // sanity check
  2509. if (damage <= 0)
  2510. return 0;
  2511.  
  2512. final float divider = getTemplate().baseVitalityDivider;
  2513. if (divider == 0)
  2514. return 0;
  2515.  
  2516. // negative value - vitality will be consumed
  2517. return - Math.min(damage, getMaxHp()) / divider;
  2518. }
  2519.  
  2520. /*
  2521. * True if vitality rate for exp and sp should be applied
  2522. */
  2523. public boolean useVitalityRate()
  2524. {
  2525. if (isChampion() && !Config.L2JMOD_CHAMPION_ENABLE_VITALITY)
  2526. return false;
  2527.  
  2528. return true;
  2529. }
  2530. }
Advertisement
Add Comment
Please, Sign In to add comment