Advertisement
iliqbg

dropsystem

Mar 11th, 2013
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 339.44 KB | None | 0 0
  1. ### Eclipse Workspace Patch 1.0
  2. #P Lisvus_GameServer
  3. Index: java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java
  4. ===================================================================
  5. --- java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java   (revision 355)
  6. +++ java/net/sf/l2j/gameserver/script/faenor/FaenorInterface.java   (working copy)
  7. @@ -26,6 +26,7 @@
  8.  import net.sf.l2j.gameserver.Announcements;
  9.  import net.sf.l2j.gameserver.EventDroplist;
  10.  import net.sf.l2j.gameserver.model.L2DropData;
  11. +import net.sf.l2j.gameserver.model.L2DropCategory;
  12.  import net.sf.l2j.gameserver.model.L2PetData;
  13.  import net.sf.l2j.gameserver.script.DateRange;
  14.  import net.sf.l2j.gameserver.script.EngineInterface;
  15. @@ -87,7 +88,7 @@
  16.          drop.setChance(chance);
  17.          drop.setQuestID(questID);
  18.          drop.addStates(states);
  19. -        npc.addDropData(drop);
  20. +        addDrop(npc, drop, false);
  21.      }
  22.  
  23.      /**
  24. @@ -108,11 +109,52 @@
  25.          drop.setItemId(itemID);
  26.          drop.setMinDrop(min);
  27.          drop.setMaxDrop(max);
  28. -        drop.setSweep(sweep);
  29.          drop.setChance(chance);
  30. -        npc.addDropData(drop);
  31. +
  32. +        addDrop(npc, drop, sweep);
  33.      }
  34. +    
  35. +   /**
  36. +    * Adds a new drop to an NPC.  If the drop is sweep, it adds it to the NPC's Sweep category
  37. +    * If the drop is non-sweep, it creates a new category for this drop.
  38. +    *  
  39. +    * @param npc
  40. +    * @param drop
  41. +    * @param sweep
  42. +    */
  43. +    public void addDrop(L2NpcTemplate npc, L2DropData drop, boolean sweep)
  44. +    {
  45. +       if(sweep)
  46. +           addDrop(npc, drop,-1);
  47. +       else
  48. +       {
  49. +           int maxCategory = -1;
  50.  
  51. +           for(L2DropCategory cat:npc.getDropData())
  52. +           {
  53. +               if(maxCategory<cat.getCategoryType())
  54. +                   maxCategory = cat.getCategoryType();
  55. +           }
  56. +           maxCategory++;
  57. +           npc.addDropData(drop, maxCategory);
  58. +       }
  59. +
  60. +    }
  61. +
  62. +   /**
  63. +    * Adds a new drop to an NPC, in the specified category.  If the category does not exist,
  64. +    * it is created.  
  65. +    *  
  66. +    * @param npc
  67. +    * @param drop
  68. +    * @param sweep
  69. +    */
  70. +    public void addDrop(L2NpcTemplate npc, L2DropData drop, int category)
  71. +    {
  72. +       npc.addDropData(drop, category);
  73. +    }
  74. +
  75. +
  76.      /**
  77.       * @return Returns the _questDrops.
  78.       */
  79. @@ -124,7 +166,8 @@
  80.              return null;
  81.          }
  82.          List<L2DropData> questDrops = new FastList<L2DropData>();
  83. -        for (L2DropData drop : npc.getDropData())
  84. +        for (L2DropCategory cat:npc.getDropData())
  85. +        for (L2DropData drop : cat.getAllDrops() )
  86.          {
  87.              if (drop.getQuestID() != null)
  88.              {
  89. Index: java/net/sf/l2j/gameserver/model/L2DropData.java
  90. ===================================================================
  91. --- java/net/sf/l2j/gameserver/model/L2DropData.java    (revision 355)
  92. +++ java/net/sf/l2j/gameserver/model/L2DropData.java    (working copy)
  93. @@ -35,7 +35,6 @@
  94.     private int _itemId;
  95.     private int _mindrop;
  96.     private int _maxdrop;
  97. -   private boolean _sweep;
  98.     private int _chance;
  99.      private String _questID = null;
  100.      private String[] _stateID = null;
  101. @@ -77,15 +76,6 @@
  102.     }
  103.    
  104.     /**
  105. -    * Returns if item dropped come from sweep
  106. -    * @return boolean
  107. -    */
  108. -   public boolean isSweep()
  109. -   {
  110. -       return _sweep;
  111. -   }
  112. -  
  113. -   /**
  114.      * Returns the chance of having a drop
  115.      * @return int
  116.      */
  117. @@ -113,15 +103,6 @@
  118.     }
  119.    
  120.     /**
  121. -    * Sets if the item come from sweep
  122. -    * @param sweep
  123. -    */
  124. -   public void setSweep(boolean sweep)
  125. -   {
  126. -       _sweep = sweep;
  127. -   }
  128. -  
  129. -   /**
  130.      * Sets the chance of having the item for a drop
  131.      * @param chance : int designating the chance
  132.      */
  133. Index: java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java
  134. ===================================================================
  135. --- java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java (revision 355)
  136. +++ java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java (working copy)
  137. @@ -24,6 +24,7 @@
  138.  
  139.  import javolution.util.FastList;
  140.  import javolution.util.FastMap;
  141. +import net.sf.l2j.gameserver.model.L2DropCategory;
  142.  import net.sf.l2j.gameserver.model.L2DropData;
  143.  import net.sf.l2j.gameserver.model.L2MinionData;
  144.  import net.sf.l2j.gameserver.model.L2Skill;
  145. @@ -32,309 +33,315 @@
  146.  import net.sf.l2j.gameserver.skills.Stats;
  147.  
  148.  /**
  149. - * This cl contains all generic data of a L2Spawn object.<BR><BR>
  150. - *
  151. - * <B><U> Data</U> :</B><BR><BR>
  152. - * <li>npcId, type, name, sex</li>
  153. - * <li>rewardExp, rewardSp</li>
  154. - * <li>aggroRange, factionId, factionRange</li>
  155. - * <li>rhand, lhand, armor</li>
  156. - * <li>isUndead</li>
  157. - * <li>_drops</li>
  158. - * <li>_minions</li>
  159. - * <li>_teachInfo</li>
  160. - * <li>_skills</li>
  161. - * <li>_questsStart</li><BR><BR>
  162. - *
  163. + * This cl contains all generic data of a L2Spawn object.<BR>
  164. + * <BR>
  165. + * <B><U> Data</U> :</B><BR>
  166. + * <BR>
  167. + * <li>npcId, type, name, sex</li> <li>rewardExp, rewardSp</li> <li>aggroRange, factionId, factionRange</li> <li>rhand, lhand, armor</li> <li>isUndead</li> <li>_drops</li> <li>_minions</li> <li>_teachInfo</li> <li>_skills</li> <li>_questsStart</li><BR>
  168. + * <BR>
  169.   * @version $Revision: 1.1.2.4 $ $Date: 2005/04/02 15:57:51 $
  170.   */
  171.  public final class L2NpcTemplate extends L2CharTemplate
  172.  {
  173. -        protected static Logger _log = Logger.getLogger(Quest.class.getName());
  174. -
  175. -   public final int     npcId;
  176. -        public final int     idTemplate;
  177. -   public final String  type;
  178. -   public final String  name;
  179. -        public final boolean serverSideName;
  180. -        public final String  title;
  181. -        public final boolean serverSideTitle;
  182. -   public final String  sex;
  183. -   public final int     level;
  184. -   public final int     rewardExp;
  185. -   public final int     rewardSp;
  186. -   public final int     aggroRange;
  187. -   public final int     rhand;
  188. -   public final int     lhand;
  189. -   public final int     armor;
  190. -   public final String  factionId;
  191. -   public final int     factionRange;
  192. -        public final int     absorb_level;
  193. -
  194. +   protected static Logger _log = Logger.getLogger(Quest.class.getName());
  195. +  
  196. +   public final int npcId;
  197. +   public final int idTemplate;
  198. +   public final String type;
  199. +   public final String name;
  200. +   public final boolean serverSideName;
  201. +   public final String title;
  202. +   public final boolean serverSideTitle;
  203. +   public final String sex;
  204. +   public final int level;
  205. +   public final int rewardExp;
  206. +   public final int rewardSp;
  207. +   public final int aggroRange;
  208. +   public final int rhand;
  209. +   public final int lhand;
  210. +   public final int armor;
  211. +   public final String factionId;
  212. +   public final int factionRange;
  213. +   public final int absorb_level;
  214. +  
  215.     private final StatsSet npcStatsSet;
  216. -
  217. -   /** fixed skills*/
  218. -   public int     race;
  219. -
  220. -   /** The table containing all Item that can be dropped by L2NpcInstance using this L2NpcTemplate*/
  221. -   private final List<L2DropData>    _drops       = new FastList<L2DropData>(0);
  222. -   private final List<L2DropData>    _fulldrops       = new FastList<L2DropData>(0);
  223. -   private final List<L2DropData>    _miscdrops       = new FastList<L2DropData>(0);
  224. -
  225. -   /** The table containing all Minions that must be spawn with the L2NpcInstance using this L2NpcTemplate*/
  226. -   private final List<L2MinionData>  _minions     = new FastList<L2MinionData>(0);
  227. -
  228. -   private List<ClassId>             _teachInfo;
  229. +  
  230. +   /** fixed skills */
  231. +   public int race;
  232. +  
  233. +   /** The table containing all Item that can be dropped by L2NpcInstance using this L2NpcTemplate */
  234. +   private final FastList<L2DropCategory> _categories = new FastList<L2DropCategory>();
  235. +  
  236. +   /** The table containing all Minions that must be spawn with the L2NpcInstance using this L2NpcTemplate */
  237. +   private final List<L2MinionData> _minions = new FastList<L2MinionData>(0);
  238. +  
  239. +   private List<ClassId> _teachInfo;
  240.     private Map<Integer, L2Skill> _skills;
  241.     private Map<Stats, Double> _vulnerabilities;
  242.     // contains a list of quests for each event type (questStart, questAttack, questKill, etc)
  243. -        private Map<Quest.QuestEventType, Quest[]> _questEvents;
  244. -
  245. +   private Map<Quest.QuestEventType, Quest[]> _questEvents;
  246. +  
  247.     /**
  248. -    * Constructor of L2Character.<BR><BR>
  249. -    *
  250. +    * Constructor of L2Character.<BR>
  251. +    * <BR>
  252.      * @param set The StatsSet object to transfert data to the method
  253. -    *
  254.      */
  255.     public L2NpcTemplate(StatsSet set)
  256.     {
  257.         super(set);
  258. -       npcId     = set.getInteger("npcId");
  259. -                idTemplate = set.getInteger("idTemplate");
  260. -       type      = set.getString("type");
  261. -       name      = set.getString("name");
  262. -                serverSideName = set.getBool("serverSideName");
  263. -                title     = set.getString("title");
  264. -                serverSideTitle = set.getBool("serverSideTitle");
  265. -       sex       = set.getString("sex");
  266. -       level     = set.getInteger("level");
  267. +       npcId = set.getInteger("npcId");
  268. +       idTemplate = set.getInteger("idTemplate");
  269. +       type = set.getString("type");
  270. +       name = set.getString("name");
  271. +       serverSideName = set.getBool("serverSideName");
  272. +       title = set.getString("title");
  273. +       serverSideTitle = set.getBool("serverSideTitle");
  274. +       sex = set.getString("sex");
  275. +       level = set.getInteger("level");
  276.         rewardExp = set.getInteger("rewardExp");
  277. -       rewardSp  = set.getInteger("rewardSp");
  278. -       aggroRange= set.getInteger("aggroRange");
  279. -       rhand     = set.getInteger("rhand");
  280. -       lhand     = set.getInteger("lhand");
  281. -       armor     = set.getInteger("armor");
  282. -       String f  = set.getString("factionId", null);
  283. +       rewardSp = set.getInteger("rewardSp");
  284. +       aggroRange = set.getInteger("aggroRange");
  285. +       rhand = set.getInteger("rhand");
  286. +       lhand = set.getInteger("lhand");
  287. +       armor = set.getInteger("armor");
  288. +       String f = set.getString("factionId", null);
  289.         if (f == null)
  290. +       {
  291.             factionId = null;
  292. +       }
  293.         else
  294. +       {
  295.             factionId = f.intern();
  296. -       factionRange  = set.getInteger("factionRange");
  297. -                absorb_level  = set.getInteger("absorb_level", 0);
  298. -       //String r = set.getString("race", null);
  299. -       //if (r == null)
  300. -       //  race = null;
  301. -       //else
  302. -       //  race = r.intern();
  303. +       }
  304. +       factionRange = set.getInteger("factionRange");
  305. +       absorb_level = set.getInteger("absorb_level", 0);
  306. +       // String r = set.getString("race", null);
  307. +       // if (r == null)
  308. +       // race = null;
  309. +       // else
  310. +       // race = r.intern();
  311.         race = 0;
  312.         npcStatsSet = set;
  313.         _teachInfo = null;
  314.     }
  315. -
  316. -        public void addTeachInfo(ClassId classId)
  317. +  
  318. +   public void addTeachInfo(ClassId classId)
  319.     {
  320.         if (_teachInfo == null)
  321. +       {
  322.             _teachInfo = new FastList<ClassId>();
  323. +       }
  324.         _teachInfo.add(classId);
  325.     }
  326. -
  327. +  
  328.     public ClassId[] getTeachInfo()
  329.     {
  330.         if (_teachInfo == null)
  331. +       {
  332.             return null;
  333. +       }
  334.         return _teachInfo.toArray(new ClassId[_teachInfo.size()]);
  335.     }
  336. -
  337. +  
  338.     public boolean canTeach(ClassId classId)
  339.     {
  340.         if (_teachInfo == null)
  341. +       {
  342.             return false;
  343. -
  344. -        // If the player is on a third class, fetch the class teacher
  345. -        // information for its parent class.
  346. -        if (classId.getId() >= 88)
  347. -            return _teachInfo.contains(classId.getParent());
  348. -
  349. +       }
  350. +      
  351. +       // If the player is on a third class, fetch the class teacher
  352. +       // information for its parent class.
  353. +       if (classId.getId() >= 88)
  354. +       {
  355. +           return _teachInfo.contains(classId.getParent());
  356. +       }
  357. +      
  358.         return _teachInfo.contains(classId);
  359.     }
  360. -
  361. -   // for all spoil, plus adena, sealstone, quest, Raidboss, and all other drops that
  362. -   // should NOT follow the rule of 1 drop per category per kill
  363. -        public void addDropData(L2DropData drop)
  364. +  
  365. +   // add a drop to a given category. If the category does not exist, create it.
  366. +   public void addDropData(L2DropData drop, int categoryType)
  367.     {
  368. -       if (drop.isQuestDrop()) {
  369. -//         if (_questDrops == null)
  370. -//             _questDrops = new FastList<L2DropData>(0);
  371. -//         _questDrops.add(drop);
  372. -       } else {
  373. -           _drops.add(drop);
  374. -       }
  375. +       if (drop.isQuestDrop())
  376. +       {
  377. +           // if (_questDrops == null)
  378. +           // _questDrops = new FastList<L2DropData>(0);
  379. +           // _questDrops.add(drop);
  380. +       }
  381. +       else
  382. +       {
  383. +           // if the category doesn't already exist, create it first
  384. +           synchronized (_categories)
  385. +           {
  386. +               boolean catExists = false;
  387. +               for (L2DropCategory cat : _categories)
  388. +               {
  389. +                   // if the category exists, add the drop to this category.
  390. +                   if (cat.getCategoryType() == categoryType)
  391. +                   {
  392. +                       cat.addDropData(drop);
  393. +                       catExists = true;
  394. +                       break;
  395. +                   }
  396. +               }
  397. +               // if the category doesn't exit, create it and add the drop
  398. +               if (!catExists)
  399. +               {
  400. +                   L2DropCategory cat = new L2DropCategory(categoryType);
  401. +                   cat.addDropData(drop);
  402. +                   _categories.add(cat);
  403. +               }
  404. +           }
  405. +       }
  406.     }
  407. -
  408. -        // for the first category: Full drops and parts (like fabrics, patterns, edges, etc)
  409. -        // only ONE of all items in this catgory should be dropped per kill .
  410. -        public void addFullDropData(L2DropData drop)
  411. +  
  412. +   public void addRaidData(L2MinionData minion)
  413.     {
  414. -       if (drop.isQuestDrop()) {
  415. -//         should never happen here
  416. -       } else {
  417. -           _fulldrops.add(drop);
  418. -       }
  419. +       _minions.add(minion);
  420.     }
  421. -
  422. -        // for the second category: mats, potions, scrolls, and other miscellaneous items.
  423. -        // basically, for everything not included in the other two categories.
  424. -        // only ONE of all items in this catgory should be dropped per kill .
  425. -        public void addMiscDropData(L2DropData drop)
  426. +  
  427. +   public void addSkill(L2Skill skill)
  428.     {
  429. -       if (drop.isQuestDrop()) {
  430. -//         should never happen here
  431. -       } else {
  432. -           _miscdrops.add(drop);
  433. -       }
  434. +       if (_skills == null)
  435. +       {
  436. +           _skills = new FastMap<Integer, L2Skill>();
  437. +       }
  438. +       _skills.put(skill.getId(), skill);
  439.     }
  440. -
  441. -        public void addRaidData(L2MinionData minion)
  442. -        {
  443. -           _minions.add(minion);
  444. -        }
  445. -
  446. -        public void addSkill(L2Skill skill)
  447. +  
  448. +   public void addVulnerability(Stats id, double vuln)
  449.     {
  450. -       if (_skills == null)
  451. -       _skills = new FastMap<Integer, L2Skill>();
  452. -       _skills.put(skill.getId(), skill);
  453. +       if (_vulnerabilities == null)
  454. +       {
  455. +           _vulnerabilities = new FastMap<Stats, Double>();
  456. +       }
  457. +       _vulnerabilities.put(id, new Double(vuln));
  458.     }
  459. -
  460. -        public void addVulnerability(Stats id, double vuln)
  461. +  
  462. +   public double getVulnerability(Stats id)
  463.     {
  464. -       if (_vulnerabilities == null)
  465. -       _vulnerabilities = new FastMap<Stats, Double>();
  466. -       _vulnerabilities.put(id, new Double(vuln));
  467. +       if ((_vulnerabilities == null) || (_vulnerabilities.get(id) == null))
  468. +       {
  469. +           return 1;
  470. +       }
  471. +       return _vulnerabilities.get(id);
  472.     }
  473. -
  474. -        public double getVulnerability(Stats id)
  475. +  
  476. +   public double removeVulnerability(Stats id)
  477.     {
  478. -           if (_vulnerabilities == null || _vulnerabilities.get(id) == null)
  479. -           return 1;
  480. -       return _vulnerabilities.get(id);
  481. +       return _vulnerabilities.remove(id);
  482.     }
  483. -
  484. -        public double removeVulnerability(Stats id)
  485. +  
  486. +   public FastList<L2DropCategory> getDropData()
  487.     {
  488. -       return _vulnerabilities.remove(id);
  489. +       return _categories;
  490.     }
  491. -
  492. +  
  493.     /**
  494. -    * Return the list of all possible UNCATEGORIZED drops of this L2NpcTemplate.<BR><BR>
  495. +    * Return the list of all possible item drops of this L2NpcTemplate.<BR>
  496. +    * (ie full drops and part drops, mats, miscellaneous & UNCATEGORIZED)<BR>
  497. +    * <BR>
  498.      */
  499. -   public List<L2DropData> getDropData()
  500. +   public List<L2DropData> getAllDropData()
  501.     {
  502. -       return _drops;
  503. +       List<L2DropData> lst = new FastList<L2DropData>();
  504. +       for (L2DropCategory tmp : _categories)
  505. +       {
  506. +           lst.addAll(tmp.getAllDrops());
  507. +       }
  508. +       return lst;
  509.     }
  510. -
  511. +  
  512.     /**
  513. -    * Return the list of all possible full drops and part drops of this L2NpcTemplate.<BR><BR>
  514. +    * Empty all possible drops of this L2NpcTemplate.<BR>
  515. +    * <BR>
  516.      */
  517. -   public List<L2DropData> getFullDropData()
  518. +   public synchronized void clearAllDropData()
  519.     {
  520. -       return _fulldrops;
  521. +       while (_categories.size() > 0)
  522. +       {
  523. +           _categories.getFirst().clearAllDrops();
  524. +           _categories.removeFirst();
  525. +       }
  526. +       _categories.clear();
  527.     }
  528. -
  529. +  
  530.     /**
  531. -    * Return the list of all possible mat & miscellaneous item drops of this L2NpcTemplate.<BR><BR>
  532. +    * Return the list of all Minions that must be spawn with the L2NpcInstance using this L2NpcTemplate.<BR>
  533. +    * <BR>
  534.      */
  535. -   public List<L2DropData> getMiscDropData()
  536. -   {
  537. -       return _miscdrops;
  538. -   }
  539. -
  540. -        /**
  541. -         * Return the list of all possible item drops of this L2NpcTemplate.<BR>
  542. -         * (ie full drops and part drops, mats, miscellaneous & UNCATEGORIZED)<BR><BR>
  543. -         */
  544. -        public List<L2DropData> getAllDropData()
  545. -        {
  546. -            List<L2DropData> lst = new FastList<L2DropData>();
  547. -            lst.addAll(_drops);
  548. -            lst.addAll(_fulldrops);
  549. -            lst.addAll(_miscdrops);
  550. -            return lst;
  551. -        }
  552. -
  553. -        /**
  554. -         * Empty all possible drops of this L2NpcTemplate.<BR><BR>
  555. -         */
  556. -        public void clearAllDropData()
  557. -        {
  558. -            _drops.clear();
  559. -            _fulldrops.clear();
  560. -            _miscdrops.clear();
  561. -        }
  562. -
  563. -   /**
  564. -    * Return the list of all Minions that must be spawn with the L2NpcInstance using this L2NpcTemplate.<BR><BR>
  565. -    */
  566.     public List<L2MinionData> getMinionData()
  567.     {
  568. -       return _minions;
  569. +       return _minions;
  570.     }
  571. -
  572. -        public Map<Integer, L2Skill> getSkills()
  573. +  
  574. +   public Map<Integer, L2Skill> getSkills()
  575.     {
  576. -       return _skills;
  577. +       return _skills;
  578.     }
  579. -
  580. +  
  581.     public void addQuestEvent(Quest.QuestEventType EventType, Quest q)
  582. -        {
  583. -            if (_questEvents == null)
  584. -                _questEvents = new FastMap<Quest.QuestEventType, Quest[]>();
  585. -
  586. -            if (_questEvents.get(EventType) == null)
  587. -                _questEvents.put(EventType, new Quest[]{q});
  588. -            else
  589. -            {
  590. -                Quest[] _quests = _questEvents.get(EventType);
  591. -                int len = _quests.length;
  592. -
  593. -                // if only one registration per npc is allowed for this event type
  594. -                // then only register this NPC if not already registered for the specified event.
  595. -                // if a quest allows multiple registrations, then register regardless of count
  596. -                if (EventType.isMultipleRegistrationAllowed() || (len < 1))
  597. -                {
  598. -                    Quest[] tmp = new Quest[len+1];
  599. -                    for (int i=0; i < len; i++)
  600. -                    {
  601. -                        if (_quests[i].getName().equals(q.getName()))
  602. -                        {
  603. -                            _quests[i] = q;
  604. -                            return;
  605. -                        }
  606. -                        tmp[i] = _quests[i];
  607. -                    }
  608. -                    tmp[len] = q;
  609. -                    _questEvents.put(EventType, tmp);
  610. -                }
  611. -                else
  612. -                    _log.warning("Quest event not allowed in multiple quests.  Skipped addition of Event Type \""+EventType+"\" for NPC \""+this.name +"\" and quest \""+q.getName()+"\".");
  613. -            }
  614. +   {
  615. +       if (_questEvents == null)
  616. +       {
  617. +           _questEvents = new FastMap<Quest.QuestEventType, Quest[]>();
  618. +       }
  619. +      
  620. +       if (_questEvents.get(EventType) == null)
  621. +       {
  622. +           _questEvents.put(EventType, new Quest[]
  623. +           {
  624. +               q
  625. +           });
  626. +       }
  627. +       else
  628. +       {
  629. +           Quest[] _quests = _questEvents.get(EventType);
  630. +           int len = _quests.length;
  631. +          
  632. +           // if only one registration per npc is allowed for this event type
  633. +           // then only register this NPC if not already registered for the specified event.
  634. +           // if a quest allows multiple registrations, then register regardless of count
  635. +           if (EventType.isMultipleRegistrationAllowed() || (len < 1))
  636. +           {
  637. +               Quest[] tmp = new Quest[len + 1];
  638. +               for (int i = 0; i < len; i++)
  639. +               {
  640. +                   if (_quests[i].getName().equals(q.getName()))
  641. +                   {
  642. +                       _quests[i] = q;
  643. +                       return;
  644. +                   }
  645. +                   tmp[i] = _quests[i];
  646. +               }
  647. +               tmp[len] = q;
  648. +               _questEvents.put(EventType, tmp);
  649. +           }
  650. +           else
  651. +           {
  652. +               _log.warning("Quest event not allowed in multiple quests.  Skipped addition of Event Type \"" + EventType + "\" for NPC \"" + this.name + "\" and quest \"" + q.getName() + "\".");
  653. +           }
  654. +       }
  655.     }
  656. -
  657. -        public Quest[] getEventQuests(Quest.QuestEventType EventType)
  658. -        {
  659. -            if (_questEvents == null)
  660. -                return null;
  661. -
  662. -            return _questEvents.get(EventType);
  663. -        }
  664. -
  665. +  
  666. +   public Quest[] getEventQuests(Quest.QuestEventType EventType)
  667. +   {
  668. +       if (_questEvents == null)
  669. +       {
  670. +           return null;
  671. +       }
  672. +      
  673. +       return _questEvents.get(EventType);
  674. +   }
  675. +  
  676.     public StatsSet getStatsSet()
  677.     {
  678. -       return npcStatsSet;
  679. +       return npcStatsSet;
  680.     }
  681. -
  682. +  
  683.     public void setRace(int newrace)
  684.     {
  685. -       race = newrace;
  686. +       race = newrace;
  687.     }
  688.  }
  689. \ No newline at end of file
  690. Index: java/net/sf/l2j/gameserver/datatables/NpcTable.java
  691. ===================================================================
  692. --- java/net/sf/l2j/gameserver/datatables/NpcTable.java (revision 355)
  693. +++ java/net/sf/l2j/gameserver/datatables/NpcTable.java (working copy)
  694. @@ -28,6 +28,7 @@
  695.  import javolution.util.FastMap;
  696.  import net.sf.l2j.Config;
  697.  import net.sf.l2j.L2DatabaseFactory;
  698. +import net.sf.l2j.gameserver.model.L2DropCategory;
  699.  import net.sf.l2j.gameserver.model.L2DropData;
  700.  import net.sf.l2j.gameserver.model.L2MinionData;
  701.  import net.sf.l2j.gameserver.model.L2Skill;
  702. @@ -135,7 +136,7 @@
  703.            
  704.             try
  705.                          {
  706. -               PreparedStatement statement2 = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"mobId", "itemId", "min", "max", "sweep", "chance"}) + ", IFNULL(drop_category,1) AS drop_category FROM droplist LEFT JOIN etcitem ON itemId = item_id ORDER BY mobId, chance DESC");
  707. +               PreparedStatement statement2 = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"mobId", "itemId", "min", "max", "category", "chance"}) + " FROM droplist ORDER BY mobId, chance DESC");
  708.                 ResultSet dropData = statement2.executeQuery();
  709.                 L2DropData dropDat = null;
  710.                 L2NpcTemplate npcDat = null;
  711. @@ -154,37 +155,11 @@
  712.                     dropDat.setItemId(dropData.getInt("itemId"));
  713.                     dropDat.setMinDrop(dropData.getInt("min"));
  714.                     dropDat.setMaxDrop(dropData.getInt("max"));
  715. -                   dropDat.setSweep(dropData.getInt("sweep") == 1);
  716.                     dropDat.setChance(dropData.getInt("chance"));
  717.                      
  718. -                   int category = dropData.getInt("drop_category");
  719. +                   int category = dropData.getInt("category");
  720.                    
  721. -                   // uncategorized drops: marked as uncategorized, or are sweep, or this is a raidboss
  722. -                   // uncategorized allows many drops to be given from the same list
  723. -                   // the following mobs are grandbosses.  Grandbosses are L2Monster but should be treated like RBs.
  724. -                   // 12001    Queen Ant
  725. -                   // 12169    Orfen
  726. -                   // 12211    Antharas
  727. -                   // 12372    Baium
  728. -                   // 12374    Zaken
  729. -                   // 12899    Valakas                
  730. -                   if ((category == 0)
  731. -                        || (dropDat.isSweep())
  732. -                        || (npcDat.type.compareToIgnoreCase("L2RaidBoss") == 0)
  733. -                        || (npcDat.type.compareToIgnoreCase("L2Boss") == 0)
  734. -                      )
  735. -                    {
  736. -                       npcDat.addDropData(dropDat);
  737. -                    }
  738. -                   //  categorized as full drops and parts for armor/weapon/jewel
  739. -                   else
  740. -                   {
  741. -                       if (category == 1)
  742. -                           npcDat.addFullDropData(dropDat);
  743. -                       // other items (miscellaneous like scrolls, potions, mats, etc).
  744. -                       else
  745. -                           npcDat.addMiscDropData(dropDat);
  746. -                   }
  747. +                   npcDat.addDropData(dropDat, category);
  748.                 }
  749.  
  750.                 dropData.close();
  751. @@ -350,10 +325,10 @@
  752.             if (old.getSkills() != null)
  753.                 skills.putAll(old.getSkills());
  754.              
  755. -           List<L2DropData> drops = new FastList<L2DropData>();
  756. +           FastList<L2DropCategory> categories = new FastList<L2DropCategory>();
  757.              
  758.             if (old.getDropData() != null)
  759. -               drops.addAll(old.getDropData());
  760. +               categories.addAll(old.getDropData());
  761.              
  762.             ClassId[] classIds = null;
  763.              
  764. @@ -380,9 +355,6 @@
  765.             for (L2Skill skill : skills.values())
  766.                 created.addSkill(skill);
  767.              
  768. -           for (L2DropData drop : drops)
  769. -               created.addDropData(drop);
  770. -            
  771.             if (classIds != null)
  772.                 for (ClassId classId : classIds)
  773.                     created.addTeachInfo(classId);
  774. Index: java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditNpc.java
  775. ===================================================================
  776. --- java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditNpc.java   (revision 355)
  777. +++ java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminEditNpc.java   (working copy)
  778. @@ -35,6 +35,7 @@
  779.  import net.sf.l2j.gameserver.datatables.NpcTable;
  780.  import net.sf.l2j.gameserver.handler.IAdminCommandHandler;
  781.  import net.sf.l2j.gameserver.model.L2DropData;
  782. +import net.sf.l2j.gameserver.model.L2DropCategory;
  783.  import net.sf.l2j.gameserver.model.L2ItemInstance;
  784.  import net.sf.l2j.gameserver.model.L2Object;
  785.  import net.sf.l2j.gameserver.model.L2TradeList;
  786. @@ -839,13 +840,14 @@
  787.         replyMSG.append("<table>");
  788.         replyMSG.append("<tr><td>npc_id itemId</td><td>item[id]</td><td>type</td><td>del</td></tr>");
  789.        
  790. -       for(L2DropData drop : npcData.getAllDropData())
  791. -       {
  792. -           replyMSG.append("<tr><td><a action=\"bypass -h admin_edit_drop " + npcData.npcId + " " + drop.getItemId() + "\">"
  793. -                    + npcData.npcId + " " + drop.getItemId() + "</a></td>" +
  794. -                    "<td>" + ItemTable.getInstance().getTemplate(drop.getItemId()).getName() + "[" + drop.getItemId() + "]" + "</td><td>" + (drop.isQuestDrop()?"Q":(drop.isSweep()?"S":"D")) + "</td><td>" +
  795. -                    "<a action=\"bypass -h admin_del_drop " + npcData.npcId + " " + drop.getItemId() + "\">del</a></td></tr>");
  796. -       }
  797. +       for(L2DropCategory cat:npcData.getDropData())
  798. +           for(L2DropData drop : cat.getAllDrops())
  799. +           {
  800. +               replyMSG.append("<tr><td><a action=\"bypass -h admin_edit_drop " + npcData.npcId + " " + drop.getItemId() + "\">"
  801. +                       + npcData.npcId + " " + drop.getItemId() + "</a></td>" +
  802. +                       "<td>" + ItemTable.getInstance().getTemplate(drop.getItemId()).getName() + "[" + drop.getItemId() + "]" + "</td><td>" + (drop.isQuestDrop()?"Q":(cat.isSweep()?"S":"D")) + "</td><td>" +
  803. +                       "<a action=\"bypass -h admin_del_drop " + npcData.npcId + " " + drop.getItemId() + "\">del</a></td></tr>");
  804. +           }
  805.        
  806.         replyMSG.append("</table>");
  807.         replyMSG.append("<center>");
  808. @@ -1102,28 +1104,10 @@
  809.                 dropData.setItemId(dropDataList.getInt("itemId"));
  810.                 dropData.setMinDrop(dropDataList.getInt("min"));
  811.                 dropData.setMaxDrop(dropDataList.getInt("max"));
  812. -               dropData.setSweep(dropDataList.getInt("sweep") == 1);
  813.                 dropData.setChance(dropDataList.getInt("chance"));
  814.  
  815. -                int category = dropDataList.getInt("drop_category");
  816. -                
  817. -                if ((category == 0)
  818. -                    || (dropData.isSweep())
  819. -                    || (npcData.type.compareToIgnoreCase("L2RaidBoss") == 0)
  820. -                    || (npcData.type.compareToIgnoreCase("L2Boss") == 0)
  821. -                   )
  822. -                {
  823. -                    npcData.addDropData(dropData);
  824. -                }
  825. -                //  categorized as full drops and parts for armor/weapon/jewel
  826. -                else
  827. -                {
  828. -                    if (category == 1)
  829. -                        npcData.addFullDropData(dropData);
  830. -                    // other items (miscellaneous like scrolls, potions, mats, etc).
  831. -                    else
  832. -                        npcData.addMiscDropData(dropData);
  833. -                }
  834. +               int category = dropDataList.getInt("category");
  835. +               npcData.addDropData(dropData, category);
  836.             }
  837.             dropDataList.close();
  838.             statement.close();
  839. Index: java/net/sf/l2j/gameserver/model/L2DropCategory.java
  840. ===================================================================
  841. --- java/net/sf/l2j/gameserver/model/L2DropCategory.java    (revision 0)
  842. +++ java/net/sf/l2j/gameserver/model/L2DropCategory.java    (revision 0)
  843. @@ -0,0 +1,170 @@
  844. +/*
  845. + * Copyright (C) 2004-2013 L2J Server
  846. + *
  847. + * This file is part of L2J Server.
  848. + *
  849. + * L2J Server is free software: you can redistribute it and/or modify
  850. + * it under the terms of the GNU General Public License as published by
  851. + * the Free Software Foundation, either version 3 of the License, or
  852. + * (at your option) any later version.
  853. + *
  854. + * L2J Server is distributed in the hope that it will be useful,
  855. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  856. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  857. + * General Public License for more details.
  858. + *
  859. + * You should have received a copy of the GNU General Public License
  860. + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  861. + */
  862. +package net.sf.l2j.gameserver.model;
  863. +
  864. +import javolution.util.FastList;
  865. +import net.sf.l2j.Config;
  866. +import net.sf.l2j.gameserver.lib.Rnd;
  867. +
  868. +/**
  869. + * @author Fulminus
  870. + */
  871. +public class L2DropCategory
  872. +{
  873. +   private final FastList<L2DropData> _drops;
  874. +   private int _categoryChance; // a sum of chances for calculating if an item will be dropped from this category
  875. +   private int _categoryBalancedChance; // sum for balancing drop selection inside categories in high rate servers
  876. +   private final int _categoryType;
  877. +  
  878. +   public L2DropCategory(int categoryType)
  879. +   {
  880. +       _categoryType = categoryType;
  881. +       _drops = new FastList<>(0);
  882. +       _categoryChance = 0;
  883. +       _categoryBalancedChance = 0;
  884. +   }
  885. +  
  886. +   public void addDropData(L2DropData drop)
  887. +   {
  888. +       if (drop.isQuestDrop())
  889. +       {
  890. +           // if (_questDrops == null)
  891. +           // _questDrops = new FastList<>(0);
  892. +           // _questDrops.add(drop);
  893. +       }
  894. +       else
  895. +       {
  896. +          
  897. +           _drops.add(drop);
  898. +           _categoryChance += drop.getChance();
  899. +           // for drop selection inside a category: max 100 % chance for getting an item, scaling all values to that.
  900. +           _categoryBalancedChance += Math.min((drop.getChance() * (Config.RATE_DROP_ITEMS)), L2DropData.MAX_CHANCE);
  901. +          
  902. +       }
  903. +   }
  904. +  
  905. +   public FastList<L2DropData> getAllDrops()
  906. +   {
  907. +       return _drops;
  908. +   }
  909. +  
  910. +   public void clearAllDrops()
  911. +   {
  912. +       _drops.clear();
  913. +   }
  914. +  
  915. +   public boolean isSweep()
  916. +   {
  917. +       return (getCategoryType() == -1);
  918. +   }
  919. +  
  920. +   // this returns the chance for the category to be visited in order to check if
  921. +   // drops might come from it. Category -1 (spoil) must always be visited
  922. +   // (but may return 0 or many drops)
  923. +   public int getCategoryChance()
  924. +   {
  925. +       if (getCategoryType() >= 0)
  926. +       {
  927. +           return _categoryChance;
  928. +       }
  929. +       return L2DropData.MAX_CHANCE;
  930. +   }
  931. +  
  932. +   public int getCategoryBalancedChance()
  933. +   {
  934. +       if (getCategoryType() >= 0)
  935. +       {
  936. +           return _categoryBalancedChance;
  937. +       }
  938. +       return L2DropData.MAX_CHANCE;
  939. +   }
  940. +  
  941. +   public int getCategoryType()
  942. +   {
  943. +       return _categoryType;
  944. +   }
  945. +  
  946. +   /**
  947. +    * Useful for seeded conditions... the category will attempt to drop only among items that are allowed to be dropped when a mob is seeded.<br>
  948. +    * Previously, this only included Adena. According to sh1ny, seals tones are also acceptable drops.<br>
  949. +    * If no acceptable drops are in the category, nothing will be dropped.<br>
  950. +    * therwise, it will check for the item's chance to drop and either drop it or drop nothing.
  951. +    * @return acceptable drop when mob is seeded, if it exists. Null otherwise.
  952. +    */
  953. +   public synchronized L2DropData dropSeedAllowedDropsOnly()
  954. +   {
  955. +       FastList<L2DropData> drops = new FastList<>();
  956. +       int subCatChance = 0;
  957. +       for (L2DropData drop : getAllDrops())
  958. +       {
  959. +           if ((drop.getItemId() == PcInventory.ADENA_ID))
  960. +           {
  961. +               drops.add(drop);
  962. +               subCatChance += drop.getChance();
  963. +           }
  964. +       }
  965. +      
  966. +       // among the results choose one.
  967. +       int randomIndex = Rnd.get(subCatChance);
  968. +       int sum = 0;
  969. +       for (L2DropData drop : drops)
  970. +       {
  971. +           sum += drop.getChance();
  972. +          
  973. +           if (sum > randomIndex) // drop this item and exit the function
  974. +           {
  975. +               drops.clear();
  976. +               drops = null;
  977. +               return drop;
  978. +           }
  979. +       }
  980. +       // since it is still within category, only drop one of the acceptable drops from the results.
  981. +       return null;
  982. +   }
  983. +  
  984. +   /**
  985. +    * One of the drops in this category is to be dropped now.<br>
  986. +    * to see which one will be dropped, weight all items' chances such that their sum of chances equals MAX_CHANCE.<br>
  987. +    * Since the individual drops have their base chance, we also ought to use the base category chance for the weight.<br>
  988. +    * So weight = MAX_CHANCE/basecategoryDropChance.<br>
  989. +    * Then get a single random number within this range. The first item (in order of the list) whose contribution to the sum makes the sum greater than the random number, will be dropped.<br>
  990. +    * Edited: How _categoryBalancedChance works in high rate servers:<br>
  991. +    * Let's say item1 has a drop chance (when considered alone, without category) of 1 % * RATE_DROP_ITEMS and item2 has 20 % * RATE_DROP_ITEMS, and the server's RATE_DROP_ITEMS is for example 50x.<br>
  992. +    * Without this balancer, the relative chance inside the category to select item1 to be dropped would be 1/26 and item2 25/26, no matter what rates are used.<br>
  993. +    * In high rate servers people usually consider the 1 % individual drop chance should become higher than this relative chance (1/26) inside the category, since having the both items for example in their own categories would result in having a drop chance for item1 50 % and item2 1000 %.<br>
  994. +    * _categoryBalancedChance limits the individual chances to 100 % max, making the chance for item1 to be selected from this category 50/(50+100) = 1/3 and item2 100/150 = 2/3.<br>
  995. +    * This change doesn't affect calculation when drop_chance * RATE_DROP_ITEMS < 100%, meaning there are no big changes for low rate servers and no changes at all for 1x servers.
  996. +    * @return selected drop from category, or null if nothing is dropped.
  997. +    */
  998. +   public synchronized L2DropData dropOne()
  999. +   {
  1000. +       int randomIndex = Rnd.get(getCategoryBalancedChance());
  1001. +       int sum = 0;
  1002. +       for (L2DropData drop : getAllDrops())
  1003. +       {
  1004. +           sum += Math.min((drop.getChance() * (Config.RATE_DROP_ITEMS)), L2DropData.MAX_CHANCE);
  1005. +          
  1006. +           if (sum >= randomIndex)
  1007. +           {
  1008. +               return drop;
  1009. +           }
  1010. +       }
  1011. +       return null;
  1012. +   }
  1013. +}
  1014. Index: java/net/sf/l2j/gameserver/model/L2Attackable.java
  1015. ===================================================================
  1016. --- java/net/sf/l2j/gameserver/model/L2Attackable.java  (revision 355)
  1017. +++ java/net/sf/l2j/gameserver/model/L2Attackable.java  (working copy)
  1018. @@ -58,2059 +58,2434 @@
  1019.  import net.sf.l2j.gameserver.util.Util;
  1020.  
  1021.  /**
  1022. - * This class manages all NPC that can be attacked.<BR><BR>
  1023. - *
  1024. - * L2Attackable :<BR><BR>
  1025. - * <li>L2ArtefactInstance</li>
  1026. - * <li>L2FriendlyMobInstance</li>
  1027. - * <li>L2MonsterInstance</li>
  1028. - * <li>L2SiegeGuardInstance </li>
  1029. - *
  1030. + * This class manages all NPC that can be attacked.<BR>
  1031. + * <BR>
  1032. + * L2Attackable :<BR>
  1033. + * <BR>
  1034. + * <li>L2ArtefactInstance</li> <li>L2FriendlyMobInstance</li> <li>L2MonsterInstance</li> <li>L2SiegeGuardInstance</li>
  1035.   * @version $Revision: 1.24.2.3.2.16 $ $Date: 2005/04/11 19:11:21 $
  1036.   */
  1037.  public class L2Attackable extends L2NpcInstance
  1038.  {
  1039. -    //protected static Logger _log = Logger.getLogger(L2Attackable.class.getName());
  1040. -    
  1041. -    /**
  1042. -     * This class contains all AggroInfo of the L2Attackable against the attacker L2Character.<BR><BR>
  1043. -     *
  1044. -     * <B><U> Data</U> :</B><BR><BR>
  1045. -     * <li>attacker : The attaker L2Character concerned by this AggroInfo of this L2Attackable </li>
  1046. -     * <li>hate : Hate level of this L2Attackable against the attaker L2Character (hate = damage) </li>
  1047. -     * <li>damage : Number of damages that the attaker L2Character gave to this L2Attackable </li><BR><BR>
  1048. -     *
  1049. -     */
  1050. -    public final class AggroInfo
  1051. -    {
  1052. -        /** The attaker L2Character concerned by this AggroInfo of this L2Attackable */
  1053. -        L2Character attacker;
  1054. -        
  1055. -        /** Hate level of this L2Attackable against the attaker L2Character (hate = damage) */
  1056. -        int hate;
  1057. -        
  1058. -        /** Number of damages that the attaker L2Character gave to this L2Attackable */
  1059. -        int damage;
  1060. -        
  1061. -        
  1062. -        /**
  1063. -         * Constructor of AggroInfo.<BR><BR>
  1064. -         */
  1065. -        AggroInfo(L2Character pAttacker)
  1066. -        {
  1067. -            attacker = pAttacker;
  1068. -        }
  1069. -        
  1070. -        /**
  1071. -         * Verify is object is equal to this AggroInfo.<BR><BR>
  1072. -         */
  1073. -        public boolean equals(Object obj)
  1074. -        {
  1075. -            if (this == obj)
  1076. -                return true;
  1077. -
  1078. -            if (obj instanceof AggroInfo)
  1079. -                return (((AggroInfo)obj).attacker == attacker);
  1080. -
  1081. -            return false;
  1082. -        }
  1083. -        
  1084. -        /**
  1085. -         * Return the Identifier of the attaker L2Character.<BR><BR>
  1086. -         */
  1087. -        public int hashCode()
  1088. -        {
  1089. -            return attacker.getObjectId();
  1090. -        }
  1091. -        
  1092. -    }
  1093. -    
  1094. -    
  1095. -    /**
  1096. -     * This class contains all RewardInfo of the L2Attackable against the any attacker L2Character, based on amount of damage done.<BR><BR>
  1097. -     *
  1098. -     * <B><U> Data</U> :</B><BR><BR>
  1099. -     * <li>attacker : The attaker L2Character concerned by this RewardInfo of this L2Attackable </li>
  1100. -     * <li>dmg : Total amount of damage done by the attacker to this L2Attackable (summon + own) </li>
  1101. -     *
  1102. -     */
  1103. -    protected final class RewardInfo
  1104. -    {
  1105. -        protected L2Character attacker;
  1106. -        protected int dmg = 0;
  1107. -        
  1108. -        public RewardInfo(L2Character pAttacker, int pDmg)
  1109. -        {
  1110. -            attacker = pAttacker;
  1111. -            dmg = pDmg;
  1112. -        }
  1113. -        
  1114. -        public void addDamage(int pDmg)
  1115. -        {
  1116. -            dmg += pDmg;
  1117. -        }
  1118. -        
  1119. -        public boolean equals(Object obj)
  1120. -        {
  1121. -            if (this == obj)
  1122. -                return true;
  1123. -
  1124. -            if (obj instanceof RewardInfo)
  1125. -                return (((RewardInfo)obj).attacker == attacker);
  1126. -
  1127. -            return false;
  1128. -        }
  1129. -        
  1130. -        public int hashCode()
  1131. -        {
  1132. -            return attacker.getObjectId();
  1133. -        }
  1134. -    }
  1135. -    
  1136. -    /**
  1137. -     * This class contains all AbsorberInfo of the L2Attackable against the absorber L2Character.<BR><BR>
  1138. -     *
  1139. -     * <B><U> Data</U> :</B><BR><BR>
  1140. -     * <li>absorber : The attaker L2Character concerned by this AbsorberInfo of this L2Attackable </li>
  1141. -     *
  1142. -     */
  1143. -    public final class AbsorberInfo
  1144. -    {
  1145. -        /** The attaker L2Character concerned by this AbsorberInfo of this L2Attackable */
  1146. -        L2PcInstance absorber;
  1147. -        int crystalId;
  1148. -        double absorbedHP;
  1149. -        
  1150. -        /**
  1151. -         * Constructor of AbsorberInfo.<BR><BR>
  1152. -         */
  1153. -        AbsorberInfo(L2PcInstance attacker, int pCrystalId, double pAbsorbedHP)
  1154. -        {
  1155. -            absorber = attacker;
  1156. -            crystalId = pCrystalId;
  1157. -            absorbedHP = pAbsorbedHP;
  1158. -        }
  1159. -        
  1160. -        /**
  1161. -         * Verify is object is equal to this AbsorberInfo.<BR><BR>
  1162. -         */
  1163. -        public boolean equals(Object obj)
  1164. -        {
  1165. -            if (this == obj)
  1166. -                return true;
  1167. -
  1168. -            if (obj instanceof AbsorberInfo)
  1169. -                return (((AbsorberInfo)obj).absorber == absorber);
  1170. -
  1171. -            return false;
  1172. -        }
  1173. -        
  1174. -        /**
  1175. -         * Return the Identifier of the absorber L2Character.<BR><BR>
  1176. -         */
  1177. -        public int hashCode()
  1178. -        {
  1179. -            return absorber.getObjectId();
  1180. -        }
  1181. -    }
  1182. -    
  1183. -    /**
  1184. -     * This class is used to create item reward lists instead of creating item instances.<BR><BR>
  1185. -     */
  1186. -    public final class RewardItem
  1187. -    {
  1188. -        protected int _itemId;
  1189. -        protected int _count;
  1190. -        
  1191. -        public RewardItem(int itemId, int count)
  1192. -        {
  1193. -            _itemId = itemId;
  1194. -            _count = count;
  1195. -        }
  1196. -        
  1197. -        public int getItemId() { return _itemId;}
  1198. -        public int getCount() { return _count;}
  1199. -    }
  1200. -
  1201. -    private FastMap<L2Character, AggroInfo> _aggroList = new FastMap<L2Character, AggroInfo>().setShared(true);
  1202. -
  1203. -    /** Use this to Remove Object from this Map
  1204. -     * This Should be Synchronized While Iterating over This Map - if u cant iterating and removing object at once
  1205. -     */
  1206. -    public final FastMap<L2Character, AggroInfo> getAggroList()
  1207. -    {
  1208. -       return _aggroList;
  1209. -    }
  1210. -
  1211. -    private boolean _isReturningToSpawnPoint = false;
  1212. -
  1213. -    public final boolean isReturningToSpawnPoint()
  1214. -    {
  1215. -        return _isReturningToSpawnPoint;
  1216. -    }
  1217. -
  1218. -    public final void setIsReturningToSpawnPoint(boolean value)
  1219. -    {
  1220. -        _isReturningToSpawnPoint = value;
  1221. -    }
  1222. -
  1223. -    /** Table containing all Items that a Dwarf can Sweep on this L2Attackable */
  1224. -    private RewardItem[] _sweepItems;
  1225. -    
  1226. -    /** crops */
  1227. -    private RewardItem[] _harvestItems;
  1228. -    private boolean _seeded;
  1229. -    private int _seedType = 0;
  1230. -    private L2PcInstance _seeder = null;
  1231. -    
  1232. -    /** True if an over-hit enabled skill has successfully landed on the L2Attackable */
  1233. -    private boolean _overhit;
  1234. -    
  1235. -    /** Stores the extra (over-hit) damage done to the L2Attackable when the attacker uses an over-hit enabled skill */
  1236. -    private double _overhitDamage;
  1237. -    
  1238. -    /** Stores the attacker who used the over-hit enabled skill on the L2Attackable */
  1239. -    private L2Character _overhitAttacker;
  1240. -    
  1241. -    /** True if a Soul Crystal was successfuly used on the L2Attackable */
  1242. -    private boolean _absorbed;
  1243. -    
  1244. -    /** The table containing all L2PcInstance that successfuly absorbed the soul of this L2Attackable */
  1245. -    private FastMap<L2PcInstance, AbsorberInfo> _absorbersList = new FastMap<L2PcInstance, AbsorberInfo>().setShared(true);
  1246. -
  1247. -    /** Have this L2Attackable to drop somethink on DIE? **/
  1248. -    private boolean _haveToDrop;
  1249. -
  1250. -    /** Have this L2Attackable to reward Exp and SP on Die? **/
  1251. -    private boolean _mustGiveExpSp;
  1252. -
  1253. -    /**
  1254. -     * Constructor of L2Attackable (use L2Character and L2NpcInstance constructor).<BR><BR>
  1255. -     *  
  1256. -     * <B><U> Actions</U> :</B><BR><BR>
  1257. -     * <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>
  1258. -     * <li>Set the name of the L2Attackable</li>
  1259. -     * <li>Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it </li><BR><BR>
  1260. -     *
  1261. -     * @param objectId Identifier of the object to initialized
  1262. -     * @param L2NpcTemplate Template to apply to the NPC
  1263. -     */
  1264. -    public L2Attackable(int objectId, L2NpcTemplate template)
  1265. -    {
  1266. -        super(objectId, template);
  1267. -        getKnownList(); // init knownlist
  1268. -        _haveToDrop = true;
  1269. -        _mustGiveExpSp = true;
  1270. -    }
  1271. -
  1272. -    public AttackableKnownList getKnownList()
  1273. -    {
  1274. -        if (super.getKnownList() == null || !(super.getKnownList() instanceof AttackableKnownList))
  1275. -            setKnownList(new AttackableKnownList(this));
  1276. -        return (AttackableKnownList)super.getKnownList();
  1277. -    }
  1278. -
  1279. -    /**
  1280. -     * Return the L2Character AI of the L2Attackable and if its null create a new one.<BR><BR>
  1281. -     */
  1282. -    public L2CharacterAI getAI()
  1283. -    {
  1284. -        if (_ai == null)
  1285. -        {
  1286. -            synchronized(this)
  1287. -            {
  1288. -                if (_ai == null)
  1289. -                    _ai = new L2AttackableAI(new AIAccessor());
  1290. -            }
  1291. -        }
  1292. -        return _ai;
  1293. -    }
  1294. -    
  1295. -    // get condition to hate, actually isAggressive() is checked
  1296. -    // by monster and karma by guards in motheds that overwrite this one.
  1297. -    /**
  1298. -     * Not used.<BR><BR>
  1299. -     *
  1300. -     * @deprecated
  1301. -     *
  1302. -     */
  1303. -    @Deprecated
  1304. -    public boolean getCondition2(L2Character target)
  1305. -    {
  1306. -        if (target instanceof L2FolkInstance || target instanceof L2DoorInstance)
  1307. -            return false;
  1308. -        
  1309. -        if (target.isAlikeDead()
  1310. -                || !isInsideRadius(target, getAggroRange(), false, false)
  1311. -                || Math.abs(getZ()-target.getZ()) > 100
  1312. -)
  1313. -            return false;
  1314. -
  1315. -        return !target.isInvul();
  1316. -    }
  1317. -    
  1318. -    /**
  1319. -     * Reduce the current HP of the L2Attackable.<BR><BR>
  1320. -     *
  1321. -     * @param damage The HP decrease value
  1322. -     * @param attacker The L2Character who attacks
  1323. -     *
  1324. -     */
  1325. -    public void reduceCurrentHp(double damage, L2Character attacker)
  1326. -    {
  1327. -        reduceCurrentHp(damage, attacker, true);
  1328. -    }
  1329. -    
  1330. -    /**
  1331. -     * Reduce the current HP of the L2Attackable, update its _aggroList and launch the doDie Task if necessary.<BR><BR>
  1332. -     *
  1333. -     * @param i The HP decrease value
  1334. -     * @param attacker The L2Character who attacks
  1335. -     * @param awake The awake state (If True : stop sleeping)
  1336. -     *
  1337. -     */
  1338. -    public void reduceCurrentHp(double damage, L2Character attacker, boolean awake)
  1339. -    {
  1340. -
  1341. -        if (isEventMob)
  1342. -            return;
  1343. -
  1344. -
  1345. -        // Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList
  1346. -        if (attacker != null)
  1347. -        {
  1348. -            addDamage(attacker, (int)damage);
  1349. -            addBufferHate();
  1350. -        }
  1351. -        
  1352. -        // If this L2Attackable is a L2MonsterInstance and it has spawned minions, call its minions to battle
  1353. -        if (this instanceof L2MonsterInstance)
  1354. -        {
  1355. -            L2MonsterInstance master = (L2MonsterInstance) this;
  1356. -            if (this instanceof L2MinionInstance)
  1357. -            {
  1358. -                master = ((L2MinionInstance)this).getLeader();
  1359. -                if (!master.isInCombat()&&!master.isDead())
  1360. -                {
  1361. -                    master.addDamage(attacker, 1);
  1362. -                    master.addBufferHate();
  1363. -                }
  1364. -            }
  1365. -            if (master.hasMinions())
  1366. -                master.callMinionsToAssist(attacker);
  1367. -        }
  1368. -        
  1369. -        // Reduce the current HP of the L2Attackable and launch the doDie Task if necessary
  1370. -        super.reduceCurrentHp(damage, attacker, awake);
  1371. -    }
  1372. -
  1373. -    public synchronized void setHaveToDrop(boolean value)
  1374. -    {
  1375. -        _haveToDrop = value;
  1376. -    }
  1377. -
  1378. -    public synchronized boolean getHaveToDrop()
  1379. -    {
  1380. -        return _haveToDrop;
  1381. -    }
  1382. -
  1383. -    public synchronized void setMustRewardExpSp(boolean value)
  1384. -    {
  1385. -        _mustGiveExpSp = value;
  1386. -    }
  1387. -
  1388. -    public synchronized boolean getMustRewardExpSP()
  1389. -    {
  1390. -        return _mustGiveExpSp;
  1391. -    }
  1392. -
  1393. -    /**
  1394. -     * Kill the L2Attackable (the corpse disappeared after 7 seconds), distribute rewards (EXP, SP, Drops...) and notify Quest Engine.<BR><BR>
  1395. -     *
  1396. -     * <B><U> Actions</U> :</B><BR><BR>
  1397. -     * <li>Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members </li>
  1398. -     * <li>Notify the Quest Engine of the L2Attackable death if necessary</li>
  1399. -     * <li>Kill the L2NpcInstance (the corpse disappeared after 7 seconds) </li><BR><BR>
  1400. -     *
  1401. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR><BR>
  1402. -     *
  1403. -     * @param killer The L2Character that has killed the L2Attackable
  1404. -     *
  1405. -     */
  1406. -    public boolean doDie(L2Character killer)
  1407. -    {
  1408. -        // Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
  1409. -        if (!super.doDie(killer))
  1410. -            return false;
  1411. -
  1412. -        // Enhance soul crystals of the attacker if this L2Attackable had its soul absorbed
  1413. -        try
  1414. -        {
  1415. -
  1416. -
  1417. -            levelSoulCrystals(killer);
  1418. -
  1419. -        }
  1420. -        catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  1421. -        
  1422. -        // Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members
  1423. -
  1424. -        if (getHaveToDrop() || getMustRewardExpSP())
  1425. -        {
  1426. -            try
  1427. -            {
  1428. -                calculateRewards(killer);
  1429. -            }
  1430. -            catch (Exception e)
  1431. -            {
  1432. -                _log.log(Level.SEVERE, "", e);
  1433. -            }
  1434. -        }
  1435. -
  1436. -        // Notify the Quest Engine of the L2Attackable death if necessary
  1437. -        try
  1438. -        {
  1439. -            L2PcInstance player = null;
  1440. -            if (killer instanceof L2PcInstance)
  1441. -                player = (L2PcInstance)killer;
  1442. -            else if (killer instanceof L2Summon)
  1443. -                player = ((L2Summon)killer).getOwner();
  1444. -
  1445. -            if (player != null)
  1446. -            {
  1447. -                List<QuestState> questList = new FastList<QuestState>();
  1448. -  
  1449. -                if (player.getParty() != null)
  1450. -                {
  1451. -                    Map<String, List<QuestState>> tempMap = new FastMap<String, List<QuestState>>();
  1452. -
  1453. -               for (L2PcInstance pl : player.getParty().getPartyMembers())
  1454. -               {
  1455. -                        if (pl.getQuestsForKills(this) == null)
  1456. -                            continue;
  1457. -
  1458. -                   for (QuestState qs : pl.getQuestsForKills(this))
  1459. -                   {
  1460. -                       if (qs.getState().isParty())
  1461. -                       {
  1462. -                           if (!qs.isCompleted() && !pl.isDead() && Util.checkIfInRange(1400, this, pl, true))
  1463. -                                {
  1464. -                                    if (this instanceof L2RaidBossInstance)
  1465. -                                        questList.add(qs);
  1466. -                                    else
  1467. -                                    {
  1468. -                                   if (tempMap.get(qs.getQuest().getName()) != null)
  1469. -                                       tempMap.get(qs.getQuest().getName()).add(qs);
  1470. -                                   else
  1471. -                                   {
  1472. -                                       List<QuestState> tempList = new FastList<QuestState>();
  1473. -                                            tempList.add(qs);
  1474. -                                       tempMap.put(qs.getQuest().getName(), tempList);
  1475. -                                   }
  1476. -                                    }
  1477. -                                }
  1478. -                       }
  1479. -                       else if (pl == player)
  1480. -                           questList.add(qs);
  1481. -                   }
  1482. -               }
  1483. -
  1484. -               for (List<QuestState> list : tempMap.values())
  1485. -                   questList.add((QuestState)list.toArray()[Rnd.nextInt(list.size())]);
  1486. -                }
  1487. -                else
  1488. -                {
  1489. -                    if (player.getQuestsForKills(this) != null)
  1490. -                    {
  1491. -                        for (QuestState qs : player.getQuestsForKills(this))
  1492. -                            questList.add(qs);
  1493. -                    }
  1494. -                }
  1495. -
  1496. -                for (QuestState qs : questList)
  1497. -                    qs.getQuest().notifyKill(this, qs);
  1498. -            }
  1499. -        }
  1500. -        catch (Exception e)
  1501. -        {
  1502. -
  1503. -            _log.log(Level.SEVERE, "", e);
  1504. -        }
  1505. -        return true;
  1506. -    }
  1507. -    
  1508. -    /**
  1509. -     * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members.<BR><BR>
  1510. -     *
  1511. -     * <B><U> Actions</U> :</B><BR><BR>
  1512. -     * <li>Get the L2PcInstance owner of the L2SummonInstance (if necessary) and L2Party in progress </li>
  1513. -     * <li>Calculate the Experience and SP rewards in function of the level difference</li>
  1514. -     * <li>Add Exp and SP rewards to L2PcInstance (including Summon penalty) and to Party members in the known area of the last attacker </li><BR><BR>
  1515. -     *
  1516. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR><BR>
  1517. -     *
  1518. -     * @param lastAttacker The L2Character that has killed the L2Attackable
  1519. -     *
  1520. -     */
  1521. -    private void calculateRewards(L2Character lastAttacker)
  1522. -    {
  1523. -       if (getAggroList().isEmpty()) return;
  1524. -
  1525. -        if (getMustRewardExpSP())
  1526. -        {
  1527. -
  1528. -
  1529. -        // Creates an empty list of rewards
  1530. -        FastMap<L2Character, RewardInfo> rewards = new FastMap<L2Character, RewardInfo>().setShared(true);
  1531. -        int rewardCount = 0;
  1532. -
  1533. -
  1534. -        int damage;
  1535. -        L2Character attacker;
  1536. -        L2Character ddealer;
  1537. -        RewardInfo reward;
  1538. -
  1539. -        // While Iterating over This Map Removing Object is Not Allowed
  1540. -        synchronized (getAggroList())
  1541. -        {
  1542. -            // Go through the _aggroList of the L2Attackable
  1543. -            for (AggroInfo info : getAggroList().values())
  1544. -            {
  1545. -                if (info == null) continue;
  1546. -
  1547. -                // Get the L2Character corresponding to this attacker
  1548. -                attacker = info.attacker;
  1549. -
  1550. -
  1551. -                // Get damages done by this attacker
  1552. -                damage = info.damage;
  1553. -                
  1554. -                // Prevent unwanted behavior
  1555. -                if (damage > 1)
  1556. -                {
  1557. -                    if (attacker instanceof L2SummonInstance)
  1558. -                        ddealer = ((L2SummonInstance)attacker).getOwner();
  1559. -                    else
  1560. -                       ddealer = info.attacker;
  1561. -
  1562. -                    if (!Util.checkIfInRange(1600, this, ddealer, true))
  1563. -                        continue;
  1564. -
  1565. -
  1566. -                    // Calculate real damages (Summoners should get own damage plus summon's damage)
  1567. -                    reward = rewards.get(ddealer);
  1568. -
  1569. -
  1570. -                    if (reward == null)
  1571. -                    {
  1572. -                        reward = new RewardInfo(ddealer, damage);
  1573. -                        rewardCount++;
  1574. -                    }
  1575. -                    else
  1576. -                    {
  1577. -                        reward.addDamage(damage);
  1578. -                    }
  1579. -
  1580. -                    rewards.put(ddealer, reward);
  1581. -                }
  1582. -
  1583. -            }
  1584. -
  1585. -        }
  1586. -
  1587. -        if (!rewards.isEmpty())
  1588. -        {
  1589. -
  1590. -           L2Party attackerParty;
  1591. -
  1592. -           int exp;
  1593. -           int levelDiff;
  1594. -           int partyDmg;
  1595. -           float partyMul;
  1596. -           float penalty;
  1597. -
  1598. -           RewardInfo reward2;
  1599. -           int sp;
  1600. -           int[] tmp;
  1601. -
  1602. -            for (FastMap.Entry<L2Character, RewardInfo> entry = rewards.head(), end = rewards.tail(); (entry = entry.getNext()) != end;)
  1603. -            {
  1604. -                if (entry == null) continue;
  1605. -
  1606. -                reward = entry.getValue();
  1607. -                if(reward == null) continue;
  1608. -                
  1609. -                // Penalty applied to the attacker's XP
  1610. -                penalty = 0;
  1611. -                
  1612. -                // Attacker to be rewarded
  1613. -                attacker = reward.attacker;
  1614. -                
  1615. -                // Total amount of damage done
  1616. -                damage = reward.dmg;
  1617. -                
  1618. -                // If the attacker is a Pet, get the party of the owner
  1619. -                if (attacker instanceof L2PetInstance)
  1620. -                    attackerParty = ((L2PetInstance)attacker).getParty();
  1621. -                else if (attacker instanceof L2PcInstance)
  1622. -                   attackerParty = ((L2PcInstance)attacker).getParty();
  1623. -                else
  1624. -                    return;
  1625. -                
  1626. -                // If this attacker is a L2PcInstance with a summoned L2SummonInstance, get Exp Penalty applied for the current summoned L2SummonInstance
  1627. -                if (attacker instanceof L2PcInstance && ((L2PcInstance)attacker).getPet() instanceof L2SummonInstance)
  1628. -
  1629. -                   penalty = ((L2SummonInstance)((L2PcInstance)attacker).getPet()).getExpPenalty();
  1630. -
  1631. -                
  1632. -                // We must avoid "over damage", if any
  1633. -                if (damage > getMaxHp()) damage = getMaxHp();
  1634. -                
  1635. -                // If there's NO party in progress
  1636. -                if (attackerParty == null)
  1637. -                {
  1638. -                    // Calculate Exp and SP rewards
  1639. -                    if (attacker.getKnownList().knowsObject(this))
  1640. -                    {
  1641. -                        // Calculate the difference of level between this attacker (L2PcInstance or L2SummonInstance owner) and the L2Attackable
  1642. -                        // mob = 24, atk = 10, diff = -14 (full xp)
  1643. -                        // mob = 24, atk = 28, diff = 4 (some xp)
  1644. -                        // mob = 24, atk = 50, diff = 26 (no xp)
  1645. -                        levelDiff = attacker.getLevel() - getLevel();
  1646. -                        
  1647. -                        tmp = calculateExpAndSp(levelDiff, damage);
  1648. -                        exp = tmp[0];
  1649. -                        exp *= 1 - penalty;
  1650. -                        sp = tmp[1];
  1651. -                        
  1652. -                        // Check for an over-hit enabled strike
  1653. -                        if (attacker instanceof L2PcInstance)
  1654. -                        {
  1655. -                            L2PcInstance player = (L2PcInstance)attacker;
  1656. -                            if (isOverhit() && attacker == getOverhitAttacker())
  1657. -                            {
  1658. -                                player.sendPacket(new SystemMessage(SystemMessage.OVER_HIT));
  1659. -                                exp += calculateOverhitExp(exp);
  1660. -                            }
  1661. -                        }
  1662. -                        
  1663. -                        // Distribute the Exp and SP between the L2PcInstance and its L2Summon
  1664. -                        if (!attacker.isDead())
  1665. -                            attacker.addExpAndSp((int)Math.round(attacker.calcStat(Stats.EXPSP_RATE, exp, null, null)), (int)attacker.calcStat(Stats.EXPSP_RATE, sp, null, null));
  1666. -                    }
  1667. -                }
  1668. -                else
  1669. -                {
  1670. -                    //share with party members
  1671. -                    partyDmg = 0;
  1672. -                    partyMul = 1.f;
  1673. -                    
  1674. -                    // Get all L2Character (including L2Summon) that can be rewarded in the party
  1675. -                    List<L2Character> rewardedMembers = new FastList<L2Character>();
  1676. -                    
  1677. -                    // Go through all L2PcInstance in the party
  1678. -                    for (L2PcInstance pl : attackerParty.getPartyMembers())
  1679. -                    {
  1680. -                        if (pl == null || pl.isDead()) continue;
  1681. -
  1682. -                        // Get the RewardInfo of this L2PcInstance from L2Attackable rewards
  1683. -                        reward2 = rewards.get(pl);
  1684. -                        
  1685. -                        // If the L2PcInstance is in the L2Attackable rewards add its damages to party damages
  1686. -                        if (reward2 != null)
  1687. -                        {
  1688. -                            if (Util.checkIfInRange(1600, this, pl, true))
  1689. -                            {
  1690. -                                // Add L2PcInstance damages to party damages
  1691. -                                partyDmg += reward2.dmg;
  1692. -
  1693. -
  1694. -                                rewardedMembers.add(pl);
  1695. -                            }
  1696. -
  1697. -
  1698. -                            // Remove the L2PcInstance from the L2Attackable rewards
  1699. -                            rewards.remove(pl);
  1700. -                        }
  1701. -                        else
  1702. -                        {
  1703. -                            // Add L2PcInstance of the party (that have attacked or not) to members that can be rewarded if it's not dead
  1704. -                            // and in range of the monster.
  1705. -                            if (Util.checkIfInRange(1600, this, pl, true))
  1706. -                                rewardedMembers.add(pl);
  1707. -                        }
  1708. -
  1709. -
  1710. -
  1711. -                        L2PlayableInstance summon = pl.getPet();
  1712. -                        if (summon != null && summon instanceof L2PetInstance)
  1713. -                        {
  1714. -                            reward2 = rewards.get(summon);
  1715. -                            if (reward2 != null)
  1716. -                            {
  1717. -
  1718. -                                if (Util.checkIfInRange(1600, this, summon, true))
  1719. -                                {
  1720. -                                    partyDmg += reward2.dmg;
  1721. -                                    rewardedMembers.add(summon);
  1722. -                                }
  1723. -
  1724. -                                // Remove the summon from the L2Attackable rewards
  1725. -                                rewards.remove(summon);
  1726. -                            }
  1727. -                        }
  1728. -                    }
  1729. -                    
  1730. -                    // If the party didn't killed this L2Attackable alone
  1731. -                    if (partyDmg < getMaxHp()) partyMul = ((float)partyDmg / (float)getMaxHp());
  1732. -                    
  1733. -                    // Avoid "over damage"
  1734. -                    if (partyDmg > getMaxHp()) partyDmg = getMaxHp();
  1735. -                    
  1736. -                    // Calculate the level difference between Party and L2Attackable
  1737. -                    levelDiff = attackerParty.getLevel() - getLevel();
  1738. -                    
  1739. -                    // Calculate Exp and SP rewards
  1740. -                    tmp = calculateExpAndSp(levelDiff, partyDmg);
  1741. -                    exp = tmp[0];
  1742. -                    sp = tmp[1];
  1743. -                    
  1744. -                    exp *= partyMul;
  1745. -                    sp *= partyMul;
  1746. -                    
  1747. -                    // Check for an over-hit enabled strike
  1748. -                    // (When in party, the over-hit exp bonus is given to the whole party and splitted proportionally through the party members)
  1749. -                    if (attacker instanceof L2PcInstance)
  1750. -                    {
  1751. -                        L2PcInstance player = (L2PcInstance)attacker;
  1752. -                        if (isOverhit() && attacker == getOverhitAttacker())
  1753. -                        {
  1754. -
  1755. -
  1756. -                            player.sendPacket(new SystemMessage(SystemMessage.OVER_HIT));
  1757. -                            exp += calculateOverhitExp(exp);
  1758. -                        }
  1759. -                    }
  1760. -                    
  1761. -                    // Distribute Experience and SP rewards to L2PcInstance Party members in the known area of the last attacker
  1762. -                    if (partyDmg > 0) attackerParty.distributeXpAndSp(exp, sp, rewardedMembers, lastAttacker);
  1763. -                }
  1764. -            }
  1765. -        }
  1766. -        
  1767. -        rewards = null;
  1768. -        }
  1769. -        // Manage Base, Quests and Sweep drops of the L2Attackable
  1770. -        if (getHaveToDrop())
  1771. -            doItemDrop(lastAttacker);
  1772. -        // Manage drop of Special Events created by GM for a defined period
  1773. -        doEventDrop(lastAttacker);
  1774. -    }
  1775. -
  1776. -    /**
  1777. -     * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR><BR>
  1778. -     *
  1779. -     * @param attacker The L2Character that gave damages to this L2Attackable
  1780. -     * @param damage The number of damages given by the attacker L2Character
  1781. -     *
  1782. -     */
  1783. -    public void addDamage(L2Character attacker, int damage)
  1784. -    {
  1785. -        addDamageHate(attacker, damage, damage);
  1786. -    }
  1787. -    
  1788. -    public void addBufferHate()
  1789. -    {
  1790. -        L2Character target = getMostHated();
  1791. -
  1792. -        if (target == null)
  1793. -            return;
  1794. -
  1795. -        for (L2PcInstance actor : getKnownList().getKnownPlayers().values())
  1796. -        {
  1797. -            if (actor.isCastingNow() && target.getLastBuffer() == actor)
  1798. -            {
  1799. -                int actorLevel = actor.getLevel();
  1800. -                double divisor = 0;
  1801. -                L2Skill skill = actor.getLastSkillCast();
  1802. -                
  1803. -                if (actorLevel < 10)
  1804. -                    divisor = 15;
  1805. -                else if (actorLevel > 9 && actorLevel < 20)
  1806. -                    divisor = 11.5;
  1807. -                else if (actorLevel > 19 && actorLevel < 30)
  1808. -                    divisor = 8.5;
  1809. -                else if (actorLevel > 29 && actorLevel < 40)
  1810. -                    divisor = 6;
  1811. -                else if (actorLevel > 39 && actorLevel < 50)
  1812. -                    divisor = 4;
  1813. -                else if (actorLevel > 49 && actorLevel < 60)
  1814. -                    divisor = 2.5;
  1815. -                else if (actorLevel > 59 && actorLevel < 70)
  1816. -                    divisor = 1.5;
  1817. -                else if (actorLevel > 69)
  1818. -                    divisor = 1;
  1819. -                
  1820. -
  1821. -                if (skill != null && (skill.getSkillType() == SkillType.HEAL || skill.getSkillType() == SkillType.HEAL_PERCENT || skill.getSkillType() == SkillType.MANAHEAL || skill.getSkillType() == SkillType.BALANCE_LIFE))
  1822. -                {
  1823. -                    L2Object[] targetList = skill.getTargetList(actor,true);
  1824. -
  1825. -                    if(targetList != null && targetList.length != 0 && (targetList[0] instanceof L2PcInstance || targetList[0] instanceof L2SummonInstance || targetList[0] instanceof L2PetInstance))
  1826. -                    {
  1827. -                        if ((getMaxHp()/5) < target.getLastHealAmount())
  1828. -                            target.setLastHealAmount((getMaxHp()/5));
  1829. -                        
  1830. -                        addDamageHate(actor, 0, (int)(target.getLastHealAmount()/divisor));
  1831. -
  1832. -                        if (Config.DEBUG)
  1833. -                            System.out.print("Mob detect heal.\n");
  1834. -                    }
  1835. -                }
  1836. -
  1837. -                if (skill != null && (skill.getSkillType() == SkillType.BUFF || skill.getSkillType() == SkillType.HOT))
  1838. -                {
  1839. -                    L2Object[] targetList = skill.getTargetList(actor,true);
  1840. -
  1841. -                    if(targetList != null && targetList.length != 0 && (targetList[0] instanceof L2PcInstance || targetList[0] instanceof L2SummonInstance || targetList[0] instanceof L2PetInstance))
  1842. -                    {
  1843. -                        addDamageHate(actor, 0, (int)((skill.getLevel()*getStat().getMpConsume(skill))/divisor));
  1844. -
  1845. -                        if (Config.DEBUG)
  1846. -                            System.out.print("Mob detect buff.\n");
  1847. -                    }
  1848. -                }
  1849. -
  1850. -                if (((L2PcInstance)target).isInParty() && skill != null && skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY)
  1851. -                {
  1852. -                    List<L2PcInstance> members = ((L2PcInstance)target).getParty().getPartyMembers();
  1853. -
  1854. -                    for (L2PcInstance member : members)
  1855. -                    {
  1856. -                        if (member == actor)
  1857. -                        {
  1858. -                            if ((getMaxHp()/3) < (int)(((getHating(target)-getHating(actor))+800)/divisor))
  1859. -                                addDamageHate(actor, 0, (getMaxHp()/3));
  1860. -                            else
  1861. -                                addDamageHate(actor, 0, (int)(((getHating(target)-getHating(actor))+800)/divisor));
  1862. -
  1863. -                            if (Config.DEBUG)
  1864. -                                System.out.print("Mob detect party cast.\n");
  1865. -                        }
  1866. -                    }
  1867. -                }
  1868. -            }
  1869. -        }
  1870. -    }
  1871. -    
  1872. -    /**
  1873. -     * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR><BR>
  1874. -     *
  1875. -     * @param attacker The L2Character that gave damages to this L2Attackable
  1876. -     * @param damage The number of damages given by the attacker L2Character
  1877. -     * @param aggro The hate (=damage) given by the attacker L2Character
  1878. -     *
  1879. -     */
  1880. -    public void addDamageHate(L2Character attacker, int damage, int aggro)
  1881. -    {
  1882. -        if (attacker == null) return;
  1883. -        
  1884. -        // Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable
  1885. -        AggroInfo ai = getAggroList().get(attacker);
  1886. -        if (ai == null)
  1887. -
  1888. -        {
  1889. -
  1890. -            ai = new AggroInfo(attacker);
  1891. -            ai.damage = 0;
  1892. -            ai.hate = 0;
  1893. -
  1894. -
  1895. -
  1896. -            getAggroList().put(attacker, ai);
  1897. -        }
  1898. -
  1899. -
  1900. -        // Add new damage and aggro (=damage) to the AggroInfo object
  1901. -        ai.damage += damage;
  1902. -        ai.hate += aggro;
  1903. -
  1904. -        // Set the intention to the L2Attackable to AI_INTENTION_ACTIVE
  1905. -        if (aggro > 0 && getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE) getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  1906. -        
  1907. -        // Notify the L2Attackable AI with EVT_ATTACKED
  1908. -        if (damage > 0) getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, attacker);
  1909. -        
  1910. -        try
  1911. -        {
  1912. -            L2PcInstance player = null;
  1913. -            if (attacker instanceof L2PcInstance)
  1914. -                player = (L2PcInstance)attacker;
  1915. -            else if (attacker instanceof L2Summon)
  1916. -                player = ((L2Summon)attacker).getOwner();
  1917. -
  1918. -            if (player != null)
  1919. -            {
  1920. -
  1921. -                if (player.getQuestsForAttacks(this) != null)
  1922. -                {
  1923. -                    for (QuestState st : player.getQuestsForAttacks(this))
  1924. -                        st.getQuest().notifyAttack(this, st);
  1925. -                }
  1926. -            }
  1927. -        }
  1928. -        catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  1929. -    }
  1930. -    
  1931. -    /**
  1932. -     * Return the most hated L2Character of the L2Attackable _aggroList.<BR><BR>
  1933. -     */
  1934. -    public L2Character getMostHated()
  1935. -    {
  1936. -       if (getAggroList().isEmpty() || isAlikeDead()) return null;
  1937. -        
  1938. -        L2Character mostHated = null;
  1939. -        int maxHate = 0;
  1940. -        
  1941. -        // While Iterating over This Map Removing Object is Not Allowed
  1942. -
  1943. -        synchronized (getAggroList())
  1944. -        {
  1945. -            // Go through the aggroList of the L2Attackable
  1946. -            for (AggroInfo ai : getAggroList().values())
  1947. -            {
  1948. -                if (ai == null) continue;
  1949. -                if (ai.attacker.isAlikeDead() || !getKnownList().knowsObject(ai.attacker) ||!ai.attacker.isVisible())
  1950. -                    ai.hate = 0;
  1951. -
  1952. -
  1953. -                if (ai.hate > maxHate)
  1954. -                {
  1955. -                    mostHated = ai.attacker;
  1956. -                    maxHate = ai.hate;
  1957. -                }
  1958. -            }
  1959. -        }
  1960. -
  1961. -        return mostHated;
  1962. -    }
  1963. -
  1964. -    /**
  1965. -     * Return the hate level of the L2Attackable against this L2Character contained in _aggroList.<BR><BR>
  1966. -     *
  1967. -     * @param target The L2Character whose hate level must be returned
  1968. -     *
  1969. -     */
  1970. -    public int getHating(L2Character target)
  1971. -    {
  1972. -       if (getAggroList().isEmpty()) return 0;
  1973. -        
  1974. -        AggroInfo ai = getAggroList().get(target);
  1975. -        if (ai == null) return 0;
  1976. -
  1977. -        if (ai.attacker instanceof L2PcInstance && (((L2PcInstance)ai.attacker).getInvisible() == 1 || ai.attacker.isInvul()))
  1978. -        {
  1979. -                //Remove Object Should Use This Method and Can be Blocked While Iterating
  1980. -           getAggroList().remove(target);
  1981. -           return 0;
  1982. -        }
  1983. -        if (!ai.attacker.isVisible())
  1984. -        {
  1985. -           getAggroList().remove(target);
  1986. -                return 0;
  1987. -        }
  1988. -        if (ai.attacker.isAlikeDead())
  1989. -        {
  1990. -            ai.hate = 0;
  1991. -            return 0;
  1992. -        }
  1993. -
  1994. -        return ai.hate;
  1995. -    }
  1996. -
  1997. -    /**
  1998. -     * Calculates quantity of items for specific drop acording to current situation <br>
  1999. -     *
  2000. -     * @param drop The L2DropData count is being calculated for
  2001. -     * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  2002. -     * @param deepBlueDrop Factor to divide the drop chance
  2003. -     * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  2004. -     */
  2005. -     private RewardItem calculateRewardItem(L2PcInstance lastAttacker, L2DropData drop, int levelModifier)
  2006. -     {
  2007. -         // Get default drop chance
  2008. -         float dropChance = drop.getChance();
  2009. -
  2010. -         float dropItemsRate;
  2011. -         if (this instanceof L2BossInstance || this instanceof L2RaidBossInstance)
  2012. -             dropItemsRate = Config.RATE_BOSS_DROP_ITEMS;
  2013. -         else
  2014. -             dropItemsRate = Config.RATE_DROP_ITEMS;
  2015. -
  2016. -         int deepBlueDrop = 1;
  2017. -         if (Config.DEEPBLUE_DROP_RULES)
  2018. -         {
  2019. -             if (levelModifier > 0)
  2020. -             {
  2021. -                 // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  2022. -                 // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  2023. -                 deepBlueDrop = 3;
  2024. -                 if (drop.getItemId() == 57) deepBlueDrop *= (int)dropItemsRate;
  2025. -             }
  2026. -         }
  2027. -        
  2028. -         if(deepBlueDrop == 0) //avoid div by 0
  2029. -            deepBlueDrop = 1;
  2030. -         // Check if we should apply our maths so deep blue mobs will not drop that easy
  2031. -         if (Config.DEEPBLUE_DROP_RULES) dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier)/100)) / deepBlueDrop);
  2032. -
  2033. -         // Applies Drop rates
  2034. -         if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA;
  2035. -         else if (drop.isSweep()) dropChance *= Config.RATE_DROP_SPOIL;
  2036. -         else dropChance *= dropItemsRate;
  2037. -
  2038. -         // Round drop chance
  2039. -         dropChance = Math.round(dropChance);
  2040. -
  2041. -         // Set our limits for chance of drop
  2042. -         if (dropChance < 1) dropChance = 1;
  2043. -//         if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time
  2044. -
  2045. -         // Get min and max Item quantity that can be dropped in one time
  2046. -         int minCount = drop.getMinDrop();
  2047. -         int maxCount = drop.getMaxDrop();
  2048. -         int itemCount = 0;
  2049. -
  2050. -         // Count and chance adjustment for high rate servers
  2051. -         if (dropChance > L2DropData.MAX_CHANCE && !Config.PRECISE_DROP_CALCULATION)
  2052. -         {
  2053. -             int multiplicator = (int)dropChance / L2DropData.MAX_CHANCE;
  2054. -             if (minCount < maxCount) itemCount += Rnd.get(minCount * multiplicator, maxCount * multiplicator);
  2055. -             else if (minCount == maxCount) itemCount += minCount * multiplicator;
  2056. -             else itemCount += multiplicator;
  2057. -
  2058. -             dropChance = dropChance % L2DropData.MAX_CHANCE;
  2059. -         }
  2060. -
  2061. -         // Check if the Item must be dropped
  2062. -         int random = Rnd.get(L2DropData.MAX_CHANCE);
  2063. -         while (random < dropChance)
  2064. -         {
  2065. -             // Get the item quantity dropped
  2066. -             if (minCount < maxCount) itemCount += Rnd.get(minCount, maxCount);
  2067. -             else if (minCount == maxCount) itemCount += minCount;
  2068. -             else itemCount++;
  2069. -
  2070. -             // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  2071. -             dropChance -= L2DropData.MAX_CHANCE;
  2072. -         }
  2073. -
  2074. -         if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount);
  2075. -         else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop...");
  2076. -
  2077. -         return null;
  2078. -     }
  2079. -
  2080. -     /**
  2081. -      * Calculates quantity of items for specific drop CATEGORY according to current situation <br>
  2082. -      * Only a max of ONE item from a category is allowed to be dropped.
  2083. -      *
  2084. -      * @param drop The L2DropData count is being calculated for
  2085. -      * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  2086. -      * @param deepBlueDrop Factor to divide the drop chance
  2087. -      * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  2088. -      */
  2089. -      private RewardItem calculateCategorizedRewardItem(L2PcInstance lastAttacker, List<L2DropData> categoryDrops, int levelModifier)
  2090. -      {
  2091. -            if ((categoryDrops == null) || (categoryDrops.size() == 0))
  2092. -                return null;
  2093. -        
  2094. -          // Get default drop chance for the category (that's the sum of chances for all items in the category)
  2095. -          // keep track of the base category chance as it'll be used later, if an item is drop from the category.
  2096. -          // for everything else, use the total "categoryDropChance"
  2097. -          int basecategoryDropChance = 0;          
  2098. -          int categoryDropChance = 0;          
  2099. -          for (L2DropData drop : categoryDrops)
  2100. -              basecategoryDropChance += drop.getChance();
  2101. -          categoryDropChance = basecategoryDropChance;
  2102. -
  2103. -          int deepBlueDrop = 1;
  2104. -          if (Config.DEEPBLUE_DROP_RULES)
  2105. -          {
  2106. -              if (levelModifier > 0)
  2107. -              {
  2108. -                  // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  2109. -                  // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  2110. -                  deepBlueDrop = 3;
  2111. -              }
  2112. -          }
  2113. -          
  2114. -          if(deepBlueDrop == 0) //avoid div by 0
  2115. -           deepBlueDrop = 1;
  2116. -          // Check if we should apply our maths so deep blue mobs will not drop that easy
  2117. -          if (Config.DEEPBLUE_DROP_RULES) categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier)/100)) / deepBlueDrop);
  2118. -
  2119. -          // Applies Drop rates
  2120. -          if (this instanceof L2BossInstance || this instanceof L2RaidBossInstance)
  2121. -              categoryDropChance *= Config.RATE_BOSS_DROP_ITEMS;
  2122. -          else
  2123. -              categoryDropChance *= Config.RATE_DROP_ITEMS;
  2124. -
  2125. -          // Round drop chance
  2126. -          categoryDropChance = Math.round(categoryDropChance);
  2127. -
  2128. -          // Set our limits for chance of drop
  2129. -          if (categoryDropChance < 1) categoryDropChance = 1;
  2130. -
  2131. -          // Check if an Item from this category must be dropped
  2132. -          if (Rnd.get(L2DropData.MAX_CHANCE) < categoryDropChance)
  2133. -          {
  2134. -            // ONE of the drops in this category is to be dropped now.  
  2135. -            // to see which one will be dropped, weight all items' chances such that
  2136. -            // their sum of chances equals MAX_CHANCE.
  2137. -            // since the individual drops have their base chance, we also ought to use the
  2138. -            // base category chance for the weight.  So weight = MAX_CHANCE/basecategoryDropChance.  
  2139. -            // Then get a single random number within this range.  The first item
  2140. -            // (in order of the list) whose contribution to the sum makes the
  2141. -            // sum greater than the random number, will be dropped.
  2142. -            int randomIndex = Rnd.get(L2DropData.MAX_CHANCE);
  2143. -            double sum = 0.0;
  2144. -            double weight = ((double)(L2DropData.MAX_CHANCE))/basecategoryDropChance;
  2145. -              for (L2DropData drop : categoryDrops)
  2146. -              {
  2147. -                sum = sum + (drop.getChance()*weight);
  2148. -                
  2149. -                if(Config.DEBUG)
  2150. -                    _log.info("sum so far: "+sum);
  2151. -                
  2152. -                if (sum >= randomIndex)       // drop this item and exit the function
  2153. -                {
  2154. -                      // Get min and max Item quantity that can be dropped in one time
  2155. -                      int min = drop.getMinDrop();
  2156. -                      int max = drop.getMaxDrop();
  2157. -
  2158. -                      // Get the item quantity dropped
  2159. -                      int itemCount = 0;
  2160. -                      if (min < max)
  2161. -                          itemCount += Rnd.get(min, max);
  2162. -                      else if (min == max)
  2163. -                          itemCount += min;
  2164. -                      else
  2165. -                          itemCount++;
  2166. -                      
  2167. -                      if (itemCount > 0)
  2168. -                          return new RewardItem(drop.getItemId(), itemCount);
  2169. -                      else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop...");
  2170. -                }
  2171. -              }
  2172. -          }
  2173. -          return null;
  2174. -      }
  2175. -    
  2176. -     /**
  2177. -      * Calculates the level modifier for drop<br>
  2178. -      *
  2179. -      * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  2180. -      */
  2181. -     private int calculateLevelModifierForDrop(L2PcInstance lastAttacker)
  2182. -     {
  2183. -         if (Config.DEEPBLUE_DROP_RULES)
  2184. -         {
  2185. -             int highestLevel = lastAttacker.getLevel();
  2186. -
  2187. -             // Check to prevent very high level player to nearly kill mob and let low level player do the last hit.
  2188. -             if (getAttackByList() != null && !getAttackByList().isEmpty())
  2189. -             {
  2190. -                 for (L2Character atkChar: getAttackByList())
  2191. -                     if (atkChar != null && atkChar.getLevel() > highestLevel) highestLevel = atkChar.getLevel();
  2192. -             }
  2193. -
  2194. -             // According to official data (Prima), deep blue mobs are 9 or more levels below players
  2195. -             if (highestLevel - 9 >= getLevel()) return ((highestLevel - (getLevel() + 8)) * 9);
  2196. -         }
  2197. -
  2198. -         return 0;
  2199. -     }
  2200. -
  2201. -     public void doItemDrop(L2Character lastAttacker)
  2202. -     {
  2203. -         doItemDrop(getTemplate(),lastAttacker);
  2204. -     }
  2205. -
  2206. -     /**
  2207. -      * Manage Base, Quests and Special Events drops of L2Attackable (called by calculateRewards).<BR><BR>
  2208. -      *  
  2209. -      * <B><U> Concept</U> :</B><BR><BR>
  2210. -      * During a Special Event all L2Attackable can drop extra Items.
  2211. -      * Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist.
  2212. -      * Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR><BR>
  2213. -      *
  2214. -      * <B><U> Actions</U> : </B><BR><BR>
  2215. -      * <li>Manage drop of Special Events created by GM for a defined period </li>
  2216. -      * <li>Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops</li>
  2217. -      * <li>For each possible drops (base + quests), calculate which one must be dropped (random) </li>
  2218. -      * <li>Get each Item quantity dropped (random) </li>
  2219. -      * <li>Create this or these L2ItemInstance corresponding to each Item Identifier dropped</li>
  2220. -      * <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>
  2221. -      * <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><BR><BR>
  2222. -      *
  2223. -      * @param lastAttacker The L2Character that has killed the L2Attackable
  2224. -      */
  2225. -     public void doItemDrop(L2NpcTemplate npcTemplate, L2Character lastAttacker)
  2226. -     {
  2227. -         L2PcInstance player = null;
  2228. -         if (lastAttacker instanceof L2PcInstance) player = (L2PcInstance)lastAttacker;
  2229. -         else if (lastAttacker instanceof L2Summon) player = ((L2Summon)lastAttacker).getOwner();
  2230. -
  2231. -         if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  2232. -
  2233. -         int levelModifier = calculateLevelModifierForDrop(player);          // level modifier in %'s (will be subtracted from drop chance)
  2234. -        
  2235. -         // Create a table containing all possible drops of this L2Attackable from L2NpcTemplate
  2236. -         List<L2DropData> drops = new FastList<L2DropData>();
  2237. -         drops.addAll(npcTemplate.getDropData());
  2238. -         if (Config.DEBUG) _log.finer("this npc has "+drops.size()+" drops defined");
  2239. -
  2240. -         // Add Quest drops to the table containing all possible drops of this L2Attackable
  2241. -         player.fillQuestDrops(this, drops);
  2242. -        
  2243. -         List<RewardItem> sweepList = new FastList<RewardItem>();
  2244. -         // Go Throw all possible drops (base + quests) of this L2Attackable
  2245. -         // This includes all spoil, plus adena, sealstone, quest, Raidboss, and all other drops that
  2246. -         // should NOT follow the rule of 1 drop per category per kill
  2247. -         for (L2DropData drop : drops)
  2248. -         {
  2249. -             if (drop == null) continue;
  2250. -
  2251. -             RewardItem item = calculateRewardItem(player, drop, levelModifier);
  2252. -             if (item == null) continue;
  2253. -            
  2254. -             if (drop.isSweep())
  2255. -             {
  2256. -                if (!isSpoil()) continue; // L2Attackable was not spoiled, skip sweep drop
  2257. -                 if (Config.DEBUG) _log.fine("Item id to spoil: " + item.getItemId() + " amount: " + item.getCount());
  2258. -                sweepList.add(item);
  2259. -             }
  2260. -             else
  2261. -             {
  2262. -                if (isSeeded() && item.getItemId() != 57) continue; // L2Attackable was seeded, don't ropd other than adena
  2263. -                 if (Config.DEBUG) _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  2264. -                
  2265. -                 // Check if the autoLoot mode is active
  2266. -                 if (Config.AUTO_LOOT)
  2267. -                     player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  2268. -                 else
  2269. -                     dropItem(player, item); // drop the item on the ground
  2270. -
  2271. -                 // Broadcast message if RaidBoss was defeated
  2272. -                 if (this instanceof L2RaidBossInstance)
  2273. -                 {
  2274. -                     SystemMessage sm;
  2275. -                     sm = new SystemMessage(SystemMessage.S1_DIED_DROPPED_S3_S2);
  2276. -                     sm.addString(getName());
  2277. -                     sm.addItemName(item.getItemId());
  2278. -                     sm.addNumber(item.getCount());
  2279. -                     broadcastPacket(sm);
  2280. -                 }
  2281. -             }
  2282. -         }
  2283. -
  2284. -         if (!isSeeded())
  2285. -         {
  2286. -             RewardItem item = calculateCategorizedRewardItem(player, npcTemplate.getFullDropData(), levelModifier);
  2287. -             if (item != null)
  2288. -             {
  2289. -                 if (Config.DEBUG) _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  2290. -                
  2291. -                 // Check if the autoLoot mode is active
  2292. -                 if (Config.AUTO_LOOT)
  2293. -                     player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  2294. -                 else
  2295. -                     dropItem(player, item); // drop the item on the ground
  2296. -             }
  2297. -
  2298. -             item = calculateCategorizedRewardItem(player, npcTemplate.getMiscDropData(), levelModifier);
  2299. -             if (item != null)
  2300. -             {
  2301. -                 if (Config.DEBUG) _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  2302. -                
  2303. -                 // Check if the autoLoot mode is active
  2304. -                 if (Config.AUTO_LOOT)
  2305. -                     player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  2306. -                 else
  2307. -                     dropItem(player, item); // drop the item on the ground
  2308. -             }
  2309. -         }
  2310. -
  2311. -
  2312. -         // Set the table _sweepItems of this L2Attackable
  2313. -         if (!sweepList.isEmpty())
  2314. -             _sweepItems = sweepList.toArray(new RewardItem[sweepList.size()]);
  2315. -     }
  2316. -    
  2317. -     /**
  2318. -      * Manage Special Events drops created by GM for a defined period.<BR><BR>
  2319. -      *  
  2320. -      * <B><U> Concept</U> :</B><BR><BR>
  2321. -      * During a Special Event all L2Attackable can drop extra Items.
  2322. -      * Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist.
  2323. -      * Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR><BR>
  2324. -      *
  2325. -      * <B><U> Actions</U> : <I>If an extra drop must be generated</I></B><BR><BR>
  2326. -      * <li>Get an Item Identifier (random) from the DateDrop Item table of this Event </li>
  2327. -      * <li>Get the Item quantity dropped (random) </li>
  2328. -      * <li>Create this or these L2ItemInstance corresponding to this Item Identifier</li>
  2329. -      * <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>
  2330. -      * <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><BR><BR>
  2331. -      *
  2332. -      * @param lastAttacker The L2Character that has killed the L2Attackable
  2333. -      */
  2334. -     public void doEventDrop(L2Character lastAttacker)
  2335. -     {
  2336. -         L2PcInstance player = null;
  2337. -         if (lastAttacker instanceof L2PcInstance)
  2338. -             player = (L2PcInstance)lastAttacker;
  2339. -         else if (lastAttacker instanceof L2Summon)
  2340. -             player = ((L2Summon)lastAttacker).getOwner();
  2341. -
  2342. -         if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  2343. -        
  2344. -         if (player.getLevel() - getLevel() > 9) return;
  2345. -        
  2346. -         // Go through DateDrop of EventDroplist allNpcDateDrops within the date range
  2347. -         for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
  2348. -         {
  2349. -             if (Rnd.get(L2DropData.MAX_CHANCE) < drop.chance)
  2350. -             {
  2351. -                 RewardItem item = new RewardItem(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
  2352. -                 if (Config.AUTO_LOOT)
  2353. -                     player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  2354. -                 else
  2355. -                     dropItem(player, item); // drop the item on the ground
  2356. -             }
  2357. -         }
  2358. -     }
  2359. -    
  2360. -     /**
  2361. -      * Drop reward item.<BR><BR>
  2362. -      */
  2363. -     public L2ItemInstance dropItem(L2PcInstance lastAttacker, RewardItem item)
  2364. -     {
  2365. -         int randDropLim = 70;
  2366. -
  2367. -         L2ItemInstance ditem = null;
  2368. -         for (int i = 0; i < item.getCount(); i++)
  2369. -         {
  2370. -             // Randomize drop position  
  2371. -             int newX = getX() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  2372. -             int newY = getY() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  2373. -             int newZ = Math.max(getZ(), lastAttacker.getZ()) + 20; // TODO: temp hack, do something nicer when we have geodatas
  2374. -
  2375. -             // Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last
  2376. -             ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), lastAttacker, this);
  2377. -             ditem.dropMe(this, newX, newY, newZ);
  2378. -
  2379. -             // Add drop to auto destroy item task
  2380. -             if (!Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
  2381. -             {
  2382. -                 if (Config.AUTODESTROY_ITEM_AFTER > 0)
  2383. -                     ItemsAutoDestroy.getInstance().addItem(ditem);
  2384. -             }
  2385. -             ditem.setProtected(false);
  2386. -             // If stackable, end loop as entire count is included in 1 instance of item  
  2387. -             if (ditem.isStackable() || !Config.MULTIPLE_ITEM_DROP) break;
  2388. -         }
  2389. -         return ditem;
  2390. -     }
  2391. -
  2392. -    public L2ItemInstance dropItem(L2PcInstance lastAttacker, int itemId, int itemCount)
  2393. -    {
  2394. -        return dropItem(lastAttacker, new RewardItem(itemId, itemCount));
  2395. -    }
  2396. -
  2397. -    /**
  2398. -     * Return the active weapon of this L2Attackable (= null).<BR><BR>
  2399. -     */
  2400. -    public L2ItemInstance getActiveWeapon()
  2401. -    {
  2402. -        return null;
  2403. -    }
  2404. -    
  2405. -    /**
  2406. -     * Return True if the _aggroList of this L2Attackable is Empty.<BR><BR>
  2407. -     */
  2408. -    public boolean noTarget()
  2409. -    {
  2410. -       return getAggroList().isEmpty();
  2411. -    }
  2412. -    
  2413. -    /**
  2414. -     * Return True if the _aggroList of this L2Attackable contains the L2Character.<BR><BR>
  2415. -     *
  2416. -     * @param player The L2Character searched in the _aggroList of the L2Attackable
  2417. -     *
  2418. -     */
  2419. -    public boolean containsTarget(L2Character player)
  2420. -    {
  2421. -       return getAggroList().containsKey(player);
  2422. -    }
  2423. -    
  2424. -    /**
  2425. -     * Clear the _aggroList of the L2Attackable.<BR><BR>
  2426. -     */
  2427. -    public void clearAggroList()
  2428. -    {
  2429. -       getAggroList().clear();
  2430. -
  2431. -        _overhit = false;
  2432. -        _overhitDamage = 0;
  2433. -        _overhitAttacker = null;
  2434. -    }
  2435. -
  2436. -    /**
  2437. -     * Clears _aggroList hate of the L2Character without removing from the list.<BR><BR>
  2438. -     */
  2439. -    public void clearHating(L2Character target)
  2440. -    {
  2441. -        if (getAggroList().isEmpty()) return;
  2442. -        AggroInfo ai = getAggroList().get(target);
  2443. -        if (ai == null) return;
  2444. -        ai.hate = 0;
  2445. -    }
  2446. -
  2447. -    /**
  2448. -     * Return True if a Dwarf use Sweep on the L2Attackable and if item can be spoiled.<BR><BR>
  2449. -     */
  2450. -    public boolean isSweepActive()
  2451. -    {
  2452. -        return _sweepItems != null;
  2453. -    }
  2454. -    
  2455. -    /**
  2456. -     * Return table containing all L2ItemInstance that can be spoiled.<BR><BR>
  2457. -     */
  2458. -    public synchronized RewardItem[] takeSweep()
  2459. -    {
  2460. -       RewardItem[] sweep = _sweepItems;
  2461. -        
  2462. -        _sweepItems = null;
  2463. -        
  2464. -        return sweep;
  2465. -    }
  2466. -    
  2467. -    /**
  2468. -     * Return table containing all L2ItemInstance that can be harvested.<BR><BR>
  2469. -     */
  2470. -    public synchronized RewardItem[] takeHarvest()
  2471. -    {
  2472. -       RewardItem[] harvest = _harvestItems;
  2473. -         _harvestItems = null;
  2474. -         return harvest;
  2475. -    }
  2476. -    
  2477. -    /**
  2478. -     * Set the over-hit flag on the L2Attackable.<BR><BR>
  2479. -     *
  2480. -     * @param status The status of the over-hit flag
  2481. -     *
  2482. -     */
  2483. -    public void overhitEnabled(boolean status)
  2484. -    {
  2485. -        _overhit = status;
  2486. -    }
  2487. -    
  2488. -    /**
  2489. -     * Set the over-hit values like the attacker who did the strike and the ammount of damage done by the skill.<BR><BR>
  2490. -     *
  2491. -     * @param attacker The L2Character who hit on the L2Attackable using the over-hit enabled skill
  2492. -     * @param damage The ammount of damage done by the over-hit enabled skill on the L2Attackable
  2493. -     *
  2494. -     */
  2495. -    public void setOverhitValues(L2Character attacker, double damage)
  2496. -    {
  2497. -        // Calculate the over-hit damage
  2498. -        // Ex: mob had 10 HP left, over-hit skill did 50 damage total, over-hit damage is 40
  2499. -        double overhitDmg = ((getCurrentHp() - damage) * (-1));
  2500. -        if (overhitDmg < 0)
  2501. -        {
  2502. -            // we didn't killed the mob with the over-hit strike. (it wasn't really an over-hit strike)
  2503. -            // let's just clear all the over-hit related values
  2504. -            overhitEnabled(false);
  2505. -            _overhitDamage = 0;
  2506. -            _overhitAttacker = null;
  2507. -            return;
  2508. -        }
  2509. -        overhitEnabled(true);
  2510. -        _overhitDamage = overhitDmg;
  2511. -        _overhitAttacker = attacker;
  2512. -    }
  2513. -    
  2514. -    /**
  2515. -     * Return the L2Character who hit on the L2Attackable using an over-hit enabled skill.<BR><BR>
  2516. -     *
  2517. -     * @return L2Character attacker
  2518. -     */
  2519. -    public L2Character getOverhitAttacker()
  2520. -    {
  2521. -        return _overhitAttacker;
  2522. -    }
  2523. -    
  2524. -    /**
  2525. -     * Return the ammount of damage done on the L2Attackable using an over-hit enabled skill.<BR><BR>
  2526. -     *
  2527. -     * @return double damage
  2528. -     */
  2529. -    public double getOverhitDamage()
  2530. -    {
  2531. -        return _overhitDamage;
  2532. -    }
  2533. -    
  2534. -    /**
  2535. -     * Return True if the L2Attackable was hit by an over-hit enabled skill.<BR><BR>
  2536. -     */
  2537. -    public boolean isOverhit()
  2538. -    {
  2539. -        return _overhit;
  2540. -    }
  2541. -    
  2542. -    /**
  2543. -     * Activate the absorbed soul condition on the L2Attackable.<BR><BR>
  2544. -     */
  2545. -    public void absorbSoul()
  2546. -    {
  2547. -        _absorbed = true;
  2548. -    }
  2549. -    
  2550. -    /**
  2551. -     * Return True if the L2Attackable had his soul absorbed.<BR><BR>
  2552. -     */
  2553. -    public boolean isAbsorbed()
  2554. -    {
  2555. -        return _absorbed;
  2556. -    }
  2557. -    
  2558. -    /**
  2559. -     * Adds an attacker that successfully absorbed the soul of this L2Attackable into the _absorbersList.<BR><BR>
  2560. -     *
  2561. -     * params:  attacker    - a valid L2PcInstance
  2562. -     *          condition   - an integer indicating the event when mob dies. This should be:
  2563. -     *                          = 0     - "the crystal scatters";
  2564. -     *                          = 1     - "the crystal failed to absorb. nothing happens";
  2565. -     *                          = 2     - "the crystal resonates because you got more than 1 crystal on you";
  2566. -     *                          = 3     - "the crystal cannot absorb the soul because the mob level is too low";
  2567. -     *                          = 4     - "the crystal successfuly absorbed the soul";
  2568. -     */
  2569. -    public void addAbsorber(L2PcInstance attacker, int crystalId)
  2570. -    {
  2571. -        // This just works for targets like L2MonsterInstance
  2572. -        if (!(this instanceof L2MonsterInstance))
  2573. -            return;
  2574. -        
  2575. -        // The attacker must not be null
  2576. -        if (attacker == null)
  2577. -            return;
  2578. -        
  2579. -        // This L2Attackable must be of one type in the _absorbingMOBS_levelXX tables.
  2580. -        // OBS: This is done so to avoid triggering the absorbed conditions for mobs that can't be absorbed.
  2581. -        if (getAbsorbLevel() == 0)
  2582. -            return;
  2583. -        
  2584. -        // If we have no _absorbersList initiated, do it
  2585. -        AbsorberInfo ai = _absorbersList.get(attacker);
  2586. -
  2587. -
  2588. -        // If the L2Character attacker isn't already in the _absorbersList of this L2Attackable, add it
  2589. -        if (ai == null)
  2590. -        {
  2591. -            ai = new AbsorberInfo(attacker, crystalId, getCurrentHp());
  2592. -            _absorbersList.put(attacker, ai);
  2593. -        }
  2594. -        else
  2595. -        {
  2596. -            ai.absorber = attacker;
  2597. -            ai.crystalId = crystalId;
  2598. -            ai.absorbedHP = getCurrentHp();
  2599. -        }
  2600. -        
  2601. -        // Set this L2Attackable as absorbed
  2602. -        absorbSoul();
  2603. -    }
  2604. -    
  2605. -    /**
  2606. -     * Calculate the leveling chance of Soul Crystals based on the attacker that killed this L2Attackable
  2607. -     *
  2608. -     * @param attacker The player that last killed this L2Attackable
  2609. -     * $ Rewrite 06.12.06 - Yesod
  2610. -     */
  2611. -    private void levelSoulCrystals(L2Character attacker)
  2612. -    {
  2613. -        // Only L2PcInstance can absorb a soul
  2614. -        if (!(attacker instanceof L2PcInstance))
  2615. -        {
  2616. -            resetAbsorbList(); return;
  2617. -        }
  2618. -                
  2619. -        int maxAbsorbLevel = getAbsorbLevel();
  2620. -        int minAbsorbLevel = 0;
  2621. -        
  2622. -        // If this is not a valid L2Attackable, clears the _absorbersList and just return
  2623. -        if (maxAbsorbLevel == 0)
  2624. -        {
  2625. -            resetAbsorbList(); return;
  2626. -        }
  2627. -        // All boss mobs with maxAbsorbLevel 13 have minAbsorbLevel of 12 else 10
  2628. -        if (maxAbsorbLevel > 10)
  2629. -            minAbsorbLevel = maxAbsorbLevel > 12 ? 12 : 10;
  2630. -        
  2631. -        //Init some useful vars  
  2632. -        boolean isSuccess = true;
  2633. -        boolean doLevelup = true;
  2634. -        boolean isBossMob = maxAbsorbLevel > 10 ? true : false;        
  2635. -        
  2636. -        L2PcInstance killer = (L2PcInstance)attacker;
  2637. -        
  2638. -        // If this mob is a boss, then skip some checkings
  2639. -        if (!isBossMob)
  2640. -        {
  2641. -            // Fail if this L2Attackable isn't absorbed or there's no one in its _absorbersList
  2642. -            if (!isAbsorbed() /*|| _absorbersList == null*/)
  2643. -            {
  2644. -                resetAbsorbList();
  2645. -                return;
  2646. -            }
  2647. -            
  2648. -            // Fail if the killer isn't in the _absorbersList of this L2Attackable and mob is not boss
  2649. -            AbsorberInfo ai = _absorbersList.get(killer);
  2650. -            if (ai == null || ai.absorber.getObjectId() != killer.getObjectId())
  2651. -                isSuccess = false;
  2652. -            
  2653. -            // Check if the soul crystal was used when HP of this L2Attackable wasn't higher than half of it
  2654. -            if (ai != null && ai.absorbedHP > (getMaxHp()/2))
  2655. -                isSuccess = false;
  2656. -            
  2657. -            if (!isSuccess) {            
  2658. -                resetAbsorbList();
  2659. -                return;
  2660. -            }
  2661. -        }
  2662. -        
  2663. -        // ********
  2664. -        String[] crystalNFO = null;
  2665. -        String   crystalNME = "";
  2666. -        
  2667. -        int dice = Rnd.get(100);
  2668. -        int crystalQTY = 0;
  2669. -        int crystalLVL = 0;
  2670. -        int crystalOLD = 0;
  2671. -        int crystalNEW = 0;
  2672. -        
  2673. -        // ********
  2674. -        // Now we have four choices:
  2675. -        // 1- The Monster level is too low for the crystal. Nothing happens.
  2676. -        // 2- Everything is correct, but it failed. Nothing happens. (57.5%)
  2677. -        // 3- Everything is correct, but it failed. The crystal scatters. A sound event is played. (10%)
  2678. -        // 4- Everything is correct, the crystal level up. A sound event is played. (32.5%)
  2679. -        
  2680. -        List<L2PcInstance> players = new FastList<L2PcInstance>();        
  2681. -                
  2682. -        if (isBossMob && killer.isInParty())
  2683. -            players = killer.getParty().getPartyMembers();
  2684. -        else
  2685. -            players.add(killer);
  2686. -        
  2687. -        for (L2PcInstance player : players)
  2688. -        {
  2689. -            if (player == null)
  2690. -                continue;
  2691. -
  2692. -            QuestState qs = player.getQuestState("350_EnhanceYourWeapon");
  2693. -            if (qs == null || !qs.isStarted())
  2694. -                continue;
  2695. -
  2696. -
  2697. -
  2698. -            crystalQTY = 0;
  2699. -
  2700. -            L2ItemInstance[] inv = player.getInventory().getItems();
  2701. -            for (L2ItemInstance item : inv)
  2702. -            {
  2703. -                int itemId = item.getItemId();
  2704. -                for (int id : SoulCrystal.SoulCrystalTable)
  2705. -                {
  2706. -                    // Find any of the 39 possible crystals.
  2707. -                    if (id == itemId)
  2708. -                    {
  2709. -                        crystalQTY++;
  2710. -                        // Keep count but make sure the player has no more than 1 crystal
  2711. -                        if (crystalQTY > 1)
  2712. -                        {
  2713. -                            isSuccess = false; break;
  2714. -                        }
  2715. -
  2716. -                        // Validate if the crystal has already leveled
  2717. -                        if(id != SoulCrystal.RED_NEW_CRYSTAL
  2718. -                        && id != SoulCrystal.GRN_NEW_CYRSTAL
  2719. -                        && id != SoulCrystal.BLU_NEW_CRYSTAL)
  2720. -                        {
  2721. -                            try
  2722. -                            {
  2723. -                                if (item.getItem().getName().contains("Grade"))
  2724. -                                {
  2725. -                                        // Split the name of the crystal into 'name' & 'level'
  2726. -                                        crystalNFO = item.getItem().getName().trim().replace(" Grade ", "-").split("-");
  2727. -                                        // Set Level to 13
  2728. -                                        crystalLVL = 13;
  2729. -                                        // Get Name
  2730. -                                        crystalNME = crystalNFO[0].toLowerCase();
  2731. -                                }
  2732. -                                else
  2733. -                                {
  2734. -                                        // Split the name of the crystal into 'name' & 'level'
  2735. -                                        crystalNFO = item.getItem().getName().trim().replace(" Stage ", "").split("-");
  2736. -                                        // Get Level
  2737. -                                        crystalLVL = Integer.parseInt(crystalNFO[1].trim());
  2738. -                                        // Get Name
  2739. -                                        crystalNME  = crystalNFO[0].toLowerCase();
  2740. -                                }
  2741. -                                // Allocate current and levelup ids' for higher level crystals
  2742. -                                if(crystalLVL > 9)
  2743. -                                {
  2744. -                                    for(int i = 0; i < SoulCrystal.HighSoulConvert.length; i++)
  2745. -                                        // Get the next stage above 10 using array.
  2746. -                                        if(id == SoulCrystal.HighSoulConvert[i][0])
  2747. -                                        {
  2748. -                                            crystalNEW = SoulCrystal.HighSoulConvert[i][1]; break;
  2749. -                                        }
  2750. -                                }
  2751. -                                else
  2752. -                                    crystalNEW = id+1;
  2753. -                            }
  2754. -                            catch (NumberFormatException nfe)
  2755. -                            {
  2756. -                                _log.log(Level.WARNING, "An attempt to identify a soul crystal failed, " +
  2757. -                                                        "verify the names have not changed in etcitem "  +
  2758. -                                                        "table.", nfe);
  2759. -                                
  2760. -                                player.sendMessage("There has been an error handling your soul crystal." +
  2761. -                                                   " Please notify your server admin.");
  2762. -                                
  2763. -                                isSuccess = false;
  2764. -                                break;
  2765. -                            }
  2766. -                            catch (Exception e)
  2767. -                            {
  2768. -                                e.printStackTrace();
  2769. -                                isSuccess = false;
  2770. -                                break;
  2771. -                            }
  2772. -                        }
  2773. -                        else
  2774. -                        {
  2775. -                            crystalNME = item.getItem().getName().toLowerCase().trim();
  2776. -                            crystalNEW = id+1;
  2777. -                        }
  2778. -                        
  2779. -                        // Done
  2780. -                        crystalOLD = id;                                
  2781. -                        break;
  2782. -                    }
  2783. -                }
  2784. -                if (!isSuccess) break;
  2785. -            }
  2786. -          
  2787. -            // If the crystal level is way too high for this mob, say that we can't increase it
  2788. -            if ((crystalLVL < minAbsorbLevel) || (crystalLVL >= maxAbsorbLevel))
  2789. -                doLevelup = false;
  2790. -
  2791. -            // The player doesn't have any crystals with him get to the next player.
  2792. -            if (crystalQTY < 1 || crystalQTY > 1 || !isSuccess || !doLevelup)
  2793. -            {
  2794. -                // Too many crystals in inventory.
  2795. -                if  (crystalQTY > 1)
  2796. -                {
  2797. -                    player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_FAILED_RESONATION));
  2798. -                }
  2799. -                // The soul crystal stage of the player is way too high
  2800. -                else if (!doLevelup && crystalQTY > 0)
  2801. -                    player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_REFUSED));
  2802. -                
  2803. -                crystalQTY = 0;
  2804. -                continue;
  2805. -            }
  2806. -                        
  2807. -            // Ember and Anakazel(78) are not 100% success rate and each individual
  2808. -            // member of the party has a failure rate on leveling.          
  2809. -            if(isBossMob && (getNpcId() == 10319 || getNpcId() == 10338))
  2810. -                doLevelup = false;
  2811. -            
  2812. -            // If succeeds or it is a boss mob, level up the crystal.
  2813. -            if ((isBossMob && doLevelup) || (dice <= SoulCrystal.LEVEL_CHANCE))
  2814. -            {
  2815. -                // Give staged crystal
  2816. -                exchangeCrystal(player, crystalOLD, crystalNEW, false);
  2817. -            }
  2818. -            // If true and not a boss mob, break the crystal.
  2819. -            else if (!isBossMob && dice >= (100.0 - SoulCrystal.BREAK_CHANCE))
  2820. -            {
  2821. -                // Remove current crystal an give a broken open.
  2822. -                if (crystalNME.startsWith("red"))
  2823. -                    exchangeCrystal(player, crystalOLD, SoulCrystal.RED_BROKEN_CRYSTAL, true);
  2824. -
  2825. -                else if (crystalNME.startsWith("gre"))
  2826. -                    exchangeCrystal(player, crystalOLD, SoulCrystal.GRN_BROKEN_CYRSTAL, true);
  2827. -
  2828. -                else if (crystalNME.startsWith("blu"))
  2829. -                    exchangeCrystal(player, crystalOLD, SoulCrystal.BLU_BROKEN_CRYSTAL, true);
  2830. -
  2831. -                resetAbsorbList();
  2832. -            }
  2833. -            else
  2834. -                player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_FAILED));
  2835. -        }
  2836. -    }
  2837. -    
  2838. -    private void exchangeCrystal(L2PcInstance player, int takeid, int giveid, boolean broke)
  2839. -    {
  2840. -        L2ItemInstance Item = player.getInventory().destroyItemByItemId("SoulCrystal", takeid, 1, player, this);
  2841. -        if (Item != null)
  2842. -        {
  2843. -            // Prepare inventory update packet
  2844. -            InventoryUpdate playerIU = new InventoryUpdate();
  2845. -            playerIU.addRemovedItem(Item);
  2846. -
  2847. -            // Add new crystal to the killer's inventory
  2848. -            Item = player.getInventory().addItem("SoulCrystal", giveid, 1, player, this);
  2849. -            playerIU.addItem(Item);
  2850. -            
  2851. -            // Send a sound event and text message to the player
  2852. -            if(broke)
  2853. -            {
  2854. -                player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_BROKE));
  2855. -            }
  2856. -            else
  2857. -                player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_SUCCEEDED));
  2858. -            
  2859. -            // Send system message
  2860. -            SystemMessage sms = new SystemMessage(SystemMessage.EARNED_ITEM);
  2861. -            sms.addItemName(giveid);
  2862. -            player.sendPacket(sms);
  2863. -                        
  2864. -            // Send inventory update packet
  2865. -            player.sendPacket(playerIU);
  2866. -        }
  2867. -    }
  2868. -    
  2869. -    private void resetAbsorbList()
  2870. -    {
  2871. -        _absorbed = false;
  2872. -        _absorbersList.clear();
  2873. -    }
  2874. -    
  2875. -    /**
  2876. -     * Calculate the Experience and SP to distribute to attacker (L2PcInstance, L2SummonInstance or L2Party) of the L2Attackable.<BR><BR>
  2877. -     *
  2878. -     * @param diff The difference of level between attacker (L2PcInstance, L2SummonInstance or L2Party) and the L2Attackable
  2879. -     * @param damage The damages given by the attacker (L2PcInstance, L2SummonInstance or L2Party)
  2880. -     *
  2881. -     */
  2882. -    private int[] calculateExpAndSp(int diff, int damage)
  2883. -    {
  2884. -        long xp;
  2885. -        long sp;
  2886. -
  2887. -        if(diff < -5) diff = -5; // makes possible to use ALT_GAME_EXPONENT configuration
  2888. -        xp = (long)getExpReward() * damage / getMaxHp();
  2889. -        if (Config.ALT_GAME_EXPONENT_XP != 0) xp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_XP);
  2890. -
  2891. -        sp = (long)getSpReward() * damage / getMaxHp();
  2892. -        if (Config.ALT_GAME_EXPONENT_SP != 0) sp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_SP);
  2893. -        
  2894. -        if (Config.ALT_GAME_EXPONENT_XP == 0 && Config.ALT_GAME_EXPONENT_SP == 0)
  2895. -        {
  2896. -            // deep blue mob, is more than 8 levels below attacker lvl
  2897. -            if (diff > 8)
  2898. -            {
  2899. -                xp = 0;
  2900. -                sp = 0;
  2901. -            }
  2902. -            // green or light blue mob, is 6 to 8 levels below attacker lvl  
  2903. -            else if (diff > 5)
  2904. -            {
  2905. -                xp -= diff * xp / 10;
  2906. -                sp -= diff * sp / 10;
  2907. -            }
  2908. -            
  2909. -            if (xp <= 0)
  2910. -            {
  2911. -                xp = 0;
  2912. -                sp = 0;
  2913. -            }
  2914. -            else if (sp <= 0)
  2915. -            {
  2916. -                sp = 0;
  2917. -            }
  2918. -        }
  2919. -        
  2920. -        int[] tmp = { (int)xp, (int)sp };
  2921. -        
  2922. -        return  tmp;
  2923. -    }
  2924. -    
  2925. -    public int calculateOverhitExp(int normalExp)
  2926. -    {
  2927. -        // Get the percentage based on the total of extra (over-hit) damage done relative to the total (maximum) ammount of HP on the L2Attackable
  2928. -        double overhitPercentage = ((getOverhitDamage() * 100) / getMaxHp());
  2929. -        
  2930. -        // Over-hit damage percentages are limited to 25% max
  2931. -        if (overhitPercentage > 25)
  2932. -            overhitPercentage = 25;
  2933. -        
  2934. -        // Get the overhit exp bonus according to the above over-hit damage percentage
  2935. -        // (1/1 basis - 13% of over-hit damage, 13% of extra exp is given, and so on...)
  2936. -        double overhitExp = ((overhitPercentage / 100) * normalExp);
  2937. -        
  2938. -        // Return the rounded ammount of exp points to be added to the player's normal exp reward
  2939. -        int bonusOverhit = (int)Math.round(overhitExp);
  2940. -        return bonusOverhit;
  2941. -    }
  2942. -    
  2943. -    /**
  2944. -     * Return True.<BR><BR>
  2945. -     */
  2946. -    public boolean isAttackable()
  2947. -    {
  2948. -        return true;
  2949. -    }
  2950. -    
  2951. -    public void onSpawn()
  2952. -    {
  2953. -        super.onSpawn();
  2954. -        // Clear mob spoil,seed
  2955. -        setSpoil(false);
  2956. -
  2957. -        // Clear all aggro char from list
  2958. -        clearAggroList();
  2959. -        // Clear Harvester Reward List
  2960. -        _harvestItems = null;
  2961. -        // Clear mod Seeded stat
  2962. -        setSeeded(false);
  2963. -        // Clear overhit value
  2964. -        overhitEnabled(false);
  2965. -
  2966. -        _sweepItems = null;
  2967. -        resetAbsorbList();
  2968. -        
  2969. -        setWalking();
  2970. -        
  2971. -        // check the region where this mob is, do not activate the AI if region is inactive.
  2972. -        if (!isInActiveRegion())
  2973. -            if (this instanceof L2SiegeGuardInstance)
  2974. -                ((L2SiegeGuardAI) getAI()).stopAITask();
  2975. -            else
  2976. -                ((L2AttackableAI) getAI()).stopAITask();
  2977. -    }
  2978. -
  2979. -    public void setSeeded()
  2980. -    {
  2981. -        if (_seedType != 0 && _seeder != null)
  2982. -            setSeeded(_seedType, _seeder.getLevel());
  2983. -    }
  2984. -
  2985. -    public void setSeeded(int id, L2PcInstance seeder)
  2986. -    {
  2987. -        if (!_seeded)
  2988. -        {
  2989. -            _seedType = id;
  2990. -            _seeder = seeder;
  2991. -        }
  2992. -    }
  2993. -
  2994. -    public void setSeeded(int id, int seederLvl)
  2995. -    {
  2996. -        _seeded = true;
  2997. -        _seedType = id;
  2998. -        int count = 1;
  2999. -
  3000. -        Map<Integer, L2Skill> skills = getTemplate().getSkills();
  3001. -        if (skills != null)
  3002. -        {
  3003. -            for (int skillId : skills.keySet())
  3004. -            {
  3005. -                switch (skillId)
  3006. -                {
  3007. -                    case 4303: //Strong type x2
  3008. -                        count *= 2;
  3009. -                        break;
  3010. -                    case 4304: //Strong type x3
  3011. -                        count *= 3;
  3012. -                        break;
  3013. -                    case 4305: //Strong type x4
  3014. -                        count *= 4;
  3015. -                        break;
  3016. -                    case 4306: //Strong type x5
  3017. -                        count *= 5;
  3018. -                        break;
  3019. -                    case 4307: //Strong type x6
  3020. -                        count *= 6;
  3021. -                        break;
  3022. -                    case 4308: //Strong type x7
  3023. -                        count *= 7;
  3024. -                        break;
  3025. -                    case 4309: //Strong type x8
  3026. -                        count *= 8;
  3027. -                        break;
  3028. -                    case 4310: //Strong type x9
  3029. -                        count *= 9;
  3030. -                        break;
  3031. -                }
  3032. -            }
  3033. -        }
  3034. -
  3035. -        int diff = (getLevel() - (L2Manor.getInstance().getSeedLevel(_seedType) - 5));
  3036. -
  3037. -        // hi-lvl mobs bonus
  3038. -        if (diff > 0)
  3039. -
  3040. -            count += diff;
  3041. -
  3042. -
  3043. -        FastList<RewardItem> harvested = new FastList<RewardItem>();
  3044. -
  3045. -        harvested.add(new RewardItem(L2Manor.getInstance().getCropType(_seedType), count * Config.RATE_DROP_MANOR));
  3046. -
  3047. -        _harvestItems = harvested.toArray(new RewardItem[harvested.size()]);
  3048. -    }
  3049. -
  3050. -    public void setSeeded(boolean seeded)
  3051. -    {
  3052. -        _seeded = seeded;
  3053. -    }
  3054. -
  3055. -    public L2PcInstance getSeeder()
  3056. -    {
  3057. -        return _seeder;
  3058. -    }
  3059. -
  3060. -    public int getSeedType()
  3061. -    {
  3062. -        return _seedType;
  3063. -    }
  3064. -
  3065. -    public boolean isSeeded()
  3066. -    {
  3067. -        return _seeded;
  3068. -    }
  3069. -
  3070. -    private int getAbsorbLevel()
  3071. -    {
  3072. -        return getTemplate().absorb_level;
  3073. -    }
  3074. -
  3075. -    /**
  3076. -     * Check if the server allows Random Animation.<BR><BR>
  3077. -     */
  3078. -    public boolean hasRandomAnimation()
  3079. -    {
  3080. -        return ((Config.MAX_MONSTER_ANIMATION > 0) && !(this instanceof L2BossInstance));
  3081. -    }
  3082. +   // protected static Logger _log = Logger.getLogger(L2Attackable.class.getName());
  3083. +  
  3084. +   /**
  3085. +    * This class contains all AggroInfo of the L2Attackable against the attacker L2Character.<BR>
  3086. +    * <BR>
  3087. +    * <B><U> Data</U> :</B><BR>
  3088. +    * <BR>
  3089. +    * <li>attacker : The attaker L2Character concerned by this AggroInfo of this L2Attackable</li> <li>hate : Hate level of this L2Attackable against the attaker L2Character (hate = damage)</li> <li>damage : Number of damages that the attaker L2Character gave to this L2Attackable</li><BR>
  3090. +    * <BR>
  3091. +    */
  3092. +   public final class AggroInfo
  3093. +   {
  3094. +       /** The attaker L2Character concerned by this AggroInfo of this L2Attackable */
  3095. +       L2Character attacker;
  3096. +      
  3097. +       /** Hate level of this L2Attackable against the attaker L2Character (hate = damage) */
  3098. +       int hate;
  3099. +      
  3100. +       /** Number of damages that the attaker L2Character gave to this L2Attackable */
  3101. +       int damage;
  3102. +      
  3103. +       /**
  3104. +        * Constructor of AggroInfo.<BR>
  3105. +        * <BR>
  3106. +        */
  3107. +       AggroInfo(L2Character pAttacker)
  3108. +       {
  3109. +           attacker = pAttacker;
  3110. +       }
  3111. +      
  3112. +       /**
  3113. +        * Verify is object is equal to this AggroInfo.<BR>
  3114. +        * <BR>
  3115. +        */
  3116. +       @Override
  3117. +       public boolean equals(Object obj)
  3118. +       {
  3119. +           if (this == obj)
  3120. +           {
  3121. +               return true;
  3122. +           }
  3123. +          
  3124. +           if (obj instanceof AggroInfo)
  3125. +           {
  3126. +               return (((AggroInfo) obj).attacker == attacker);
  3127. +           }
  3128. +          
  3129. +           return false;
  3130. +       }
  3131. +      
  3132. +       /**
  3133. +        * Return the Identifier of the attaker L2Character.<BR>
  3134. +        * <BR>
  3135. +        */
  3136. +       @Override
  3137. +       public int hashCode()
  3138. +       {
  3139. +           return attacker.getObjectId();
  3140. +       }
  3141. +      
  3142. +   }
  3143. +  
  3144. +   /**
  3145. +    * This class contains all RewardInfo of the L2Attackable against the any attacker L2Character, based on amount of damage done.<BR>
  3146. +    * <BR>
  3147. +    * <B><U> Data</U> :</B><BR>
  3148. +    * <BR>
  3149. +    * <li>attacker : The attaker L2Character concerned by this RewardInfo of this L2Attackable</li> <li>dmg : Total amount of damage done by the attacker to this L2Attackable (summon + own)</li>
  3150. +    */
  3151. +   protected final class RewardInfo
  3152. +   {
  3153. +       protected L2Character attacker;
  3154. +       protected int dmg = 0;
  3155. +      
  3156. +       public RewardInfo(L2Character pAttacker, int pDmg)
  3157. +       {
  3158. +           attacker = pAttacker;
  3159. +           dmg = pDmg;
  3160. +       }
  3161. +      
  3162. +       public void addDamage(int pDmg)
  3163. +       {
  3164. +           dmg += pDmg;
  3165. +       }
  3166. +      
  3167. +       @Override
  3168. +       public boolean equals(Object obj)
  3169. +       {
  3170. +           if (this == obj)
  3171. +           {
  3172. +               return true;
  3173. +           }
  3174. +          
  3175. +           if (obj instanceof RewardInfo)
  3176. +           {
  3177. +               return (((RewardInfo) obj).attacker == attacker);
  3178. +           }
  3179. +          
  3180. +           return false;
  3181. +       }
  3182. +      
  3183. +       @Override
  3184. +       public int hashCode()
  3185. +       {
  3186. +           return attacker.getObjectId();
  3187. +       }
  3188. +   }
  3189. +  
  3190. +   /**
  3191. +    * This class contains all AbsorberInfo of the L2Attackable against the absorber L2Character.<BR>
  3192. +    * <BR>
  3193. +    * <B><U> Data</U> :</B><BR>
  3194. +    * <BR>
  3195. +    * <li>absorber : The attaker L2Character concerned by this AbsorberInfo of this L2Attackable</li>
  3196. +    */
  3197. +   public final class AbsorberInfo
  3198. +   {
  3199. +       /** The attaker L2Character concerned by this AbsorberInfo of this L2Attackable */
  3200. +       L2PcInstance absorber;
  3201. +       int crystalId;
  3202. +       double absorbedHP;
  3203. +      
  3204. +       /**
  3205. +        * Constructor of AbsorberInfo.<BR>
  3206. +        * <BR>
  3207. +        */
  3208. +       AbsorberInfo(L2PcInstance attacker, int pCrystalId, double pAbsorbedHP)
  3209. +       {
  3210. +           absorber = attacker;
  3211. +           crystalId = pCrystalId;
  3212. +           absorbedHP = pAbsorbedHP;
  3213. +       }
  3214. +      
  3215. +       /**
  3216. +        * Verify is object is equal to this AbsorberInfo.<BR>
  3217. +        * <BR>
  3218. +        */
  3219. +       @Override
  3220. +       public boolean equals(Object obj)
  3221. +       {
  3222. +           if (this == obj)
  3223. +           {
  3224. +               return true;
  3225. +           }
  3226. +          
  3227. +           if (obj instanceof AbsorberInfo)
  3228. +           {
  3229. +               return (((AbsorberInfo) obj).absorber == absorber);
  3230. +           }
  3231. +          
  3232. +           return false;
  3233. +       }
  3234. +      
  3235. +       /**
  3236. +        * Return the Identifier of the absorber L2Character.<BR>
  3237. +        * <BR>
  3238. +        */
  3239. +       @Override
  3240. +       public int hashCode()
  3241. +       {
  3242. +           return absorber.getObjectId();
  3243. +       }
  3244. +   }
  3245. +  
  3246. +   /**
  3247. +    * This class is used to create item reward lists instead of creating item instances.<BR>
  3248. +    * <BR>
  3249. +    */
  3250. +   public final class RewardItem
  3251. +   {
  3252. +       protected int _itemId;
  3253. +       protected int _count;
  3254. +      
  3255. +       public RewardItem(int itemId, int count)
  3256. +       {
  3257. +           _itemId = itemId;
  3258. +           _count = count;
  3259. +       }
  3260. +      
  3261. +       public int getItemId()
  3262. +       {
  3263. +           return _itemId;
  3264. +       }
  3265. +      
  3266. +       public int getCount()
  3267. +       {
  3268. +           return _count;
  3269. +       }
  3270. +   }
  3271. +  
  3272. +   private final FastMap<L2Character, AggroInfo> _aggroList = new FastMap<L2Character, AggroInfo>().setShared(true);
  3273. +  
  3274. +   /**
  3275. +    * Use this to Remove Object from this Map This Should be Synchronized While Iterating over This Map - if u cant iterating and removing object at once
  3276. +    */
  3277. +   public final FastMap<L2Character, AggroInfo> getAggroList()
  3278. +   {
  3279. +       return _aggroList;
  3280. +   }
  3281. +  
  3282. +   private boolean _isReturningToSpawnPoint = false;
  3283. +  
  3284. +   public final boolean isReturningToSpawnPoint()
  3285. +   {
  3286. +       return _isReturningToSpawnPoint;
  3287. +   }
  3288. +  
  3289. +   public final void setIsReturningToSpawnPoint(boolean value)
  3290. +   {
  3291. +       _isReturningToSpawnPoint = value;
  3292. +   }
  3293. +  
  3294. +   /** Table containing all Items that a Dwarf can Sweep on this L2Attackable */
  3295. +   private RewardItem[] _sweepItems;
  3296. +  
  3297. +   /** crops */
  3298. +   private RewardItem[] _harvestItems;
  3299. +   private boolean _seeded;
  3300. +   private int _seedType = 0;
  3301. +   private L2PcInstance _seeder = null;
  3302. +  
  3303. +   /** True if an over-hit enabled skill has successfully landed on the L2Attackable */
  3304. +   private boolean _overhit;
  3305. +  
  3306. +   /** Stores the extra (over-hit) damage done to the L2Attackable when the attacker uses an over-hit enabled skill */
  3307. +   private double _overhitDamage;
  3308. +  
  3309. +   /** Stores the attacker who used the over-hit enabled skill on the L2Attackable */
  3310. +   private L2Character _overhitAttacker;
  3311. +  
  3312. +   /** True if a Soul Crystal was successfuly used on the L2Attackable */
  3313. +   private boolean _absorbed;
  3314. +  
  3315. +   /** The table containing all L2PcInstance that successfuly absorbed the soul of this L2Attackable */
  3316. +   private final FastMap<L2PcInstance, AbsorberInfo> _absorbersList = new FastMap<L2PcInstance, AbsorberInfo>().setShared(true);
  3317. +  
  3318. +   /** Have this L2Attackable to drop somethink on DIE? **/
  3319. +   private boolean _haveToDrop;
  3320. +  
  3321. +   /** Have this L2Attackable to reward Exp and SP on Die? **/
  3322. +   private boolean _mustGiveExpSp;
  3323. +  
  3324. +   /**
  3325. +    * Constructor of L2Attackable (use L2Character and L2NpcInstance constructor).<BR>
  3326. +    * <BR>
  3327. +    * <B><U> Actions</U> :</B><BR>
  3328. +    * <BR>
  3329. +    * <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> <li>Set the name of the L2Attackable</li> <li>Create a RandomAnimation Task that will be launched after the calculated delay if
  3330. +    * the server allow it</li><BR>
  3331. +    * <BR>
  3332. +    * @param objectId Identifier of the object to initialized
  3333. +    * @param L2NpcTemplate Template to apply to the NPC
  3334. +    */
  3335. +   public L2Attackable(int objectId, L2NpcTemplate template)
  3336. +   {
  3337. +       super(objectId, template);
  3338. +       getKnownList(); // init knownlist
  3339. +       _haveToDrop = true;
  3340. +       _mustGiveExpSp = true;
  3341. +   }
  3342. +  
  3343. +   @Override
  3344. +   public AttackableKnownList getKnownList()
  3345. +   {
  3346. +       if ((super.getKnownList() == null) || !(super.getKnownList() instanceof AttackableKnownList))
  3347. +       {
  3348. +           setKnownList(new AttackableKnownList(this));
  3349. +       }
  3350. +       return (AttackableKnownList) super.getKnownList();
  3351. +   }
  3352. +  
  3353. +   /**
  3354. +    * Return the L2Character AI of the L2Attackable and if its null create a new one.<BR>
  3355. +    * <BR>
  3356. +    */
  3357. +   @Override
  3358. +   public L2CharacterAI getAI()
  3359. +   {
  3360. +       if (_ai == null)
  3361. +       {
  3362. +           synchronized (this)
  3363. +           {
  3364. +               if (_ai == null)
  3365. +               {
  3366. +                   _ai = new L2AttackableAI(new AIAccessor());
  3367. +               }
  3368. +           }
  3369. +       }
  3370. +       return _ai;
  3371. +   }
  3372. +  
  3373. +   // get condition to hate, actually isAggressive() is checked
  3374. +   // by monster and karma by guards in motheds that overwrite this one.
  3375. +   /**
  3376. +    * Not used.<BR>
  3377. +    * <BR>
  3378. +    * @deprecated
  3379. +    */
  3380. +   @Deprecated
  3381. +   public boolean getCondition2(L2Character target)
  3382. +   {
  3383. +       if ((target instanceof L2FolkInstance) || (target instanceof L2DoorInstance))
  3384. +       {
  3385. +           return false;
  3386. +       }
  3387. +      
  3388. +       if (target.isAlikeDead() || !isInsideRadius(target, getAggroRange(), false, false) || (Math.abs(getZ() - target.getZ()) > 100))
  3389. +       {
  3390. +           return false;
  3391. +       }
  3392. +      
  3393. +       return !target.isInvul();
  3394. +   }
  3395. +  
  3396. +   /**
  3397. +    * Reduce the current HP of the L2Attackable.<BR>
  3398. +    * <BR>
  3399. +    * @param damage The HP decrease value
  3400. +    * @param attacker The L2Character who attacks
  3401. +    */
  3402. +   @Override
  3403. +   public void reduceCurrentHp(double damage, L2Character attacker)
  3404. +   {
  3405. +       reduceCurrentHp(damage, attacker, true);
  3406. +   }
  3407. +  
  3408. +   /**
  3409. +    * Reduce the current HP of the L2Attackable, update its _aggroList and launch the doDie Task if necessary.<BR>
  3410. +    * <BR>
  3411. +    * @param i The HP decrease value
  3412. +    * @param attacker The L2Character who attacks
  3413. +    * @param awake The awake state (If True : stop sleeping)
  3414. +    */
  3415. +   @Override
  3416. +   public void reduceCurrentHp(double damage, L2Character attacker, boolean awake)
  3417. +   {
  3418. +      
  3419. +       if (isEventMob)
  3420. +       {
  3421. +           return;
  3422. +       }
  3423. +      
  3424. +       // Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList
  3425. +       if (attacker != null)
  3426. +       {
  3427. +           addDamage(attacker, (int) damage);
  3428. +           addBufferHate();
  3429. +       }
  3430. +      
  3431. +       // If this L2Attackable is a L2MonsterInstance and it has spawned minions, call its minions to battle
  3432. +       if (this instanceof L2MonsterInstance)
  3433. +       {
  3434. +           L2MonsterInstance master = (L2MonsterInstance) this;
  3435. +           if (this instanceof L2MinionInstance)
  3436. +           {
  3437. +               master = ((L2MinionInstance) this).getLeader();
  3438. +               if (!master.isInCombat() && !master.isDead())
  3439. +               {
  3440. +                   master.addDamage(attacker, 1);
  3441. +                   master.addBufferHate();
  3442. +               }
  3443. +           }
  3444. +           if (master.hasMinions())
  3445. +           {
  3446. +               master.callMinionsToAssist(attacker);
  3447. +           }
  3448. +       }
  3449. +      
  3450. +       // Reduce the current HP of the L2Attackable and launch the doDie Task if necessary
  3451. +       super.reduceCurrentHp(damage, attacker, awake);
  3452. +   }
  3453. +  
  3454. +   public synchronized void setHaveToDrop(boolean value)
  3455. +   {
  3456. +       _haveToDrop = value;
  3457. +   }
  3458. +  
  3459. +   public synchronized boolean getHaveToDrop()
  3460. +   {
  3461. +       return _haveToDrop;
  3462. +   }
  3463. +  
  3464. +   public synchronized void setMustRewardExpSp(boolean value)
  3465. +   {
  3466. +       _mustGiveExpSp = value;
  3467. +   }
  3468. +  
  3469. +   public synchronized boolean getMustRewardExpSP()
  3470. +   {
  3471. +       return _mustGiveExpSp;
  3472. +   }
  3473. +  
  3474. +   /**
  3475. +    * Kill the L2Attackable (the corpse disappeared after 7 seconds), distribute rewards (EXP, SP, Drops...) and notify Quest Engine.<BR>
  3476. +    * <BR>
  3477. +    * <B><U> Actions</U> :</B><BR>
  3478. +    * <BR>
  3479. +    * <li>Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members</li> <li>Notify the Quest Engine of the L2Attackable death if necessary</li> <li>Kill the L2NpcInstance (the corpse disappeared after 7 seconds)</li><BR>
  3480. +    * <BR>
  3481. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR>
  3482. +    * <BR>
  3483. +    * @param killer The L2Character that has killed the L2Attackable
  3484. +    */
  3485. +   @Override
  3486. +   public boolean doDie(L2Character killer)
  3487. +   {
  3488. +       // Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
  3489. +       if (!super.doDie(killer))
  3490. +       {
  3491. +           return false;
  3492. +       }
  3493. +      
  3494. +       // Enhance soul crystals of the attacker if this L2Attackable had its soul absorbed
  3495. +       try
  3496. +       {
  3497. +          
  3498. +           levelSoulCrystals(killer);
  3499. +          
  3500. +       }
  3501. +       catch (Exception e)
  3502. +       {
  3503. +           _log.log(Level.SEVERE, "", e);
  3504. +       }
  3505. +      
  3506. +       // Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members
  3507. +      
  3508. +       if (getHaveToDrop() || getMustRewardExpSP())
  3509. +       {
  3510. +           try
  3511. +           {
  3512. +               calculateRewards(killer);
  3513. +           }
  3514. +           catch (Exception e)
  3515. +           {
  3516. +               _log.log(Level.SEVERE, "", e);
  3517. +           }
  3518. +       }
  3519. +      
  3520. +       // Notify the Quest Engine of the L2Attackable death if necessary
  3521. +       try
  3522. +       {
  3523. +           L2PcInstance player = null;
  3524. +           if (killer instanceof L2PcInstance)
  3525. +           {
  3526. +               player = (L2PcInstance) killer;
  3527. +           }
  3528. +           else if (killer instanceof L2Summon)
  3529. +           {
  3530. +               player = ((L2Summon) killer).getOwner();
  3531. +           }
  3532. +          
  3533. +           if (player != null)
  3534. +           {
  3535. +               List<QuestState> questList = new FastList<QuestState>();
  3536. +              
  3537. +               if (player.getParty() != null)
  3538. +               {
  3539. +                   Map<String, List<QuestState>> tempMap = new FastMap<String, List<QuestState>>();
  3540. +                  
  3541. +                   for (L2PcInstance pl : player.getParty().getPartyMembers())
  3542. +                   {
  3543. +                       if (pl.getQuestsForKills(this) == null)
  3544. +                       {
  3545. +                           continue;
  3546. +                       }
  3547. +                      
  3548. +                       for (QuestState qs : pl.getQuestsForKills(this))
  3549. +                       {
  3550. +                           if (qs.getState().isParty())
  3551. +                           {
  3552. +                               if (!qs.isCompleted() && !pl.isDead() && Util.checkIfInRange(1400, this, pl, true))
  3553. +                               {
  3554. +                                   if (this instanceof L2RaidBossInstance)
  3555. +                                   {
  3556. +                                       questList.add(qs);
  3557. +                                   }
  3558. +                                   else
  3559. +                                   {
  3560. +                                       if (tempMap.get(qs.getQuest().getName()) != null)
  3561. +                                       {
  3562. +                                           tempMap.get(qs.getQuest().getName()).add(qs);
  3563. +                                       }
  3564. +                                       else
  3565. +                                       {
  3566. +                                           List<QuestState> tempList = new FastList<QuestState>();
  3567. +                                           tempList.add(qs);
  3568. +                                           tempMap.put(qs.getQuest().getName(), tempList);
  3569. +                                       }
  3570. +                                   }
  3571. +                               }
  3572. +                           }
  3573. +                           else if (pl == player)
  3574. +                           {
  3575. +                               questList.add(qs);
  3576. +                           }
  3577. +                       }
  3578. +                   }
  3579. +                  
  3580. +                   for (List<QuestState> list : tempMap.values())
  3581. +                   {
  3582. +                       questList.add((QuestState) list.toArray()[Rnd.nextInt(list.size())]);
  3583. +                   }
  3584. +               }
  3585. +               else
  3586. +               {
  3587. +                   if (player.getQuestsForKills(this) != null)
  3588. +                   {
  3589. +                       for (QuestState qs : player.getQuestsForKills(this))
  3590. +                       {
  3591. +                           questList.add(qs);
  3592. +                       }
  3593. +                   }
  3594. +               }
  3595. +              
  3596. +               for (QuestState qs : questList)
  3597. +               {
  3598. +                   qs.getQuest().notifyKill(this, qs);
  3599. +               }
  3600. +           }
  3601. +       }
  3602. +       catch (Exception e)
  3603. +       {
  3604. +          
  3605. +           _log.log(Level.SEVERE, "", e);
  3606. +       }
  3607. +       return true;
  3608. +   }
  3609. +  
  3610. +   /**
  3611. +    * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members.<BR>
  3612. +    * <BR>
  3613. +    * <B><U> Actions</U> :</B><BR>
  3614. +    * <BR>
  3615. +    * <li>Get the L2PcInstance owner of the L2SummonInstance (if necessary) and L2Party in progress</li> <li>Calculate the Experience and SP rewards in function of the level difference</li> <li>Add Exp and SP rewards to L2PcInstance (including Summon penalty) and to Party members in the known area
  3616. +    * of the last attacker</li><BR>
  3617. +    * <BR>
  3618. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR>
  3619. +    * <BR>
  3620. +    * @param lastAttacker The L2Character that has killed the L2Attackable
  3621. +    */
  3622. +   private void calculateRewards(L2Character lastAttacker)
  3623. +   {
  3624. +       if (getAggroList().isEmpty())
  3625. +       {
  3626. +           return;
  3627. +       }
  3628. +      
  3629. +       if (getMustRewardExpSP())
  3630. +       {
  3631. +          
  3632. +           // Creates an empty list of rewards
  3633. +           FastMap<L2Character, RewardInfo> rewards = new FastMap<L2Character, RewardInfo>().setShared(true);
  3634. +           int rewardCount = 0;
  3635. +          
  3636. +           int damage;
  3637. +           L2Character attacker;
  3638. +           L2Character ddealer;
  3639. +           RewardInfo reward;
  3640. +          
  3641. +           // While Iterating over This Map Removing Object is Not Allowed
  3642. +           synchronized (getAggroList())
  3643. +           {
  3644. +               // Go through the _aggroList of the L2Attackable
  3645. +               for (AggroInfo info : getAggroList().values())
  3646. +               {
  3647. +                   if (info == null)
  3648. +                   {
  3649. +                       continue;
  3650. +                   }
  3651. +                  
  3652. +                   // Get the L2Character corresponding to this attacker
  3653. +                   attacker = info.attacker;
  3654. +                  
  3655. +                   // Get damages done by this attacker
  3656. +                   damage = info.damage;
  3657. +                  
  3658. +                   // Prevent unwanted behavior
  3659. +                   if (damage > 1)
  3660. +                   {
  3661. +                       if (attacker instanceof L2SummonInstance)
  3662. +                       {
  3663. +                           ddealer = ((L2SummonInstance) attacker).getOwner();
  3664. +                       }
  3665. +                       else
  3666. +                       {
  3667. +                           ddealer = info.attacker;
  3668. +                       }
  3669. +                      
  3670. +                       if (!Util.checkIfInRange(1600, this, ddealer, true))
  3671. +                       {
  3672. +                           continue;
  3673. +                       }
  3674. +                      
  3675. +                       // Calculate real damages (Summoners should get own damage plus summon's damage)
  3676. +                       reward = rewards.get(ddealer);
  3677. +                      
  3678. +                       if (reward == null)
  3679. +                       {
  3680. +                           reward = new RewardInfo(ddealer, damage);
  3681. +                           rewardCount++;
  3682. +                       }
  3683. +                       else
  3684. +                       {
  3685. +                           reward.addDamage(damage);
  3686. +                       }
  3687. +                      
  3688. +                       rewards.put(ddealer, reward);
  3689. +                   }
  3690. +                  
  3691. +               }
  3692. +              
  3693. +           }
  3694. +          
  3695. +           if (!rewards.isEmpty())
  3696. +           {
  3697. +              
  3698. +               L2Party attackerParty;
  3699. +              
  3700. +               int exp;
  3701. +               int levelDiff;
  3702. +               int partyDmg;
  3703. +               float partyMul;
  3704. +               float penalty;
  3705. +              
  3706. +               RewardInfo reward2;
  3707. +               int sp;
  3708. +               int[] tmp;
  3709. +              
  3710. +               for (FastMap.Entry<L2Character, RewardInfo> entry = rewards.head(), end = rewards.tail(); (entry = entry.getNext()) != end;)
  3711. +               {
  3712. +                   if (entry == null)
  3713. +                   {
  3714. +                       continue;
  3715. +                   }
  3716. +                  
  3717. +                   reward = entry.getValue();
  3718. +                   if (reward == null)
  3719. +                   {
  3720. +                       continue;
  3721. +                   }
  3722. +                  
  3723. +                   // Penalty applied to the attacker's XP
  3724. +                   penalty = 0;
  3725. +                  
  3726. +                   // Attacker to be rewarded
  3727. +                   attacker = reward.attacker;
  3728. +                  
  3729. +                   // Total amount of damage done
  3730. +                   damage = reward.dmg;
  3731. +                  
  3732. +                   // If the attacker is a Pet, get the party of the owner
  3733. +                   if (attacker instanceof L2PetInstance)
  3734. +                   {
  3735. +                       attackerParty = ((L2PetInstance) attacker).getParty();
  3736. +                   }
  3737. +                   else if (attacker instanceof L2PcInstance)
  3738. +                   {
  3739. +                       attackerParty = ((L2PcInstance) attacker).getParty();
  3740. +                   }
  3741. +                   else
  3742. +                   {
  3743. +                       return;
  3744. +                   }
  3745. +                  
  3746. +                   // If this attacker is a L2PcInstance with a summoned L2SummonInstance, get Exp Penalty applied for the current summoned L2SummonInstance
  3747. +                   if ((attacker instanceof L2PcInstance) && (((L2PcInstance) attacker).getPet() instanceof L2SummonInstance))
  3748. +                   {
  3749. +                       penalty = ((L2SummonInstance) ((L2PcInstance) attacker).getPet()).getExpPenalty();
  3750. +                   }
  3751. +                  
  3752. +                   // We must avoid "over damage", if any
  3753. +                   if (damage > getMaxHp())
  3754. +                   {
  3755. +                       damage = getMaxHp();
  3756. +                   }
  3757. +                  
  3758. +                   // If there's NO party in progress
  3759. +                   if (attackerParty == null)
  3760. +                   {
  3761. +                       // Calculate Exp and SP rewards
  3762. +                       if (attacker.getKnownList().knowsObject(this))
  3763. +                       {
  3764. +                           // Calculate the difference of level between this attacker (L2PcInstance or L2SummonInstance owner) and the L2Attackable
  3765. +                           // mob = 24, atk = 10, diff = -14 (full xp)
  3766. +                           // mob = 24, atk = 28, diff = 4 (some xp)
  3767. +                           // mob = 24, atk = 50, diff = 26 (no xp)
  3768. +                           levelDiff = attacker.getLevel() - getLevel();
  3769. +                          
  3770. +                           tmp = calculateExpAndSp(levelDiff, damage);
  3771. +                           exp = tmp[0];
  3772. +                           exp *= 1 - penalty;
  3773. +                           sp = tmp[1];
  3774. +                          
  3775. +                           // Check for an over-hit enabled strike
  3776. +                           if (attacker instanceof L2PcInstance)
  3777. +                           {
  3778. +                               L2PcInstance player = (L2PcInstance) attacker;
  3779. +                               if (isOverhit() && (attacker == getOverhitAttacker()))
  3780. +                               {
  3781. +                                   player.sendPacket(new SystemMessage(SystemMessage.OVER_HIT));
  3782. +                                   exp += calculateOverhitExp(exp);
  3783. +                               }
  3784. +                           }
  3785. +                          
  3786. +                           // Distribute the Exp and SP between the L2PcInstance and its L2Summon
  3787. +                           if (!attacker.isDead())
  3788. +                           {
  3789. +                               attacker.addExpAndSp((int) Math.round(attacker.calcStat(Stats.EXPSP_RATE, exp, null, null)), (int) attacker.calcStat(Stats.EXPSP_RATE, sp, null, null));
  3790. +                           }
  3791. +                       }
  3792. +                   }
  3793. +                   else
  3794. +                   {
  3795. +                       // share with party members
  3796. +                       partyDmg = 0;
  3797. +                       partyMul = 1.f;
  3798. +                      
  3799. +                       // Get all L2Character (including L2Summon) that can be rewarded in the party
  3800. +                       List<L2Character> rewardedMembers = new FastList<L2Character>();
  3801. +                      
  3802. +                       // Go through all L2PcInstance in the party
  3803. +                       for (L2PcInstance pl : attackerParty.getPartyMembers())
  3804. +                       {
  3805. +                           if ((pl == null) || pl.isDead())
  3806. +                           {
  3807. +                               continue;
  3808. +                           }
  3809. +                          
  3810. +                           // Get the RewardInfo of this L2PcInstance from L2Attackable rewards
  3811. +                           reward2 = rewards.get(pl);
  3812. +                          
  3813. +                           // If the L2PcInstance is in the L2Attackable rewards add its damages to party damages
  3814. +                           if (reward2 != null)
  3815. +                           {
  3816. +                               if (Util.checkIfInRange(1600, this, pl, true))
  3817. +                               {
  3818. +                                   // Add L2PcInstance damages to party damages
  3819. +                                   partyDmg += reward2.dmg;
  3820. +                                  
  3821. +                                   rewardedMembers.add(pl);
  3822. +                               }
  3823. +                              
  3824. +                               // Remove the L2PcInstance from the L2Attackable rewards
  3825. +                               rewards.remove(pl);
  3826. +                           }
  3827. +                           else
  3828. +                           {
  3829. +                               // Add L2PcInstance of the party (that have attacked or not) to members that can be rewarded if it's not dead
  3830. +                               // and in range of the monster.
  3831. +                               if (Util.checkIfInRange(1600, this, pl, true))
  3832. +                               {
  3833. +                                   rewardedMembers.add(pl);
  3834. +                               }
  3835. +                           }
  3836. +                          
  3837. +                           L2PlayableInstance summon = pl.getPet();
  3838. +                           if ((summon != null) && (summon instanceof L2PetInstance))
  3839. +                           {
  3840. +                               reward2 = rewards.get(summon);
  3841. +                               if (reward2 != null)
  3842. +                               {
  3843. +                                  
  3844. +                                   if (Util.checkIfInRange(1600, this, summon, true))
  3845. +                                   {
  3846. +                                       partyDmg += reward2.dmg;
  3847. +                                       rewardedMembers.add(summon);
  3848. +                                   }
  3849. +                                  
  3850. +                                   // Remove the summon from the L2Attackable rewards
  3851. +                                   rewards.remove(summon);
  3852. +                               }
  3853. +                           }
  3854. +                       }
  3855. +                      
  3856. +                       // If the party didn't killed this L2Attackable alone
  3857. +                       if (partyDmg < getMaxHp())
  3858. +                       {
  3859. +                           partyMul = ((float) partyDmg / (float) getMaxHp());
  3860. +                       }
  3861. +                      
  3862. +                       // Avoid "over damage"
  3863. +                       if (partyDmg > getMaxHp())
  3864. +                       {
  3865. +                           partyDmg = getMaxHp();
  3866. +                       }
  3867. +                      
  3868. +                       // Calculate the level difference between Party and L2Attackable
  3869. +                       levelDiff = attackerParty.getLevel() - getLevel();
  3870. +                      
  3871. +                       // Calculate Exp and SP rewards
  3872. +                       tmp = calculateExpAndSp(levelDiff, partyDmg);
  3873. +                       exp = tmp[0];
  3874. +                       sp = tmp[1];
  3875. +                      
  3876. +                       exp *= partyMul;
  3877. +                       sp *= partyMul;
  3878. +                      
  3879. +                       // Check for an over-hit enabled strike
  3880. +                       // (When in party, the over-hit exp bonus is given to the whole party and splitted proportionally through the party members)
  3881. +                       if (attacker instanceof L2PcInstance)
  3882. +                       {
  3883. +                           L2PcInstance player = (L2PcInstance) attacker;
  3884. +                           if (isOverhit() && (attacker == getOverhitAttacker()))
  3885. +                           {
  3886. +                              
  3887. +                               player.sendPacket(new SystemMessage(SystemMessage.OVER_HIT));
  3888. +                               exp += calculateOverhitExp(exp);
  3889. +                           }
  3890. +                       }
  3891. +                      
  3892. +                       // Distribute Experience and SP rewards to L2PcInstance Party members in the known area of the last attacker
  3893. +                       if (partyDmg > 0)
  3894. +                       {
  3895. +                           attackerParty.distributeXpAndSp(exp, sp, rewardedMembers, lastAttacker);
  3896. +                       }
  3897. +                   }
  3898. +               }
  3899. +           }
  3900. +          
  3901. +           rewards = null;
  3902. +       }
  3903. +       // Manage Base, Quests and Sweep drops of the L2Attackable
  3904. +       if (getHaveToDrop())
  3905. +       {
  3906. +           doItemDrop(lastAttacker);
  3907. +       }
  3908. +       // Manage drop of Special Events created by GM for a defined period
  3909. +       doEventDrop(lastAttacker);
  3910. +   }
  3911. +  
  3912. +   /**
  3913. +    * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR>
  3914. +    * <BR>
  3915. +    * @param attacker The L2Character that gave damages to this L2Attackable
  3916. +    * @param damage The number of damages given by the attacker L2Character
  3917. +    */
  3918. +   public void addDamage(L2Character attacker, int damage)
  3919. +   {
  3920. +       addDamageHate(attacker, damage, damage);
  3921. +   }
  3922. +  
  3923. +   public void addBufferHate()
  3924. +   {
  3925. +       L2Character target = getMostHated();
  3926. +      
  3927. +       if (target == null)
  3928. +       {
  3929. +           return;
  3930. +       }
  3931. +      
  3932. +       for (L2PcInstance actor : getKnownList().getKnownPlayers().values())
  3933. +       {
  3934. +           if (actor.isCastingNow() && (target.getLastBuffer() == actor))
  3935. +           {
  3936. +               int actorLevel = actor.getLevel();
  3937. +               double divisor = 0;
  3938. +               L2Skill skill = actor.getLastSkillCast();
  3939. +              
  3940. +               if (actorLevel < 10)
  3941. +               {
  3942. +                   divisor = 15;
  3943. +               }
  3944. +               else if ((actorLevel > 9) && (actorLevel < 20))
  3945. +               {
  3946. +                   divisor = 11.5;
  3947. +               }
  3948. +               else if ((actorLevel > 19) && (actorLevel < 30))
  3949. +               {
  3950. +                   divisor = 8.5;
  3951. +               }
  3952. +               else if ((actorLevel > 29) && (actorLevel < 40))
  3953. +               {
  3954. +                   divisor = 6;
  3955. +               }
  3956. +               else if ((actorLevel > 39) && (actorLevel < 50))
  3957. +               {
  3958. +                   divisor = 4;
  3959. +               }
  3960. +               else if ((actorLevel > 49) && (actorLevel < 60))
  3961. +               {
  3962. +                   divisor = 2.5;
  3963. +               }
  3964. +               else if ((actorLevel > 59) && (actorLevel < 70))
  3965. +               {
  3966. +                   divisor = 1.5;
  3967. +               }
  3968. +               else if (actorLevel > 69)
  3969. +               {
  3970. +                   divisor = 1;
  3971. +               }
  3972. +              
  3973. +               if ((skill != null) && ((skill.getSkillType() == SkillType.HEAL) || (skill.getSkillType() == SkillType.HEAL_PERCENT) || (skill.getSkillType() == SkillType.MANAHEAL) || (skill.getSkillType() == SkillType.BALANCE_LIFE)))
  3974. +               {
  3975. +                   L2Object[] targetList = skill.getTargetList(actor, true);
  3976. +                  
  3977. +                   if ((targetList != null) && (targetList.length != 0) && ((targetList[0] instanceof L2PcInstance) || (targetList[0] instanceof L2SummonInstance) || (targetList[0] instanceof L2PetInstance)))
  3978. +                   {
  3979. +                       if ((getMaxHp() / 5) < target.getLastHealAmount())
  3980. +                       {
  3981. +                           target.setLastHealAmount((getMaxHp() / 5));
  3982. +                       }
  3983. +                      
  3984. +                       addDamageHate(actor, 0, (int) (target.getLastHealAmount() / divisor));
  3985. +                      
  3986. +                       if (Config.DEBUG)
  3987. +                       {
  3988. +                           System.out.print("Mob detect heal.\n");
  3989. +                       }
  3990. +                   }
  3991. +               }
  3992. +              
  3993. +               if ((skill != null) && ((skill.getSkillType() == SkillType.BUFF) || (skill.getSkillType() == SkillType.HOT)))
  3994. +               {
  3995. +                   L2Object[] targetList = skill.getTargetList(actor, true);
  3996. +                  
  3997. +                   if ((targetList != null) && (targetList.length != 0) && ((targetList[0] instanceof L2PcInstance) || (targetList[0] instanceof L2SummonInstance) || (targetList[0] instanceof L2PetInstance)))
  3998. +                   {
  3999. +                       addDamageHate(actor, 0, (int) ((skill.getLevel() * getStat().getMpConsume(skill)) / divisor));
  4000. +                      
  4001. +                       if (Config.DEBUG)
  4002. +                       {
  4003. +                           System.out.print("Mob detect buff.\n");
  4004. +                       }
  4005. +                   }
  4006. +               }
  4007. +              
  4008. +               if (((L2PcInstance) target).isInParty() && (skill != null) && (skill.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY))
  4009. +               {
  4010. +                   List<L2PcInstance> members = ((L2PcInstance) target).getParty().getPartyMembers();
  4011. +                  
  4012. +                   for (L2PcInstance member : members)
  4013. +                   {
  4014. +                       if (member == actor)
  4015. +                       {
  4016. +                           if ((getMaxHp() / 3) < (int) (((getHating(target) - getHating(actor)) + 800) / divisor))
  4017. +                           {
  4018. +                               addDamageHate(actor, 0, (getMaxHp() / 3));
  4019. +                           }
  4020. +                           else
  4021. +                           {
  4022. +                               addDamageHate(actor, 0, (int) (((getHating(target) - getHating(actor)) + 800) / divisor));
  4023. +                           }
  4024. +                          
  4025. +                           if (Config.DEBUG)
  4026. +                           {
  4027. +                               System.out.print("Mob detect party cast.\n");
  4028. +                           }
  4029. +                       }
  4030. +                   }
  4031. +               }
  4032. +           }
  4033. +       }
  4034. +   }
  4035. +  
  4036. +   /**
  4037. +    * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR>
  4038. +    * <BR>
  4039. +    * @param attacker The L2Character that gave damages to this L2Attackable
  4040. +    * @param damage The number of damages given by the attacker L2Character
  4041. +    * @param aggro The hate (=damage) given by the attacker L2Character
  4042. +    */
  4043. +   public void addDamageHate(L2Character attacker, int damage, int aggro)
  4044. +   {
  4045. +       if (attacker == null)
  4046. +       {
  4047. +           return;
  4048. +       }
  4049. +      
  4050. +       // Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable
  4051. +       AggroInfo ai = getAggroList().get(attacker);
  4052. +       if (ai == null)
  4053. +      
  4054. +       {
  4055. +          
  4056. +           ai = new AggroInfo(attacker);
  4057. +           ai.damage = 0;
  4058. +           ai.hate = 0;
  4059. +          
  4060. +           getAggroList().put(attacker, ai);
  4061. +       }
  4062. +      
  4063. +       // Add new damage and aggro (=damage) to the AggroInfo object
  4064. +       ai.damage += damage;
  4065. +       ai.hate += aggro;
  4066. +      
  4067. +       // Set the intention to the L2Attackable to AI_INTENTION_ACTIVE
  4068. +       if ((aggro > 0) && (getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE))
  4069. +       {
  4070. +           getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  4071. +       }
  4072. +      
  4073. +       // Notify the L2Attackable AI with EVT_ATTACKED
  4074. +       if (damage > 0)
  4075. +       {
  4076. +           getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, attacker);
  4077. +       }
  4078. +      
  4079. +       try
  4080. +       {
  4081. +           L2PcInstance player = null;
  4082. +           if (attacker instanceof L2PcInstance)
  4083. +           {
  4084. +               player = (L2PcInstance) attacker;
  4085. +           }
  4086. +           else if (attacker instanceof L2Summon)
  4087. +           {
  4088. +               player = ((L2Summon) attacker).getOwner();
  4089. +           }
  4090. +          
  4091. +           if (player != null)
  4092. +           {
  4093. +              
  4094. +               if (player.getQuestsForAttacks(this) != null)
  4095. +               {
  4096. +                   for (QuestState st : player.getQuestsForAttacks(this))
  4097. +                   {
  4098. +                       st.getQuest().notifyAttack(this, st);
  4099. +                   }
  4100. +               }
  4101. +           }
  4102. +       }
  4103. +       catch (Exception e)
  4104. +       {
  4105. +           _log.log(Level.SEVERE, "", e);
  4106. +       }
  4107. +   }
  4108. +  
  4109. +   /**
  4110. +    * Return the most hated L2Character of the L2Attackable _aggroList.<BR>
  4111. +    * <BR>
  4112. +    */
  4113. +   public L2Character getMostHated()
  4114. +   {
  4115. +       if (getAggroList().isEmpty() || isAlikeDead())
  4116. +       {
  4117. +           return null;
  4118. +       }
  4119. +      
  4120. +       L2Character mostHated = null;
  4121. +       int maxHate = 0;
  4122. +      
  4123. +       // While Iterating over This Map Removing Object is Not Allowed
  4124. +      
  4125. +       synchronized (getAggroList())
  4126. +       {
  4127. +           // Go through the aggroList of the L2Attackable
  4128. +           for (AggroInfo ai : getAggroList().values())
  4129. +           {
  4130. +               if (ai == null)
  4131. +               {
  4132. +                   continue;
  4133. +               }
  4134. +               if (ai.attacker.isAlikeDead() || !getKnownList().knowsObject(ai.attacker) || !ai.attacker.isVisible())
  4135. +               {
  4136. +                   ai.hate = 0;
  4137. +               }
  4138. +              
  4139. +               if (ai.hate > maxHate)
  4140. +               {
  4141. +                   mostHated = ai.attacker;
  4142. +                   maxHate = ai.hate;
  4143. +               }
  4144. +           }
  4145. +       }
  4146. +      
  4147. +       return mostHated;
  4148. +   }
  4149. +  
  4150. +   /**
  4151. +    * Return the hate level of the L2Attackable against this L2Character contained in _aggroList.<BR>
  4152. +    * <BR>
  4153. +    * @param target The L2Character whose hate level must be returned
  4154. +    */
  4155. +   public int getHating(L2Character target)
  4156. +   {
  4157. +       if (getAggroList().isEmpty())
  4158. +       {
  4159. +           return 0;
  4160. +       }
  4161. +      
  4162. +       AggroInfo ai = getAggroList().get(target);
  4163. +       if (ai == null)
  4164. +       {
  4165. +           return 0;
  4166. +       }
  4167. +      
  4168. +       if ((ai.attacker instanceof L2PcInstance) && ((((L2PcInstance) ai.attacker).getInvisible() == 1) || ai.attacker.isInvul()))
  4169. +       {
  4170. +           // Remove Object Should Use This Method and Can be Blocked While Iterating
  4171. +           getAggroList().remove(target);
  4172. +           return 0;
  4173. +       }
  4174. +       if (!ai.attacker.isVisible())
  4175. +       {
  4176. +           getAggroList().remove(target);
  4177. +           return 0;
  4178. +       }
  4179. +       if (ai.attacker.isAlikeDead())
  4180. +       {
  4181. +           ai.hate = 0;
  4182. +           return 0;
  4183. +       }
  4184. +      
  4185. +       return ai.hate;
  4186. +   }
  4187. +  
  4188. +   /**
  4189. +    * Calculates quantity of items for specific drop acording to current situation <br>
  4190. +    * @param drop The L2DropData count is being calculated for
  4191. +    * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  4192. +    * @param deepBlueDrop Factor to divide the drop chance
  4193. +    * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  4194. +    */
  4195. +   private RewardItem calculateRewardItem(L2PcInstance lastAttacker, L2DropData drop, int levelModifier, boolean isSweep)
  4196. +   {
  4197. +       // Get default drop chance
  4198. +       float dropChance = drop.getChance();
  4199. +      
  4200. +       float dropItemsRate;
  4201. +       if ((this instanceof L2BossInstance) || (this instanceof L2RaidBossInstance))
  4202. +       {
  4203. +           dropItemsRate = Config.RATE_BOSS_DROP_ITEMS;
  4204. +       }
  4205. +       else
  4206. +       {
  4207. +           dropItemsRate = Config.RATE_DROP_ITEMS;
  4208. +       }
  4209. +      
  4210. +       int deepBlueDrop = 1;
  4211. +       if (Config.DEEPBLUE_DROP_RULES)
  4212. +       {
  4213. +           if (levelModifier > 0)
  4214. +           {
  4215. +               // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  4216. +               // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  4217. +               deepBlueDrop = 3;
  4218. +               if (drop.getItemId() == 57)
  4219. +               {
  4220. +                   deepBlueDrop *= (int) dropItemsRate;
  4221. +               }
  4222. +           }
  4223. +       }
  4224. +      
  4225. +       if (deepBlueDrop == 0)
  4226. +       {
  4227. +           deepBlueDrop = 1;
  4228. +       }
  4229. +       // Check if we should apply our maths so deep blue mobs will not drop that easy
  4230. +       if (Config.DEEPBLUE_DROP_RULES)
  4231. +       {
  4232. +           dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier) / 100)) / deepBlueDrop);
  4233. +       }
  4234. +      
  4235. +       // Applies Drop rates
  4236. +       if (drop.getItemId() == 57)
  4237. +       {
  4238. +           dropChance *= Config.RATE_DROP_ADENA;
  4239. +       }
  4240. +       else if (isSweep)
  4241. +       {
  4242. +           dropChance *= Config.RATE_DROP_SPOIL;
  4243. +       }
  4244. +       else
  4245. +       {
  4246. +           dropChance *= dropItemsRate;
  4247. +       }
  4248. +      
  4249. +       // Round drop chance
  4250. +       dropChance = Math.round(dropChance);
  4251. +      
  4252. +       // Set our limits for chance of drop
  4253. +       if (dropChance < 1)
  4254. +       {
  4255. +           dropChance = 1;
  4256. +           // if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time
  4257. +       }
  4258. +      
  4259. +       // Get min and max Item quantity that can be dropped in one time
  4260. +       int minCount = drop.getMinDrop();
  4261. +       int maxCount = drop.getMaxDrop();
  4262. +       int itemCount = 0;
  4263. +      
  4264. +       // Count and chance adjustment for high rate servers
  4265. +       if ((dropChance > L2DropData.MAX_CHANCE) && !Config.PRECISE_DROP_CALCULATION)
  4266. +       {
  4267. +           int multiplier = (int) dropChance / L2DropData.MAX_CHANCE;
  4268. +           if (minCount < maxCount)
  4269. +           {
  4270. +               itemCount += Rnd.get(minCount * multiplier, maxCount * multiplier);
  4271. +           }
  4272. +           else if (minCount == maxCount)
  4273. +           {
  4274. +               itemCount += minCount * multiplier;
  4275. +           }
  4276. +           else
  4277. +           {
  4278. +               itemCount += multiplier;
  4279. +           }
  4280. +          
  4281. +           dropChance = dropChance % L2DropData.MAX_CHANCE;
  4282. +       }
  4283. +      
  4284. +       // Check if the Item must be dropped
  4285. +       int random = Rnd.get(L2DropData.MAX_CHANCE);
  4286. +       while (random < dropChance)
  4287. +       {
  4288. +           // Get the item quantity dropped
  4289. +           if (minCount < maxCount)
  4290. +           {
  4291. +               itemCount += Rnd.get(minCount, maxCount);
  4292. +           }
  4293. +           else if (minCount == maxCount)
  4294. +           {
  4295. +               itemCount += minCount;
  4296. +           }
  4297. +           else
  4298. +           {
  4299. +               itemCount++;
  4300. +           }
  4301. +          
  4302. +           // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  4303. +           dropChance -= L2DropData.MAX_CHANCE;
  4304. +       }
  4305. +      
  4306. +       if (itemCount > 0)
  4307. +       {
  4308. +           return new RewardItem(drop.getItemId(), itemCount);
  4309. +       }
  4310. +       else if ((itemCount == 0) && Config.DEBUG)
  4311. +       {
  4312. +           _log.fine("Roll produced 0 items to drop...");
  4313. +       }
  4314. +      
  4315. +       return null;
  4316. +   }
  4317. +  
  4318. +   /**
  4319. +    * Calculates quantity of items for specific drop CATEGORY according to current situation <br>
  4320. +    * Only a max of ONE item from a category is allowed to be dropped.
  4321. +    * @param drop The L2DropData count is being calculated for
  4322. +    * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  4323. +    * @param deepBlueDrop Factor to divide the drop chance
  4324. +    * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  4325. +    */
  4326. +   private RewardItem calculateCategorizedRewardItem(L2PcInstance lastAttacker, L2DropCategory categoryDrops, int levelModifier)
  4327. +   {
  4328. +       if (categoryDrops == null)
  4329. +       {
  4330. +           return null;
  4331. +       }
  4332. +      
  4333. +       // Get default drop chance for the category (that's the sum of chances for all items in the category)
  4334. +       // keep track of the base category chance as it'll be used later, if an item is drop from the category.
  4335. +       // for everything else, use the total "categoryDropChance"
  4336. +       int basecategoryDropChance = categoryDrops.getCategoryChance();
  4337. +       int categoryDropChance = basecategoryDropChance;
  4338. +       int deepBlueDrop = 1;
  4339. +       if (Config.DEEPBLUE_DROP_RULES)
  4340. +       {
  4341. +           if (levelModifier > 0)
  4342. +           {
  4343. +               // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  4344. +               // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  4345. +               deepBlueDrop = 3;
  4346. +           }
  4347. +       }
  4348. +      
  4349. +       if (deepBlueDrop == 0)
  4350. +       {
  4351. +           deepBlueDrop = 1;
  4352. +       }
  4353. +       // Check if we should apply our maths so deep blue mobs will not drop that easy
  4354. +       if (Config.DEEPBLUE_DROP_RULES)
  4355. +       {
  4356. +           categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier) / 100)) / deepBlueDrop);
  4357. +       }
  4358. +       // Applies Drop rates
  4359. +       categoryDropChance *= Config.RATE_DROP_ITEMS;
  4360. +       // Round drop chance
  4361. +       categoryDropChance = Math.round(categoryDropChance);
  4362. +       // Set our limits for chance of drop
  4363. +       if (categoryDropChance < 1)
  4364. +       {
  4365. +           categoryDropChance = 1;
  4366. +       }
  4367. +       // Check if an Item from this category must be dropped
  4368. +       if (Rnd.get(L2DropData.MAX_CHANCE) < categoryDropChance)
  4369. +       {
  4370. +           L2DropData drop = categoryDrops.dropOne();
  4371. +           if (drop == null)
  4372. +           {
  4373. +               return null;
  4374. +           }
  4375. +          
  4376. +           // Now decide the quantity to drop based on the rates and penalties. To get this value
  4377. +           // simply divide the modified categoryDropChance by the base category chance. This
  4378. +           // results in a chance that will dictate the drops amounts: for each amount over 100
  4379. +           // that it is, it will give another chance to add to the min/max quantities.
  4380. +           //
  4381. +           // For example, If the final chance is 120%, then the item should drop between
  4382. +           // its min and max one time, and then have 20% chance to drop again. If the final
  4383. +           // chance is 330%, it will similarly give 3 times the min and max, and have a 30%
  4384. +           // chance to give a 4th time.
  4385. +           // At least 1 item will be dropped for sure. So the chance will be adjusted to 100%
  4386. +           // if smaller.
  4387. +          
  4388. +           int dropChance = drop.getChance();
  4389. +           if (drop.getItemId() == 57)
  4390. +           {
  4391. +               dropChance *= Config.RATE_DROP_ADENA;
  4392. +           }
  4393. +           else
  4394. +           {
  4395. +               dropChance *= Config.RATE_DROP_ITEMS;
  4396. +           }
  4397. +           dropChance = Math.round(dropChance);
  4398. +           if (dropChance < L2DropData.MAX_CHANCE)
  4399. +           {
  4400. +               dropChance = L2DropData.MAX_CHANCE;
  4401. +           }
  4402. +          
  4403. +           // Get min and max Item quantity that can be dropped in one time
  4404. +           int min = drop.getMinDrop();
  4405. +           int max = drop.getMaxDrop();
  4406. +           // Get the item quantity dropped
  4407. +           int itemCount = 0;
  4408. +          
  4409. +           // Count and chance adjustment for high rate servers
  4410. +           if ((dropChance > L2DropData.MAX_CHANCE) && !Config.PRECISE_DROP_CALCULATION)
  4411. +           {
  4412. +               int multiplier = dropChance / L2DropData.MAX_CHANCE;
  4413. +               if (min < max)
  4414. +               {
  4415. +                   itemCount += Rnd.get(min * multiplier, max * multiplier);
  4416. +               }
  4417. +               else if (min == max)
  4418. +               {
  4419. +                   itemCount += min * multiplier;
  4420. +               }
  4421. +               else
  4422. +               {
  4423. +                   itemCount += multiplier;
  4424. +               }
  4425. +               dropChance = dropChance % L2DropData.MAX_CHANCE;
  4426. +           }
  4427. +           // Check if the Item must be dropped
  4428. +           int random = Rnd.get(L2DropData.MAX_CHANCE);
  4429. +           while (random < dropChance)
  4430. +           {
  4431. +               // Get the item quantity dropped
  4432. +               if (min < max)
  4433. +               {
  4434. +                   itemCount += Rnd.get(min, max);
  4435. +               }
  4436. +               else if (min == max)
  4437. +               {
  4438. +                   itemCount += min;
  4439. +               }
  4440. +               else
  4441. +               {
  4442. +                   itemCount++;
  4443. +               }
  4444. +              
  4445. +               // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  4446. +               dropChance -= L2DropData.MAX_CHANCE;
  4447. +           }
  4448. +          
  4449. +           if (itemCount > 0)
  4450. +           {
  4451. +               return new RewardItem(drop.getItemId(), itemCount);
  4452. +           }
  4453. +           else if ((itemCount == 0) && Config.DEBUG)
  4454. +           {
  4455. +               _log.fine("Roll produced 0 items to drop...");
  4456. +           }
  4457. +       }
  4458. +       return null;
  4459. +      
  4460. +       /*
  4461. +        * // Applies Drop rates if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA; else if (isSweep) dropChance *= Config.RATE_DROP_SPOIL; else dropChance *= Config.RATE_DROP_ITEMS; // Round drop chance dropChance = Math.round(dropChance); // Set our limits for chance of drop if
  4462. +        * (dropChance < 1) dropChance = 1; // if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time // Get min and max Item quantity that can be dropped in one time int minCount = drop.getMinDrop(); int
  4463. +        * maxCount = drop.getMaxDrop(); int itemCount = 0; if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount); else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop..."); return null;
  4464. +        */
  4465. +   }
  4466. +  
  4467. +   /**
  4468. +    * Calculates the level modifier for drop<br>
  4469. +    * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  4470. +    */
  4471. +   private int calculateLevelModifierForDrop(L2PcInstance lastAttacker)
  4472. +   {
  4473. +       if (Config.DEEPBLUE_DROP_RULES)
  4474. +       {
  4475. +           int highestLevel = lastAttacker.getLevel();
  4476. +          
  4477. +           // Check to prevent very high level player to nearly kill mob and let low level player do the last hit.
  4478. +           if ((getAttackByList() != null) && !getAttackByList().isEmpty())
  4479. +           {
  4480. +               for (L2Character atkChar : getAttackByList())
  4481. +               {
  4482. +                   if ((atkChar != null) && (atkChar.getLevel() > highestLevel))
  4483. +                   {
  4484. +                       highestLevel = atkChar.getLevel();
  4485. +                   }
  4486. +               }
  4487. +           }
  4488. +          
  4489. +           // According to official data (Prima), deep blue mobs are 9 or more levels below players
  4490. +           if ((highestLevel - 9) >= getLevel())
  4491. +           {
  4492. +               return ((highestLevel - (getLevel() + 8)) * 9);
  4493. +           }
  4494. +       }
  4495. +      
  4496. +       return 0;
  4497. +   }
  4498. +  
  4499. +   public void doItemDrop(L2Character lastAttacker)
  4500. +   {
  4501. +       doItemDrop(getTemplate(), lastAttacker);
  4502. +   }
  4503. +  
  4504. +   /**
  4505. +    * Manage Base, Quests and Special Events drops of L2Attackable (called by calculateRewards).<BR>
  4506. +    * <BR>
  4507. +    * <B><U> Concept</U> :</B><BR>
  4508. +    * <BR>
  4509. +    * During a Special Event all L2Attackable can drop extra Items. Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist. Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR>
  4510. +    * <BR>
  4511. +    * <B><U> Actions</U> : </B><BR>
  4512. +    * <BR>
  4513. +    * <li>Manage drop of Special Events created by GM for a defined period</li> <li>Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops</li> <li>For each possible drops (base + quests), calculate which one must be dropped (random)</li> <li>Get each Item quantity
  4514. +    * dropped (random)</li> <li>Create this or these L2ItemInstance corresponding to each Item Identifier dropped</li> <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
  4515. +    * L2Attackable</li> <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><BR>
  4516. +    * <BR>
  4517. +    * @param lastAttacker The L2Character that has killed the L2Attackable
  4518. +    */
  4519. +   public void doItemDrop(L2NpcTemplate npcTemplate, L2Character lastAttacker)
  4520. +   {
  4521. +       L2PcInstance player = null;
  4522. +       if (lastAttacker instanceof L2PcInstance)
  4523. +       {
  4524. +           player = (L2PcInstance) lastAttacker;
  4525. +       }
  4526. +       else if (lastAttacker instanceof L2Summon)
  4527. +       {
  4528. +           player = ((L2Summon) lastAttacker).getOwner();
  4529. +       }
  4530. +      
  4531. +       if (player == null)
  4532. +       {
  4533. +           return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  4534. +       }
  4535. +      
  4536. +       int levelModifier = calculateLevelModifierForDrop(player); // level modifier in %'s (will be subtracted from drop chance)
  4537. +      
  4538. +       // Add Quest drops to the table containing all possible drops of this L2Attackable
  4539. +       FastList<L2DropData> questDrops = new FastList<L2DropData>();
  4540. +       player.fillQuestDrops(this, questDrops);
  4541. +      
  4542. +       // First, throw possible quest drops of this L2Attackable
  4543. +       for (L2DropData drop : questDrops)
  4544. +       {
  4545. +           if (drop == null)
  4546. +           {
  4547. +               continue;
  4548. +           }
  4549. +          
  4550. +           RewardItem item = calculateRewardItem(player, drop, levelModifier, false);
  4551. +           if (item == null)
  4552. +           {
  4553. +               continue;
  4554. +           }
  4555. +          
  4556. +           // Check if the autoLoot mode is active
  4557. +           if (Config.AUTO_LOOT)
  4558. +           {
  4559. +               player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  4560. +           }
  4561. +           else
  4562. +           {
  4563. +               dropItem(player, item); // drop the item on the ground
  4564. +           }
  4565. +       }
  4566. +      
  4567. +       // now throw all categorized drops and handle spoil.
  4568. +       for (L2DropCategory cat : npcTemplate.getDropData())
  4569. +       {
  4570. +           RewardItem item = null;
  4571. +           if (cat.isSweep())
  4572. +           {
  4573. +               // according to sh1ny, seeded mobs CAN be spoiled and swept.
  4574. +               if (isSpoil()/* && !isSeeded() */)
  4575. +               {
  4576. +                   FastList<RewardItem> sweepList = new FastList<RewardItem>();
  4577. +                  
  4578. +                   for (L2DropData drop : cat.getAllDrops())
  4579. +                   {
  4580. +                       item = calculateRewardItem(player, drop, levelModifier, true);
  4581. +                       if (item == null)
  4582. +                       {
  4583. +                           continue;
  4584. +                       }
  4585. +                      
  4586. +                       if (Config.DEBUG)
  4587. +                       {
  4588. +                           _log.fine("Item id to spoil: " + item.getItemId() + " amount: " + item.getCount());
  4589. +                       }
  4590. +                       sweepList.add(item);
  4591. +                   }
  4592. +                  
  4593. +                   // Set the table _sweepItems of this L2Attackable
  4594. +                   if (sweepList.size() > 0)
  4595. +                   {
  4596. +                       _sweepItems = sweepList.toArray(new RewardItem[sweepList.size()]);
  4597. +                   }
  4598. +               }
  4599. +           }
  4600. +           else
  4601. +           {
  4602. +               if (isSeeded())
  4603. +               {
  4604. +                   L2DropData drop = cat.dropSeedAllowedDropsOnly();
  4605. +                   if (drop == null)
  4606. +                   {
  4607. +                       continue;
  4608. +                   }
  4609. +                  
  4610. +                   item = calculateRewardItem(player, drop, levelModifier, false);
  4611. +               }
  4612. +               else
  4613. +               {
  4614. +                   item = calculateCategorizedRewardItem(player, cat, levelModifier);
  4615. +               }
  4616. +               if (item != null)
  4617. +               {
  4618. +                   if (Config.DEBUG)
  4619. +                   {
  4620. +                       _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  4621. +                   }
  4622. +                  
  4623. +                   // Check if the autoLoot mode is active
  4624. +                   if (Config.AUTO_LOOT)
  4625. +                   {
  4626. +                       player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  4627. +                   }
  4628. +                   else
  4629. +                   {
  4630. +                       dropItem(player, item); // drop the item on the ground
  4631. +                   }
  4632. +                  
  4633. +                   // Broadcast message if RaidBoss was defeated
  4634. +                   if (this instanceof L2RaidBossInstance)
  4635. +                   {
  4636. +                       SystemMessage sm;
  4637. +                       sm = new SystemMessage(SystemMessage.S1_DIED_DROPPED_S3_S2);
  4638. +                       sm.addString(getName());
  4639. +                       sm.addItemName(item.getItemId());
  4640. +                       sm.addNumber(item.getCount());
  4641. +                       broadcastPacket(sm);
  4642. +                   }
  4643. +               }
  4644. +           }
  4645. +       }
  4646. +      
  4647. +   }
  4648. +  
  4649. +   /**
  4650. +    * Manage Special Events drops created by GM for a defined period.<BR>
  4651. +    * <BR>
  4652. +    * <B><U> Concept</U> :</B><BR>
  4653. +    * <BR>
  4654. +    * During a Special Event all L2Attackable can drop extra Items. Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist. Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR>
  4655. +    * <BR>
  4656. +    * <B><U> Actions</U> : <I>If an extra drop must be generated</I></B><BR>
  4657. +    * <BR>
  4658. +    * <li>Get an Item Identifier (random) from the DateDrop Item table of this Event</li> <li>Get the Item quantity dropped (random)</li> <li>Create this or these L2ItemInstance corresponding to this Item Identifier</li> <li>If the autoLoot mode is actif and if the L2Character that has killed the
  4659. +    * L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable</li> <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
  4660. +    * the position where mob was last</li><BR>
  4661. +    * <BR>
  4662. +    * @param lastAttacker The L2Character that has killed the L2Attackable
  4663. +    */
  4664. +   public void doEventDrop(L2Character lastAttacker)
  4665. +   {
  4666. +       L2PcInstance player = null;
  4667. +       if (lastAttacker instanceof L2PcInstance)
  4668. +       {
  4669. +           player = (L2PcInstance) lastAttacker;
  4670. +       }
  4671. +       else if (lastAttacker instanceof L2Summon)
  4672. +       {
  4673. +           player = ((L2Summon) lastAttacker).getOwner();
  4674. +       }
  4675. +      
  4676. +       if (player == null)
  4677. +       {
  4678. +           return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  4679. +       }
  4680. +      
  4681. +       if ((player.getLevel() - getLevel()) > 9)
  4682. +       {
  4683. +           return;
  4684. +       }
  4685. +      
  4686. +       // Go through DateDrop of EventDroplist allNpcDateDrops within the date range
  4687. +       for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
  4688. +       {
  4689. +           if (Rnd.get(L2DropData.MAX_CHANCE) < drop.chance)
  4690. +           {
  4691. +               RewardItem item = new RewardItem(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
  4692. +               if (Config.AUTO_LOOT)
  4693. +               {
  4694. +                   player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  4695. +               }
  4696. +               else
  4697. +               {
  4698. +                   dropItem(player, item); // drop the item on the ground
  4699. +               }
  4700. +           }
  4701. +       }
  4702. +   }
  4703. +  
  4704. +   /**
  4705. +    * Drop reward item.<BR>
  4706. +    * <BR>
  4707. +    */
  4708. +   public L2ItemInstance dropItem(L2PcInstance lastAttacker, RewardItem item)
  4709. +   {
  4710. +       int randDropLim = 70;
  4711. +      
  4712. +       L2ItemInstance ditem = null;
  4713. +       for (int i = 0; i < item.getCount(); i++)
  4714. +       {
  4715. +           // Randomize drop position
  4716. +           int newX = (getX() + Rnd.get((randDropLim * 2) + 1)) - randDropLim;
  4717. +           int newY = (getY() + Rnd.get((randDropLim * 2) + 1)) - randDropLim;
  4718. +           int newZ = Math.max(getZ(), lastAttacker.getZ()) + 20; // TODO: temp hack, do something nicer when we have geodatas
  4719. +          
  4720. +           // Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last
  4721. +           ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), lastAttacker, this);
  4722. +           ditem.dropMe(this, newX, newY, newZ);
  4723. +          
  4724. +           // Add drop to auto destroy item task
  4725. +           if (!Config.LIST_PROTECTED_ITEMS.contains(item.getItemId()))
  4726. +           {
  4727. +               if (Config.AUTODESTROY_ITEM_AFTER > 0)
  4728. +               {
  4729. +                   ItemsAutoDestroy.getInstance().addItem(ditem);
  4730. +               }
  4731. +           }
  4732. +           ditem.setProtected(false);
  4733. +           // If stackable, end loop as entire count is included in 1 instance of item
  4734. +           if (ditem.isStackable() || !Config.MULTIPLE_ITEM_DROP)
  4735. +           {
  4736. +               break;
  4737. +           }
  4738. +       }
  4739. +       return ditem;
  4740. +   }
  4741. +  
  4742. +   public L2ItemInstance dropItem(L2PcInstance lastAttacker, int itemId, int itemCount)
  4743. +   {
  4744. +       return dropItem(lastAttacker, new RewardItem(itemId, itemCount));
  4745. +   }
  4746. +  
  4747. +   /**
  4748. +    * Return the active weapon of this L2Attackable (= null).<BR>
  4749. +    * <BR>
  4750. +    */
  4751. +   public L2ItemInstance getActiveWeapon()
  4752. +   {
  4753. +       return null;
  4754. +   }
  4755. +  
  4756. +   /**
  4757. +    * Return True if the _aggroList of this L2Attackable is Empty.<BR>
  4758. +    * <BR>
  4759. +    */
  4760. +   public boolean noTarget()
  4761. +   {
  4762. +       return getAggroList().isEmpty();
  4763. +   }
  4764. +  
  4765. +   /**
  4766. +    * Return True if the _aggroList of this L2Attackable contains the L2Character.<BR>
  4767. +    * <BR>
  4768. +    * @param player The L2Character searched in the _aggroList of the L2Attackable
  4769. +    */
  4770. +   public boolean containsTarget(L2Character player)
  4771. +   {
  4772. +       return getAggroList().containsKey(player);
  4773. +   }
  4774. +  
  4775. +   /**
  4776. +    * Clear the _aggroList of the L2Attackable.<BR>
  4777. +    * <BR>
  4778. +    */
  4779. +   public void clearAggroList()
  4780. +   {
  4781. +       getAggroList().clear();
  4782. +      
  4783. +       _overhit = false;
  4784. +       _overhitDamage = 0;
  4785. +       _overhitAttacker = null;
  4786. +   }
  4787. +  
  4788. +   /**
  4789. +    * Clears _aggroList hate of the L2Character without removing from the list.<BR>
  4790. +    * <BR>
  4791. +    */
  4792. +   public void clearHating(L2Character target)
  4793. +   {
  4794. +       if (getAggroList().isEmpty())
  4795. +       {
  4796. +           return;
  4797. +       }
  4798. +       AggroInfo ai = getAggroList().get(target);
  4799. +       if (ai == null)
  4800. +       {
  4801. +           return;
  4802. +       }
  4803. +       ai.hate = 0;
  4804. +   }
  4805. +  
  4806. +   /**
  4807. +    * Return True if a Dwarf use Sweep on the L2Attackable and if item can be spoiled.<BR>
  4808. +    * <BR>
  4809. +    */
  4810. +   public boolean isSweepActive()
  4811. +   {
  4812. +       return _sweepItems != null;
  4813. +   }
  4814. +  
  4815. +   /**
  4816. +    * Return table containing all L2ItemInstance that can be spoiled.<BR>
  4817. +    * <BR>
  4818. +    */
  4819. +   public synchronized RewardItem[] takeSweep()
  4820. +   {
  4821. +       RewardItem[] sweep = _sweepItems;
  4822. +      
  4823. +       _sweepItems = null;
  4824. +      
  4825. +       return sweep;
  4826. +   }
  4827. +  
  4828. +   /**
  4829. +    * Return table containing all L2ItemInstance that can be harvested.<BR>
  4830. +    * <BR>
  4831. +    */
  4832. +   public synchronized RewardItem[] takeHarvest()
  4833. +   {
  4834. +       RewardItem[] harvest = _harvestItems;
  4835. +       _harvestItems = null;
  4836. +       return harvest;
  4837. +   }
  4838. +  
  4839. +   /**
  4840. +    * Set the over-hit flag on the L2Attackable.<BR>
  4841. +    * <BR>
  4842. +    * @param status The status of the over-hit flag
  4843. +    */
  4844. +   public void overhitEnabled(boolean status)
  4845. +   {
  4846. +       _overhit = status;
  4847. +   }
  4848. +  
  4849. +   /**
  4850. +    * Set the over-hit values like the attacker who did the strike and the ammount of damage done by the skill.<BR>
  4851. +    * <BR>
  4852. +    * @param attacker The L2Character who hit on the L2Attackable using the over-hit enabled skill
  4853. +    * @param damage The ammount of damage done by the over-hit enabled skill on the L2Attackable
  4854. +    */
  4855. +   public void setOverhitValues(L2Character attacker, double damage)
  4856. +   {
  4857. +       // Calculate the over-hit damage
  4858. +       // Ex: mob had 10 HP left, over-hit skill did 50 damage total, over-hit damage is 40
  4859. +       double overhitDmg = ((getCurrentHp() - damage) * (-1));
  4860. +       if (overhitDmg < 0)
  4861. +       {
  4862. +           // we didn't killed the mob with the over-hit strike. (it wasn't really an over-hit strike)
  4863. +           // let's just clear all the over-hit related values
  4864. +           overhitEnabled(false);
  4865. +           _overhitDamage = 0;
  4866. +           _overhitAttacker = null;
  4867. +           return;
  4868. +       }
  4869. +       overhitEnabled(true);
  4870. +       _overhitDamage = overhitDmg;
  4871. +       _overhitAttacker = attacker;
  4872. +   }
  4873. +  
  4874. +   /**
  4875. +    * Return the L2Character who hit on the L2Attackable using an over-hit enabled skill.<BR>
  4876. +    * <BR>
  4877. +    * @return L2Character attacker
  4878. +    */
  4879. +   public L2Character getOverhitAttacker()
  4880. +   {
  4881. +       return _overhitAttacker;
  4882. +   }
  4883. +  
  4884. +   /**
  4885. +    * Return the ammount of damage done on the L2Attackable using an over-hit enabled skill.<BR>
  4886. +    * <BR>
  4887. +    * @return double damage
  4888. +    */
  4889. +   public double getOverhitDamage()
  4890. +   {
  4891. +       return _overhitDamage;
  4892. +   }
  4893. +  
  4894. +   /**
  4895. +    * Return True if the L2Attackable was hit by an over-hit enabled skill.<BR>
  4896. +    * <BR>
  4897. +    */
  4898. +   public boolean isOverhit()
  4899. +   {
  4900. +       return _overhit;
  4901. +   }
  4902. +  
  4903. +   /**
  4904. +    * Activate the absorbed soul condition on the L2Attackable.<BR>
  4905. +    * <BR>
  4906. +    */
  4907. +   public void absorbSoul()
  4908. +   {
  4909. +       _absorbed = true;
  4910. +   }
  4911. +  
  4912. +   /**
  4913. +    * Return True if the L2Attackable had his soul absorbed.<BR>
  4914. +    * <BR>
  4915. +    */
  4916. +   public boolean isAbsorbed()
  4917. +   {
  4918. +       return _absorbed;
  4919. +   }
  4920. +  
  4921. +   /**
  4922. +    * Adds an attacker that successfully absorbed the soul of this L2Attackable into the _absorbersList.<BR>
  4923. +    * <BR>
  4924. +    * params: attacker - a valid L2PcInstance condition - an integer indicating the event when mob dies. This should be: = 0 - "the crystal scatters"; = 1 - "the crystal failed to absorb. nothing happens"; = 2 - "the crystal resonates because you got more than 1 crystal on you"; = 3 -
  4925. +    * "the crystal cannot absorb the soul because the mob level is too low"; = 4 - "the crystal successfuly absorbed the soul";
  4926. +    */
  4927. +   public void addAbsorber(L2PcInstance attacker, int crystalId)
  4928. +   {
  4929. +       // This just works for targets like L2MonsterInstance
  4930. +       if (!(this instanceof L2MonsterInstance))
  4931. +       {
  4932. +           return;
  4933. +       }
  4934. +      
  4935. +       // The attacker must not be null
  4936. +       if (attacker == null)
  4937. +       {
  4938. +           return;
  4939. +       }
  4940. +      
  4941. +       // This L2Attackable must be of one type in the _absorbingMOBS_levelXX tables.
  4942. +       // OBS: This is done so to avoid triggering the absorbed conditions for mobs that can't be absorbed.
  4943. +       if (getAbsorbLevel() == 0)
  4944. +       {
  4945. +           return;
  4946. +       }
  4947. +      
  4948. +       // If we have no _absorbersList initiated, do it
  4949. +       AbsorberInfo ai = _absorbersList.get(attacker);
  4950. +      
  4951. +       // If the L2Character attacker isn't already in the _absorbersList of this L2Attackable, add it
  4952. +       if (ai == null)
  4953. +       {
  4954. +           ai = new AbsorberInfo(attacker, crystalId, getCurrentHp());
  4955. +           _absorbersList.put(attacker, ai);
  4956. +       }
  4957. +       else
  4958. +       {
  4959. +           ai.absorber = attacker;
  4960. +           ai.crystalId = crystalId;
  4961. +           ai.absorbedHP = getCurrentHp();
  4962. +       }
  4963. +      
  4964. +       // Set this L2Attackable as absorbed
  4965. +       absorbSoul();
  4966. +   }
  4967. +  
  4968. +   /**
  4969. +    * Calculate the leveling chance of Soul Crystals based on the attacker that killed this L2Attackable
  4970. +    * @param attacker The player that last killed this L2Attackable $ Rewrite 06.12.06 - Yesod
  4971. +    */
  4972. +   private void levelSoulCrystals(L2Character attacker)
  4973. +   {
  4974. +       // Only L2PcInstance can absorb a soul
  4975. +       if (!(attacker instanceof L2PcInstance))
  4976. +       {
  4977. +           resetAbsorbList();
  4978. +           return;
  4979. +       }
  4980. +      
  4981. +       int maxAbsorbLevel = getAbsorbLevel();
  4982. +       int minAbsorbLevel = 0;
  4983. +      
  4984. +       // If this is not a valid L2Attackable, clears the _absorbersList and just return
  4985. +       if (maxAbsorbLevel == 0)
  4986. +       {
  4987. +           resetAbsorbList();
  4988. +           return;
  4989. +       }
  4990. +       // All boss mobs with maxAbsorbLevel 13 have minAbsorbLevel of 12 else 10
  4991. +       if (maxAbsorbLevel > 10)
  4992. +       {
  4993. +           minAbsorbLevel = maxAbsorbLevel > 12 ? 12 : 10;
  4994. +       }
  4995. +      
  4996. +       // Init some useful vars
  4997. +       boolean isSuccess = true;
  4998. +       boolean doLevelup = true;
  4999. +       boolean isBossMob = maxAbsorbLevel > 10 ? true : false;
  5000. +      
  5001. +       L2PcInstance killer = (L2PcInstance) attacker;
  5002. +      
  5003. +       // If this mob is a boss, then skip some checkings
  5004. +       if (!isBossMob)
  5005. +       {
  5006. +           // Fail if this L2Attackable isn't absorbed or there's no one in its _absorbersList
  5007. +           if (!isAbsorbed() /* || _absorbersList == null */)
  5008. +           {
  5009. +               resetAbsorbList();
  5010. +               return;
  5011. +           }
  5012. +          
  5013. +           // Fail if the killer isn't in the _absorbersList of this L2Attackable and mob is not boss
  5014. +           AbsorberInfo ai = _absorbersList.get(killer);
  5015. +           if ((ai == null) || (ai.absorber.getObjectId() != killer.getObjectId()))
  5016. +           {
  5017. +               isSuccess = false;
  5018. +           }
  5019. +          
  5020. +           // Check if the soul crystal was used when HP of this L2Attackable wasn't higher than half of it
  5021. +           if ((ai != null) && (ai.absorbedHP > (getMaxHp() / 2)))
  5022. +           {
  5023. +               isSuccess = false;
  5024. +           }
  5025. +          
  5026. +           if (!isSuccess)
  5027. +           {
  5028. +               resetAbsorbList();
  5029. +               return;
  5030. +           }
  5031. +       }
  5032. +      
  5033. +       // ********
  5034. +       String[] crystalNFO = null;
  5035. +       String crystalNME = "";
  5036. +      
  5037. +       int dice = Rnd.get(100);
  5038. +       int crystalQTY = 0;
  5039. +       int crystalLVL = 0;
  5040. +       int crystalOLD = 0;
  5041. +       int crystalNEW = 0;
  5042. +      
  5043. +       // ********
  5044. +       // Now we have four choices:
  5045. +       // 1- The Monster level is too low for the crystal. Nothing happens.
  5046. +       // 2- Everything is correct, but it failed. Nothing happens. (57.5%)
  5047. +       // 3- Everything is correct, but it failed. The crystal scatters. A sound event is played. (10%)
  5048. +       // 4- Everything is correct, the crystal level up. A sound event is played. (32.5%)
  5049. +      
  5050. +       List<L2PcInstance> players = new FastList<L2PcInstance>();
  5051. +      
  5052. +       if (isBossMob && killer.isInParty())
  5053. +       {
  5054. +           players = killer.getParty().getPartyMembers();
  5055. +       }
  5056. +       else
  5057. +       {
  5058. +           players.add(killer);
  5059. +       }
  5060. +      
  5061. +       for (L2PcInstance player : players)
  5062. +       {
  5063. +           if (player == null)
  5064. +           {
  5065. +               continue;
  5066. +           }
  5067. +          
  5068. +           QuestState qs = player.getQuestState("350_EnhanceYourWeapon");
  5069. +           if ((qs == null) || !qs.isStarted())
  5070. +           {
  5071. +               continue;
  5072. +           }
  5073. +          
  5074. +           crystalQTY = 0;
  5075. +          
  5076. +           L2ItemInstance[] inv = player.getInventory().getItems();
  5077. +           for (L2ItemInstance item : inv)
  5078. +           {
  5079. +               int itemId = item.getItemId();
  5080. +               for (int id : SoulCrystal.SoulCrystalTable)
  5081. +               {
  5082. +                   // Find any of the 39 possible crystals.
  5083. +                   if (id == itemId)
  5084. +                   {
  5085. +                       crystalQTY++;
  5086. +                       // Keep count but make sure the player has no more than 1 crystal
  5087. +                       if (crystalQTY > 1)
  5088. +                       {
  5089. +                           isSuccess = false;
  5090. +                           break;
  5091. +                       }
  5092. +                      
  5093. +                       // Validate if the crystal has already leveled
  5094. +                       if ((id != SoulCrystal.RED_NEW_CRYSTAL) && (id != SoulCrystal.GRN_NEW_CYRSTAL) && (id != SoulCrystal.BLU_NEW_CRYSTAL))
  5095. +                       {
  5096. +                           try
  5097. +                           {
  5098. +                               if (item.getItem().getName().contains("Grade"))
  5099. +                               {
  5100. +                                   // Split the name of the crystal into 'name' & 'level'
  5101. +                                   crystalNFO = item.getItem().getName().trim().replace(" Grade ", "-").split("-");
  5102. +                                   // Set Level to 13
  5103. +                                   crystalLVL = 13;
  5104. +                                   // Get Name
  5105. +                                   crystalNME = crystalNFO[0].toLowerCase();
  5106. +                               }
  5107. +                               else
  5108. +                               {
  5109. +                                   // Split the name of the crystal into 'name' & 'level'
  5110. +                                   crystalNFO = item.getItem().getName().trim().replace(" Stage ", "").split("-");
  5111. +                                   // Get Level
  5112. +                                   crystalLVL = Integer.parseInt(crystalNFO[1].trim());
  5113. +                                   // Get Name
  5114. +                                   crystalNME = crystalNFO[0].toLowerCase();
  5115. +                               }
  5116. +                               // Allocate current and levelup ids' for higher level crystals
  5117. +                               if (crystalLVL > 9)
  5118. +                               {
  5119. +                                   for (int[] element : SoulCrystal.HighSoulConvert)
  5120. +                                   {
  5121. +                                       // Get the next stage above 10 using array.
  5122. +                                       if (id == element[0])
  5123. +                                       {
  5124. +                                           crystalNEW = element[1];
  5125. +                                           break;
  5126. +                                       }
  5127. +                                   }
  5128. +                               }
  5129. +                               else
  5130. +                               {
  5131. +                                   crystalNEW = id + 1;
  5132. +                               }
  5133. +                           }
  5134. +                           catch (NumberFormatException nfe)
  5135. +                           {
  5136. +                               _log.log(Level.WARNING, "An attempt to identify a soul crystal failed, " + "verify the names have not changed in etcitem " + "table.", nfe);
  5137. +                              
  5138. +                               player.sendMessage("There has been an error handling your soul crystal." + " Please notify your server admin.");
  5139. +                              
  5140. +                               isSuccess = false;
  5141. +                               break;
  5142. +                           }
  5143. +                           catch (Exception e)
  5144. +                           {
  5145. +                               e.printStackTrace();
  5146. +                               isSuccess = false;
  5147. +                               break;
  5148. +                           }
  5149. +                       }
  5150. +                       else
  5151. +                       {
  5152. +                           crystalNME = item.getItem().getName().toLowerCase().trim();
  5153. +                           crystalNEW = id + 1;
  5154. +                       }
  5155. +                      
  5156. +                       // Done
  5157. +                       crystalOLD = id;
  5158. +                       break;
  5159. +                   }
  5160. +               }
  5161. +               if (!isSuccess)
  5162. +               {
  5163. +                   break;
  5164. +               }
  5165. +           }
  5166. +          
  5167. +           // If the crystal level is way too high for this mob, say that we can't increase it
  5168. +           if ((crystalLVL < minAbsorbLevel) || (crystalLVL >= maxAbsorbLevel))
  5169. +           {
  5170. +               doLevelup = false;
  5171. +           }
  5172. +          
  5173. +           // The player doesn't have any crystals with him get to the next player.
  5174. +           if ((crystalQTY < 1) || (crystalQTY > 1) || !isSuccess || !doLevelup)
  5175. +           {
  5176. +               // Too many crystals in inventory.
  5177. +               if (crystalQTY > 1)
  5178. +               {
  5179. +                   player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_FAILED_RESONATION));
  5180. +               }
  5181. +               // The soul crystal stage of the player is way too high
  5182. +               else if (!doLevelup && (crystalQTY > 0))
  5183. +               {
  5184. +                   player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_REFUSED));
  5185. +               }
  5186. +              
  5187. +               crystalQTY = 0;
  5188. +               continue;
  5189. +           }
  5190. +          
  5191. +           // Ember and Anakazel(78) are not 100% success rate and each individual
  5192. +           // member of the party has a failure rate on leveling.
  5193. +           if (isBossMob && ((getNpcId() == 10319) || (getNpcId() == 10338)))
  5194. +           {
  5195. +               doLevelup = false;
  5196. +           }
  5197. +          
  5198. +           // If succeeds or it is a boss mob, level up the crystal.
  5199. +           if ((isBossMob && doLevelup) || (dice <= SoulCrystal.LEVEL_CHANCE))
  5200. +           {
  5201. +               // Give staged crystal
  5202. +               exchangeCrystal(player, crystalOLD, crystalNEW, false);
  5203. +           }
  5204. +           // If true and not a boss mob, break the crystal.
  5205. +           else if (!isBossMob && (dice >= (100.0 - SoulCrystal.BREAK_CHANCE)))
  5206. +           {
  5207. +               // Remove current crystal an give a broken open.
  5208. +               if (crystalNME.startsWith("red"))
  5209. +               {
  5210. +                   exchangeCrystal(player, crystalOLD, SoulCrystal.RED_BROKEN_CRYSTAL, true);
  5211. +               }
  5212. +               else if (crystalNME.startsWith("gre"))
  5213. +               {
  5214. +                   exchangeCrystal(player, crystalOLD, SoulCrystal.GRN_BROKEN_CYRSTAL, true);
  5215. +               }
  5216. +               else if (crystalNME.startsWith("blu"))
  5217. +               {
  5218. +                   exchangeCrystal(player, crystalOLD, SoulCrystal.BLU_BROKEN_CRYSTAL, true);
  5219. +               }
  5220. +              
  5221. +               resetAbsorbList();
  5222. +           }
  5223. +           else
  5224. +           {
  5225. +               player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_FAILED));
  5226. +           }
  5227. +       }
  5228. +   }
  5229. +  
  5230. +   private void exchangeCrystal(L2PcInstance player, int takeid, int giveid, boolean broke)
  5231. +   {
  5232. +       L2ItemInstance Item = player.getInventory().destroyItemByItemId("SoulCrystal", takeid, 1, player, this);
  5233. +       if (Item != null)
  5234. +       {
  5235. +           // Prepare inventory update packet
  5236. +           InventoryUpdate playerIU = new InventoryUpdate();
  5237. +           playerIU.addRemovedItem(Item);
  5238. +          
  5239. +           // Add new crystal to the killer's inventory
  5240. +           Item = player.getInventory().addItem("SoulCrystal", giveid, 1, player, this);
  5241. +           playerIU.addItem(Item);
  5242. +          
  5243. +           // Send a sound event and text message to the player
  5244. +           if (broke)
  5245. +           {
  5246. +               player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_BROKE));
  5247. +           }
  5248. +           else
  5249. +           {
  5250. +               player.sendPacket(new SystemMessage(SystemMessage.SOUL_CRYSTAL_ABSORBING_SUCCEEDED));
  5251. +           }
  5252. +          
  5253. +           // Send system message
  5254. +           SystemMessage sms = new SystemMessage(SystemMessage.EARNED_ITEM);
  5255. +           sms.addItemName(giveid);
  5256. +           player.sendPacket(sms);
  5257. +          
  5258. +           // Send inventory update packet
  5259. +           player.sendPacket(playerIU);
  5260. +       }
  5261. +   }
  5262. +  
  5263. +   private void resetAbsorbList()
  5264. +   {
  5265. +       _absorbed = false;
  5266. +       _absorbersList.clear();
  5267. +   }
  5268. +  
  5269. +   /**
  5270. +    * Calculate the Experience and SP to distribute to attacker (L2PcInstance, L2SummonInstance or L2Party) of the L2Attackable.<BR>
  5271. +    * <BR>
  5272. +    * @param diff The difference of level between attacker (L2PcInstance, L2SummonInstance or L2Party) and the L2Attackable
  5273. +    * @param damage The damages given by the attacker (L2PcInstance, L2SummonInstance or L2Party)
  5274. +    */
  5275. +   private int[] calculateExpAndSp(int diff, int damage)
  5276. +   {
  5277. +       long xp;
  5278. +       long sp;
  5279. +      
  5280. +       if (diff < -5)
  5281. +       {
  5282. +           diff = -5; // makes possible to use ALT_GAME_EXPONENT configuration
  5283. +       }
  5284. +       xp = ((long) getExpReward() * damage) / getMaxHp();
  5285. +       if (Config.ALT_GAME_EXPONENT_XP != 0)
  5286. +       {
  5287. +           xp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_XP);
  5288. +       }
  5289. +      
  5290. +       sp = ((long) getSpReward() * damage) / getMaxHp();
  5291. +       if (Config.ALT_GAME_EXPONENT_SP != 0)
  5292. +       {
  5293. +           sp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_SP);
  5294. +       }
  5295. +      
  5296. +       if ((Config.ALT_GAME_EXPONENT_XP == 0) && (Config.ALT_GAME_EXPONENT_SP == 0))
  5297. +       {
  5298. +           // deep blue mob, is more than 8 levels below attacker lvl
  5299. +           if (diff > 8)
  5300. +           {
  5301. +               xp = 0;
  5302. +               sp = 0;
  5303. +           }
  5304. +           // green or light blue mob, is 6 to 8 levels below attacker lvl
  5305. +           else if (diff > 5)
  5306. +           {
  5307. +               xp -= (diff * xp) / 10;
  5308. +               sp -= (diff * sp) / 10;
  5309. +           }
  5310. +          
  5311. +           if (xp <= 0)
  5312. +           {
  5313. +               xp = 0;
  5314. +               sp = 0;
  5315. +           }
  5316. +           else if (sp <= 0)
  5317. +           {
  5318. +               sp = 0;
  5319. +           }
  5320. +       }
  5321. +      
  5322. +       int[] tmp =
  5323. +       {
  5324. +           (int) xp,
  5325. +           (int) sp
  5326. +       };
  5327. +      
  5328. +       return tmp;
  5329. +   }
  5330. +  
  5331. +   public int calculateOverhitExp(int normalExp)
  5332. +   {
  5333. +       // Get the percentage based on the total of extra (over-hit) damage done relative to the total (maximum) ammount of HP on the L2Attackable
  5334. +       double overhitPercentage = ((getOverhitDamage() * 100) / getMaxHp());
  5335. +      
  5336. +       // Over-hit damage percentages are limited to 25% max
  5337. +       if (overhitPercentage > 25)
  5338. +       {
  5339. +           overhitPercentage = 25;
  5340. +       }
  5341. +      
  5342. +       // Get the overhit exp bonus according to the above over-hit damage percentage
  5343. +       // (1/1 basis - 13% of over-hit damage, 13% of extra exp is given, and so on...)
  5344. +       double overhitExp = ((overhitPercentage / 100) * normalExp);
  5345. +      
  5346. +       // Return the rounded ammount of exp points to be added to the player's normal exp reward
  5347. +       int bonusOverhit = (int) Math.round(overhitExp);
  5348. +       return bonusOverhit;
  5349. +   }
  5350. +  
  5351. +   /**
  5352. +    * Return True.<BR>
  5353. +    * <BR>
  5354. +    */
  5355. +   @Override
  5356. +   public boolean isAttackable()
  5357. +   {
  5358. +       return true;
  5359. +   }
  5360. +  
  5361. +   @Override
  5362. +   public void onSpawn()
  5363. +   {
  5364. +       super.onSpawn();
  5365. +       // Clear mob spoil,seed
  5366. +       setSpoil(false);
  5367. +      
  5368. +       // Clear all aggro char from list
  5369. +       clearAggroList();
  5370. +       // Clear Harvester Reward List
  5371. +       _harvestItems = null;
  5372. +       // Clear mod Seeded stat
  5373. +       setSeeded(false);
  5374. +       // Clear overhit value
  5375. +       overhitEnabled(false);
  5376. +      
  5377. +       _sweepItems = null;
  5378. +       resetAbsorbList();
  5379. +      
  5380. +       setWalking();
  5381. +      
  5382. +       // check the region where this mob is, do not activate the AI if region is inactive.
  5383. +       if (!isInActiveRegion())
  5384. +       {
  5385. +           if (this instanceof L2SiegeGuardInstance)
  5386. +           {
  5387. +               ((L2SiegeGuardAI) getAI()).stopAITask();
  5388. +           }
  5389. +           else
  5390. +           {
  5391. +               ((L2AttackableAI) getAI()).stopAITask();
  5392. +           }
  5393. +       }
  5394. +   }
  5395. +  
  5396. +   public void setSeeded()
  5397. +   {
  5398. +       if ((_seedType != 0) && (_seeder != null))
  5399. +       {
  5400. +           setSeeded(_seedType, _seeder.getLevel());
  5401. +       }
  5402. +   }
  5403. +  
  5404. +   public void setSeeded(int id, L2PcInstance seeder)
  5405. +   {
  5406. +       if (!_seeded)
  5407. +       {
  5408. +           _seedType = id;
  5409. +           _seeder = seeder;
  5410. +       }
  5411. +   }
  5412. +  
  5413. +   public void setSeeded(int id, int seederLvl)
  5414. +   {
  5415. +       _seeded = true;
  5416. +       _seedType = id;
  5417. +       int count = 1;
  5418. +      
  5419. +       Map<Integer, L2Skill> skills = getTemplate().getSkills();
  5420. +       if (skills != null)
  5421. +       {
  5422. +           for (int skillId : skills.keySet())
  5423. +           {
  5424. +               switch (skillId)
  5425. +               {
  5426. +                   case 4303: // Strong type x2
  5427. +                       count *= 2;
  5428. +                       break;
  5429. +                   case 4304: // Strong type x3
  5430. +                       count *= 3;
  5431. +                       break;
  5432. +                   case 4305: // Strong type x4
  5433. +                       count *= 4;
  5434. +                       break;
  5435. +                   case 4306: // Strong type x5
  5436. +                       count *= 5;
  5437. +                       break;
  5438. +                   case 4307: // Strong type x6
  5439. +                       count *= 6;
  5440. +                       break;
  5441. +                   case 4308: // Strong type x7
  5442. +                       count *= 7;
  5443. +                       break;
  5444. +                   case 4309: // Strong type x8
  5445. +                       count *= 8;
  5446. +                       break;
  5447. +                   case 4310: // Strong type x9
  5448. +                       count *= 9;
  5449. +                       break;
  5450. +               }
  5451. +           }
  5452. +       }
  5453. +      
  5454. +       int diff = (getLevel() - (L2Manor.getInstance().getSeedLevel(_seedType) - 5));
  5455. +      
  5456. +       // hi-lvl mobs bonus
  5457. +       if (diff > 0)
  5458. +       {
  5459. +           count += diff;
  5460. +       }
  5461. +      
  5462. +       FastList<RewardItem> harvested = new FastList<RewardItem>();
  5463. +      
  5464. +       harvested.add(new RewardItem(L2Manor.getInstance().getCropType(_seedType), count * Config.RATE_DROP_MANOR));
  5465. +      
  5466. +       _harvestItems = harvested.toArray(new RewardItem[harvested.size()]);
  5467. +   }
  5468. +  
  5469. +   public void setSeeded(boolean seeded)
  5470. +   {
  5471. +       _seeded = seeded;
  5472. +   }
  5473. +  
  5474. +   public L2PcInstance getSeeder()
  5475. +   {
  5476. +       return _seeder;
  5477. +   }
  5478. +  
  5479. +   public int getSeedType()
  5480. +   {
  5481. +       return _seedType;
  5482. +   }
  5483. +  
  5484. +   public boolean isSeeded()
  5485. +   {
  5486. +       return _seeded;
  5487. +   }
  5488. +  
  5489. +   private int getAbsorbLevel()
  5490. +   {
  5491. +       return getTemplate().absorb_level;
  5492. +   }
  5493. +  
  5494. +   /**
  5495. +    * Check if the server allows Random Animation.<BR>
  5496. +    * <BR>
  5497. +    */
  5498. +   @Override
  5499. +   public boolean hasRandomAnimation()
  5500. +   {
  5501. +       return ((Config.MAX_MONSTER_ANIMATION > 0) && !(this instanceof L2BossInstance));
  5502. +   }
  5503.  }
  5504. \ No newline at end of file
  5505. Index: java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java
  5506. ===================================================================
  5507. --- java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java  (revision 355)
  5508. +++ java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java  (working copy)
  5509. @@ -25,7 +25,6 @@
  5510.  
  5511.  import javolution.lang.TextBuilder;
  5512.  import javolution.util.FastList;
  5513. -
  5514.  import net.sf.l2j.Config;
  5515.  import net.sf.l2j.gameserver.ClientThread;
  5516.  import net.sf.l2j.gameserver.Olympiad;
  5517. @@ -49,6 +48,7 @@
  5518.  import net.sf.l2j.gameserver.model.L2Attackable;
  5519.  import net.sf.l2j.gameserver.model.L2Character;
  5520.  import net.sf.l2j.gameserver.model.L2Clan;
  5521. +import net.sf.l2j.gameserver.model.L2DropCategory;
  5522.  import net.sf.l2j.gameserver.model.L2DropData;
  5523.  import net.sf.l2j.gameserver.model.L2ItemInstance;
  5524.  import net.sf.l2j.gameserver.model.L2Multisell;
  5525. @@ -88,1411 +88,1558 @@
  5526.  import net.sf.l2j.gameserver.templates.L2Weapon;
  5527.  
  5528.  /**
  5529. - * This class represents a Non-Player-Character in the world. It can be a monster or a friendly character.
  5530. - * It also uses a template to fetch some static values. The templates are hardcoded in the client, so we can rely on them.<BR><BR>
  5531. - *
  5532. - * L2Character :<BR><BR>
  5533. - * <li>L2Attackable</li>
  5534. - * <li>L2BoxInstance</li>
  5535. - * <li>L2FolkInstance</li>
  5536. - *
  5537. + * This class represents a Non-Player-Character in the world. It can be a monster or a friendly character. It also uses a template to fetch some static values. The templates are hardcoded in the client, so we can rely on them.<BR>
  5538. + * <BR>
  5539. + * L2Character :<BR>
  5540. + * <BR>
  5541. + * <li>L2Attackable</li> <li>L2BoxInstance</li> <li>L2FolkInstance</li>
  5542.   * @version $Revision: 1.32.2.7.2.24 $ $Date: 2005/04/11 10:06:09 $
  5543.   */
  5544.  public class L2NpcInstance extends L2Character
  5545.  {
  5546. -    //private static Logger _log = Logger.getLogger(L2NpcInstance.class.getName());
  5547. -
  5548. -    /** The interaction distance of the L2NpcInstance(is used as offset in MovetoLocation method) */
  5549. -    public static final int INTERACTION_DISTANCE = 150;
  5550. -
  5551. -    /** The L2Spawn object that manage this L2NpcInstance */
  5552. -    private L2Spawn _spawn;
  5553. -
  5554. -    /** The flag to specify if this L2NpcInstance is busy */
  5555. -    private boolean _IsBusy = false;
  5556. -    
  5557. -    /** The busy message for this L2NpcInstance */
  5558. -    private String _BusyMessage = "";
  5559. -
  5560. -    /** True if endDecayTask has already been called */
  5561. -    volatile boolean _isDecayed = false;
  5562. -
  5563. -    /** True if a Dwarf has used Spoil on this L2NpcInstance */
  5564. -    private boolean _IsSpoil = false;
  5565. -
  5566. -
  5567. -
  5568. -    /** The castle index in the array of L2Castle this L2NpcInstance belongs to */
  5569. -    private int _castleIndex = -2;
  5570. -
  5571. -
  5572. -    public boolean isEventMob = false;
  5573. -
  5574. -
  5575. -    private boolean _isInTown = false;
  5576. -
  5577. -    private int _isSpoiledBy = 0;
  5578. -
  5579. -    protected RandomAnimationTask _rAniTask = null;
  5580. -
  5581. -    private int _currentCollisionHeight;
  5582. -    private int _currentCollisionRadius;
  5583. -
  5584. -    /** Task launching the function onRandomAnimation() */
  5585. -    protected class RandomAnimationTask implements Runnable
  5586. -    {
  5587. -        public void run()
  5588. -        {
  5589. -            try
  5590. -            {
  5591. -                if (this != _rAniTask)
  5592. -                    return;
  5593. -
  5594. -                if (L2NpcInstance.this instanceof L2Attackable)
  5595. -                {
  5596. -                    if (getAI().getIntention() != AI_INTENTION_ACTIVE)
  5597. -                        return;
  5598. -                }
  5599. -
  5600. -                else
  5601. -                {
  5602. -                    if (!isInActiveRegion())
  5603. -                        return;
  5604. -                }
  5605. -
  5606. -                if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))
  5607. -                    onRandomAnimation();
  5608. -
  5609. -                startRandomAnimationTimer();
  5610. -            }
  5611. -            catch (Throwable t) {}
  5612. -        }
  5613. -    }
  5614. -
  5615. -
  5616. -    /**
  5617. -     * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance and create a new RandomAnimation Task.<BR><BR>
  5618. -     */
  5619. -    public void onRandomAnimation()
  5620. -    {
  5621. -        // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  5622. -        SocialAction sa = new SocialAction(getObjectId(), Rnd.get(1, 3));
  5623. -        broadcastPacket(sa);
  5624. -    }
  5625. -
  5626. -    /**
  5627. -     * Create a RandomAnimation Task that will be launched after the calculated delay.<BR><BR>
  5628. -     */
  5629. -    public void startRandomAnimationTimer()
  5630. -    {
  5631. -        if (!hasRandomAnimation())
  5632. -            return;
  5633. -
  5634. -        int minWait =  this instanceof L2Attackable ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION;
  5635. -        int maxWait = this instanceof L2Attackable ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION;
  5636. -
  5637. -        // Calculate the delay before the next animation
  5638. -        int interval = Rnd.get(minWait, maxWait) * 1000;
  5639. -
  5640. -        // Create a RandomAnimation Task that will be launched after the calculated delay
  5641. -        _rAniTask = new RandomAnimationTask();
  5642. -        ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);
  5643. -    }
  5644. -
  5645. -    /**
  5646. -     * Check if the server allows Random Animation.<BR><BR>
  5647. -     */
  5648. -    public boolean hasRandomAnimation()
  5649. -    {
  5650. -        return (Config.MAX_NPC_ANIMATION > 0);
  5651. -    }
  5652. -
  5653. -    /**
  5654. -     * Constructor of L2NpcInstance (use L2Character constructor).<BR><BR>
  5655. -     *  
  5656. -     * <B><U> Actions</U> :</B><BR><BR>
  5657. -     * <li>Call the L2Character constructor to set the _template of the L2Character (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR)  </li>
  5658. -     * <li>Set the name of the L2Character</li>
  5659. -     * <li>Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it </li><BR><BR>
  5660. -     *
  5661. -     * @param objectId Identifier of the object to initialized
  5662. -     * @param template The L2NpcTemplate to apply to the NPC
  5663. -     *
  5664. -     */
  5665. -    public L2NpcInstance(int objectId, L2NpcTemplate template)
  5666. -    {
  5667. -        // Call the L2Character constructor to set the _template of the L2Character, copy skills from template to object
  5668. -        // and link _calculators to NPC_STD_CALCULATOR
  5669. -        super(objectId, template);
  5670. -        getKnownList();
  5671. -        getStat();
  5672. -        getStatus();
  5673. -
  5674. -        super.initCharStatusUpdateValues(); // init status update values
  5675. -
  5676. -        _currentCollisionHeight = getTemplate().collisionHeight;
  5677. -        _currentCollisionRadius = getTemplate().collisionRadius;
  5678. -
  5679. -        if (template == null)
  5680. -        {
  5681. -            _log.severe("No template for Npc. Please check your datapack is setup correctly.");
  5682. -            return;
  5683. -        }
  5684. -        
  5685. -        // Set the name of the L2Character
  5686. -        setName(template.name);
  5687. -    }
  5688. -
  5689. -    public NpcKnownList getKnownList()
  5690. -    {
  5691. -        if (super.getKnownList() == null || !(super.getKnownList() instanceof NpcKnownList))
  5692. -            setKnownList(new NpcKnownList(this));
  5693. -        return (NpcKnownList)super.getKnownList();
  5694. -    }
  5695. -
  5696. -    public NpcStat getStat()
  5697. -    {
  5698. -        if (super.getStat() == null || !(super.getStat() instanceof NpcStat))
  5699. -            setStat(new NpcStat(this));
  5700. -        return (NpcStat)super.getStat();
  5701. -    }
  5702. -
  5703. -    public NpcStatus getStatus()
  5704. -    {
  5705. -        if (super.getStatus() == null || !(super.getStatus() instanceof NpcStatus))
  5706. -            setStatus(new NpcStatus(this));
  5707. -        return (NpcStatus)super.getStatus();
  5708. -    }
  5709. -
  5710. -
  5711. -    /** Return the L2NpcTemplate of the L2NpcInstance. */
  5712. -    public final L2NpcTemplate getTemplate()
  5713. -    {
  5714. -        return (L2NpcTemplate)super.getTemplate();
  5715. -    }
  5716. -    
  5717. -    /**
  5718. -     * Return the generic Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5719. -     */
  5720. -    public int getNpcId()
  5721. -    {
  5722. -        return getTemplate().npcId;
  5723. -    }
  5724. -    
  5725. -    public boolean isAttackable()
  5726. -    {
  5727. -        return true;
  5728. -    }
  5729. -    
  5730. -    /**
  5731. -     * Return the faction Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5732. -     *
  5733. -     * <B><U> Concept</U> :</B><BR><BR>
  5734. -     * If a NPC belows to a Faction, other NPC of the faction inside the Faction range will help it if it's attacked<BR><BR>
  5735. -     *
  5736. -     */
  5737. -    public final String getFactionId()
  5738. -    {
  5739. -        return getTemplate().factionId;
  5740. -    }
  5741. -    
  5742. -    /**
  5743. -     * Return the Level of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5744. -     */
  5745. -    public final int getLevel()
  5746. -    {
  5747. -        return getTemplate().level;
  5748. -    }
  5749. -    
  5750. -    /**
  5751. -     * Return True if the L2NpcInstance is agressive (ex : L2MonsterInstance in function of aggroRange).<BR><BR>
  5752. -     */
  5753. -    public boolean isAggressive()
  5754. -    {
  5755. -        return false;
  5756. -    }
  5757. -    
  5758. -    /**
  5759. -     * Return the Aggro Range of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5760. -     */
  5761. -    public int getAggroRange()
  5762. -    {
  5763. -        return getTemplate().aggroRange;
  5764. -    }
  5765. -    
  5766. -    /**
  5767. -     * Return the Faction Range of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5768. -     */
  5769. -    public int getFactionRange()
  5770. -    {
  5771. -        return getTemplate().factionRange;
  5772. -    }
  5773. -    
  5774. -    /**
  5775. -     * Return True if this L2NpcInstance is undead in function of the L2NpcTemplate.<BR><BR>
  5776. -     */
  5777. -    public boolean isUndead()
  5778. -    {
  5779. -        return getTemplate().isUndead;
  5780. -    }
  5781. -    
  5782. -    /**
  5783. -     * Send a packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance.<BR><BR>
  5784. -     */
  5785. -    public void updateAbnormalEffect()
  5786. -    {
  5787. -
  5788. -
  5789. -        // Send a Server->Client packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  5790. -        for (L2PcInstance player : getKnownList().getKnownPlayers().values())
  5791. -        {
  5792. -            if (player != null)
  5793. -            {
  5794. -                if (getRunSpeed() == 0)
  5795. -                    player.sendPacket(new ServerObjectInfo(this, player));
  5796. -                else
  5797. -                    player.sendPacket(new NpcInfo(this, player));
  5798. -            }
  5799. -        }
  5800. -    }
  5801. -    
  5802. -    /**
  5803. -     * Return the distance under which the object must be add to _knownObject in function of the object type.<BR><BR>
  5804. -     *  
  5805. -     * <B><U> Values </U> :</B><BR><BR>
  5806. -     * <li> object is a L2FolkInstance : 0 (don't remember it) </li>
  5807. -     * <li> object is a L2Character : 0 (don't remember it) </li>
  5808. -     * <li> object is a L2PlayableInstance : 1500 </li>
  5809. -     * <li> others : 500 </li><BR><BR>
  5810. -     *
  5811. -     * <B><U> Overriden in </U> :</B><BR><BR>
  5812. -     * <li> L2Attackable</li><BR><BR>
  5813. -     *
  5814. -     * @param object The Object to add to _knownObject
  5815. -     *
  5816. -     */
  5817. -    public int getDistanceToWatchObject(L2Object object)
  5818. -    {
  5819. -        if (object instanceof L2FestivalGuideInstance)
  5820. -            return 10000;
  5821. -        
  5822. -        if (object instanceof L2FolkInstance || !(object instanceof L2Character))
  5823. -            return 0;
  5824. -        
  5825. -        if (object instanceof L2PlayableInstance)
  5826. -            return 1500;
  5827. -        
  5828. -        return 500;
  5829. -    }
  5830. -    
  5831. -    /**
  5832. -     * Return the distance after which the object must be remove from _knownObject in function of the object type.<BR><BR>
  5833. -     *  
  5834. -     * <B><U> Values </U> :</B><BR><BR>
  5835. -     * <li> object is not a L2Character : 0 (don't remember it) </li>
  5836. -     * <li> object is a L2FolkInstance : 0 (don't remember it)</li>
  5837. -     * <li> object is a L2PlayableInstance : 3000 </li>
  5838. -     * <li> others : 1000 </li><BR><BR>
  5839. -     *
  5840. -     * <B><U> Overriden in </U> :</B><BR><BR>
  5841. -     * <li> L2Attackable</li><BR><BR>
  5842. -     *
  5843. -     * @param object The Object to remove from _knownObject
  5844. -     *
  5845. -     */
  5846. -    public int getDistanceToForgetObject(L2Object object)
  5847. -    {
  5848. -        return 2*getDistanceToWatchObject(object);
  5849. -    }
  5850. -    
  5851. -    /**
  5852. -     * Return False.<BR><BR>
  5853. -     *  
  5854. -     * <B><U> Overriden in </U> :</B><BR><BR>
  5855. -     * <li> L2MonsterInstance : Check if the attacker is not another L2MonsterInstance</li>
  5856. -     * <li> L2PcInstance</li><BR><BR>
  5857. -     */
  5858. -    public boolean isAutoAttackable(@SuppressWarnings("unused") L2Character attacker)
  5859. -    {
  5860. -        return false;
  5861. -    }
  5862. -    
  5863. -    /**
  5864. -     * Return the Identifier of the item in the left hand of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5865. -     */
  5866. -    public int getLeftHandItem()
  5867. -    {
  5868. -        return getTemplate().lhand;
  5869. -    }
  5870. -    
  5871. -    /**
  5872. -     * Return the Identifier of the item in the right hand of this L2NpcInstance contained in the L2NpcTemplate.<BR><BR>
  5873. -     */
  5874. -    public int getRightHandItem()
  5875. -    {
  5876. -        return getTemplate().rhand;
  5877. -    }
  5878. -    
  5879. -    /**
  5880. -     * Return True if this L2NpcInstance has drops that can be sweeped.<BR><BR>
  5881. -     */
  5882. -    public boolean isSpoil()
  5883. -    {
  5884. -        return _IsSpoil;
  5885. -    }
  5886. -    
  5887. -    /**
  5888. -     * Set the spoil state of this L2NpcInstance.<BR><BR>
  5889. -     */
  5890. -    public void setSpoil(boolean isSpoil)
  5891. -    {
  5892. -        _IsSpoil = isSpoil;
  5893. -    }
  5894. -
  5895. -    public final int getIsSpoiledBy()
  5896. -    {
  5897. -       return _isSpoiledBy;
  5898. -    }
  5899. -    
  5900. -    public final void setIsSpoiledBy(int value)
  5901. -    {
  5902. -       _isSpoiledBy = value;
  5903. -    }
  5904. -    
  5905. -    /**
  5906. -     * Return the busy status of this L2NpcInstance.<BR><BR>
  5907. -     */
  5908. -    public final boolean isBusy()
  5909. -    {
  5910. -        return _IsBusy;
  5911. -    }
  5912. -    
  5913. -    /**
  5914. -     * Set the busy status of this L2NpcInstance.<BR><BR>
  5915. -     */
  5916. -    public void setBusy(boolean isBusy)
  5917. -    {
  5918. -        _IsBusy = isBusy;
  5919. -    }
  5920. -    
  5921. -    /**
  5922. -     * Return the busy message of this L2NpcInstance.<BR><BR>
  5923. -     */
  5924. -    public final String getBusyMessage()
  5925. -    {
  5926. -        return _BusyMessage;
  5927. -    }
  5928. -    
  5929. -    /**
  5930. -     * Set the busy message of this L2NpcInstance.<BR><BR>
  5931. -     */
  5932. -    public void setBusyMessage(String message)
  5933. -    {
  5934. -        _BusyMessage = message;
  5935. -    }
  5936. -
  5937. -    protected boolean canTarget(L2PcInstance player)
  5938. -    {
  5939. -        if (player.isConfused())
  5940. -        {
  5941. -            player.sendPacket(new ActionFailed());
  5942. -            return false;
  5943. -        }
  5944. -        // TODO: More checks...
  5945. -
  5946. -        return true;
  5947. -    }
  5948. -
  5949. -    public boolean canInteract(L2PcInstance player)
  5950. -    {
  5951. -        // TODO: NPC busy check etc...
  5952. -
  5953. -        if (player.isCastingNow() || player.isSitting())
  5954. -            return false;
  5955. -
  5956. -        if (player.isDead() || player.isFakeDeath())
  5957. -            return false;
  5958. -
  5959. -        if (player.getPrivateStoreType() != 0)
  5960. -            return false;
  5961. -
  5962. -
  5963. -        if (!isInsideRadius(player, INTERACTION_DISTANCE, false, false))
  5964. -            return false;
  5965. -
  5966. -        return true;
  5967. -    }
  5968. -
  5969. -    /**
  5970. -     * Manage actions when a player click on the L2NpcInstance.<BR><BR>
  5971. -     *
  5972. -     * <B><U> Actions on first click on the L2NpcInstance (Select it)</U> :</B><BR><BR>
  5973. -     * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li>
  5974. -     * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  5975. -     * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP bar </li>
  5976. -     * <li>Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client </li><BR><BR>
  5977. -     *
  5978. -     * <B><U> Actions on second click on the L2NpcInstance (Attack it/Intercat with it)</U> :</B><BR><BR>
  5979. -     * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  5980. -     * <li>If L2NpcInstance is autoAttackable, notify the L2PcInstance AI with AI_INTENTION_ATTACK (after a height verification)</li>
  5981. -     * <li>If L2NpcInstance is NOT autoAttackable, notify the L2PcInstance AI with AI_INTENTION_INTERACT (after a distance verification) and show message</li><BR><BR>
  5982. -     *
  5983. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid
  5984. -     * that client wait an other packet</B></FONT><BR><BR>
  5985. -     *
  5986. -     * <B><U> Example of use </U> :</B><BR><BR>
  5987. -     * <li> Client packet : Action, AttackRequest</li><BR><BR>
  5988. -     *
  5989. -     * <B><U> Overriden in </U> :</B><BR><BR>
  5990. -     * <li> L2ArtefactInstance : Manage only fisrt click to select Artefact</li><BR><BR>
  5991. -     * <li> L2GuardInstance : </li><BR><BR>
  5992. -     *
  5993. -     * @param player The L2PcInstance that start an action on the L2NpcInstance
  5994. -     *
  5995. -     */
  5996. -    public void onAction(L2PcInstance player)
  5997. -    {
  5998. -        if (!canTarget(player))
  5999. -            return;
  6000. -
  6001. -        // Check if the L2PcInstance already target the L2NpcInstance
  6002. -        if (this != player.getTarget())
  6003. -        {
  6004. -            if (Config.DEBUG) _log.fine("new target selected:"+getObjectId());
  6005. -
  6006. -            // Set the target of the L2PcInstance player
  6007. -            player.setTarget(this);
  6008. -
  6009. -            // Check if the player is attackable (without a forced attack)
  6010. -            if (isAutoAttackable(player))
  6011. -            {
  6012. -                // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  6013. -                // The player.getLevel() - getLevel() permit to display the correct color in the select window
  6014. -                MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  6015. -                player.sendPacket(my);
  6016. -
  6017. -                // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  6018. -                StatusUpdate su = new StatusUpdate(getObjectId());
  6019. -                su.addAttribute(StatusUpdate.CUR_HP, (int)getCurrentHp());
  6020. -                su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  6021. -                player.sendPacket(su);
  6022. -            }
  6023. -            else
  6024. -            {
  6025. -                // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  6026. -                MyTargetSelected my = new MyTargetSelected(getObjectId(), 0);
  6027. -                player.sendPacket(my);
  6028. -            }
  6029. -
  6030. -            // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client
  6031. -            player.sendPacket(new ValidateLocation(this));
  6032. -        }
  6033. -        else
  6034. -        {
  6035. -            player.sendPacket(new ValidateLocation(this));
  6036. -            // Check if the player is attackable (without a forced attack) and isn't dead
  6037. -            if (isAutoAttackable(player) && !isAlikeDead())
  6038. -            {
  6039. -                // Check the height difference
  6040. -                if (Math.abs(player.getZ() - getZ()) < 400) // this max heigth difference might need some tweaking
  6041. -                {
  6042. -                    // Set the L2PcInstance Intention to AI_INTENTION_ATTACK
  6043. -                    player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
  6044. -
  6045. -                }
  6046. -                else
  6047. -                {
  6048. -                    // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  6049. -                    player.sendPacket(new ActionFailed());
  6050. -                }
  6051. -            }
  6052. -            else if (!isAutoAttackable(player))
  6053. -            {
  6054. -                // Calculate the distance between the L2PcInstance and the L2NpcInstance
  6055. -                if (!canInteract(player))
  6056. -                {
  6057. -                    // Notify the L2PcInstance AI with AI_INTENTION_INTERACT
  6058. -                    player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
  6059. -                }
  6060. -                else
  6061. -                {
  6062. -                    // Send a Server->Client packet SocialAction to the all L2PcInstance on the _knownPlayer of the L2NpcInstance
  6063. -                    // to display a social action of the L2NpcInstance on their client
  6064. -                    SocialAction sa = new SocialAction(getObjectId(), Rnd.get(8));
  6065. -                    broadcastPacket(sa);
  6066. -
  6067. -                    // Open a chat window on client with the text of the L2NpcInstance
  6068. -                    if (isEventMob)
  6069. -
  6070. -                        L2Event.showEventHtml(player, String.valueOf(getObjectId()));
  6071. -
  6072. -                    else
  6073. -                    {
  6074. -                        Quest[] qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  6075. -                        if ((qlsa != null) && qlsa.length > 0)
  6076. -                            player.setLastQuestNpcObject(getObjectId());
  6077. -
  6078. -                        Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.NPC_FIRST_TALK);
  6079. -                        if ((qlst != null) && qlst.length == 1)
  6080. -                            qlst[0].notifyFirstTalk(this, player);
  6081. -                        else
  6082. -
  6083. -                            showChatWindow(player, 0);
  6084. -                    }
  6085. -
  6086. -                }
  6087. -            }
  6088. -            else
  6089. -                player.sendPacket(new ActionFailed());
  6090. -        }
  6091. -    }
  6092. -    
  6093. -    /**
  6094. -     * Manage and Display the GM console to modify the L2NpcInstance (GM only).<BR><BR>
  6095. -     *
  6096. -     * <B><U> Actions (If the L2PcInstance is a GM only)</U> :</B><BR><BR>
  6097. -     * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li>
  6098. -     * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li>
  6099. -     * <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the L2PcInstance in order to update L2NpcInstance HP bar </li>
  6100. -     * <li>Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance </li><BR><BR>
  6101. -     *
  6102. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid
  6103. -     * that client wait an other packet</B></FONT><BR><BR>
  6104. -     *
  6105. -     * <B><U> Example of use </U> :</B><BR><BR>
  6106. -     * <li> Client packet : Action</li><BR><BR>
  6107. -     *
  6108. -     * @param client The thread that manage the player that pessed Shift and click on the L2NpcInstance
  6109. -     *
  6110. -     */
  6111. -    public void onActionShift(ClientThread client)
  6112. -    {
  6113. -        // Get the L2PcInstance corresponding to the thread
  6114. -        L2PcInstance player = client.getActiveChar();
  6115. -
  6116. -        if (player == null)
  6117. -            return;
  6118. -
  6119. -        // Check if the L2PcInstance is a GM
  6120. -        if (player.getAccessLevel() >= Config.GM_ACCESSLEVEL)
  6121. -        {
  6122. -            // Set the target of the L2PcInstance player
  6123. -            player.setTarget(this);
  6124. -            
  6125. -            // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  6126. -            // The player.getLevel() - getLevel() permit to display the correct color in the select window
  6127. -            MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  6128. -            player.sendPacket(my);
  6129. -            
  6130. -            // Check if the player is attackable (without a forced attack)
  6131. -            if (isAutoAttackable(player))
  6132. -            { 
  6133. -                // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  6134. -                StatusUpdate su = new StatusUpdate(getObjectId());
  6135. -                su.addAttribute(StatusUpdate.CUR_HP, (int)getCurrentHp() );
  6136. -                su.addAttribute(StatusUpdate.MAX_HP, getMaxHp() );
  6137. -                player.sendPacket(su);
  6138. -            }
  6139. -            
  6140. -            // Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance
  6141. -            NpcHtmlMessage html = new NpcHtmlMessage(0);
  6142. -            TextBuilder html1 = new TextBuilder("<html><body><center><font color=\"LEVEL\">NPC Information</font></center>");
  6143. -            String className = getClass().getName().substring(43);
  6144. -
  6145. -            html1.append("<br>");
  6146. -
  6147. -            html1.append("Instance Type: " + className + "<br1>Faction: " + getFactionId() + "<br1>Location ID: " + (getSpawn() != null ? getSpawn().getLocation() : 0) + "<br1>");
  6148. -            
  6149. -            if (this instanceof L2ControllableMobInstance)
  6150. -                html1.append("Mob Group: " + MobGroupTable.getInstance().getGroupForMob((L2ControllableMobInstance)this).getGroupId() + "<br>");
  6151. -            else
  6152. -                html1.append("Respawn Time: " + (getSpawn()!=null ? (getSpawn().getRespawnDelay() / 1000)+"  Seconds<br>" : "?  Seconds<br>"));
  6153. -            
  6154. -            html1.append("<table border=\"0\" width=\"100%\">");
  6155. -            html1.append("<tr><td>Object ID</td><td>"+getObjectId()+"</td><td>NPC ID</td><td>"+getTemplate().npcId+"</td></tr>");
  6156. -
  6157. -            html1.append("<tr><td>Castle</td><td>"+(getCastle() != null ? getCastle().getCastleId() : 0)+"</td><td>Coords</td><td>"+getX()+","+getY()+","+getZ()+"</td></tr>");
  6158. -
  6159. -            html1.append("<tr><td>Level</td><td>"+getLevel()+"</td><td>Aggro</td><td>"+((this instanceof L2Attackable)? ((L2Attackable)this).getAggroRange() : 0)+"</td></tr>");
  6160. -            html1.append("</table><br>");
  6161. -            
  6162. -            html1.append("<font color=\"LEVEL\">Combat</font>");
  6163. -            html1.append("<table border=\"0\" width=\"100%\">");
  6164. -            html1.append("<tr><td>Current HP</td><td>"+getCurrentHp()+"</td><td>Current MP</td><td>"+getCurrentMp()+"</td></tr>");
  6165. -            html1.append("<tr><td>Max.HP</td><td>"+(int)(getMaxHp()/getStat().calcStat(Stats.MAX_HP , 1, this, null))+"*"+getStat().calcStat(Stats.MAX_HP , 1, this, null)+"</td><td>Max.MP</td><td>"+getMaxMp()+"</td></tr>");
  6166. -            html1.append("<tr><td>P.Atk.</td><td>"+getPAtk(null)+"</td><td>M.Atk.</td><td>"+getMAtk(null,null)+"</td></tr>");
  6167. -            html1.append("<tr><td>P.Def.</td><td>"+getPDef(null)+"</td><td>M.Def.</td><td>"+getMDef(null,null)+"</td></tr>");
  6168. -            html1.append("<tr><td>Accuracy</td><td>"+getAccuracy()+"</td><td>Evasion</td><td>"+getEvasionRate(null)+"</td></tr>");
  6169. -            html1.append("<tr><td>Critical</td><td>"+getCriticalHit(null,null)+"</td><td>Speed</td><td>"+getRunSpeed()+"</td></tr>");
  6170. -            html1.append("<tr><td>Atk.Speed</td><td>"+getPAtkSpd()+"</td><td>Cast.Speed</td><td>"+getMAtkSpd()+"</td></tr>");
  6171. -            html1.append("</table><br>");
  6172. -            
  6173. -            html1.append("<font color=\"LEVEL\">Basic Stats</font>");
  6174. -            html1.append("<table border=\"0\" width=\"100%\">");
  6175. -            html1.append("<tr><td>STR</td><td>"+getSTR()+"</td><td>DEX</td><td>"+getDEX()+"</td><td>CON</td><td>"+getCON()+"</td></tr>");
  6176. -            html1.append("<tr><td>INT</td><td>"+getINT()+"</td><td>WIT</td><td>"+getWIT()+"</td><td>MEN</td><td>"+getMEN()+"</td></tr>");
  6177. -            html1.append("</table>");
  6178. -            
  6179. -            html1.append("<br><center><table><tr><td><button value=\"Edit NPC\" action=\"bypass -h admin_edit_npc " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"><br1></td>");
  6180. -            html1.append("<td><button value=\"Kill\" action=\"bypass -h admin_kill\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td><br1></tr>");
  6181. -            html1.append("<tr><td><button value=\"Show DropList\" action=\"bypass -h admin_show_droplist " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");          
  6182. -            html1.append("<td><button value=\"Delete\" action=\"bypass -h admin_delete\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");
  6183. -            html1.append("</table></center><br>");
  6184. -            html1.append("</body></html>");
  6185. -            
  6186. -            html.setHtml(html1.toString());
  6187. -            player.sendPacket(html);
  6188. -        }
  6189. -        else if(Config.ALT_GAME_VIEWNPC)
  6190. -        {
  6191. -            // Set the target of the L2PcInstance player
  6192. -            player.setTarget(this);
  6193. -            
  6194. -            // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  6195. -            // The player.getLevel() - getLevel() permit to display the correct color in the select window
  6196. -            MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  6197. -            player.sendPacket(my);
  6198. -            
  6199. -            // Check if the player is attackable (without a forced attack)
  6200. -            if (isAutoAttackable(player))
  6201. -            { 
  6202. -                // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  6203. -                StatusUpdate su = new StatusUpdate(getObjectId());
  6204. -                su.addAttribute(StatusUpdate.CUR_HP, (int)getCurrentHp());
  6205. -                su.addAttribute(StatusUpdate.MAX_HP, getMaxHp() );
  6206. -                player.sendPacket(su);
  6207. -            }
  6208. -            
  6209. -            NpcHtmlMessage html = new NpcHtmlMessage(0);
  6210. -            TextBuilder html1 = new TextBuilder("<html><body>");
  6211. -            
  6212. -            html1.append("<br><center><font color=\"LEVEL\">[Combat Stats]</font></center>");
  6213. -            html1.append("<table border=0 width=\"100%\">");
  6214. -            html1.append("<tr><td>Max.HP</td><td>"+(int)(getMaxHp()/getStat().calcStat(Stats.MAX_HP , 1, this, null))+"*"+(int) getStat().calcStat(Stats.MAX_HP , 1, this, null)+"</td><td>Max.MP</td><td>"+getMaxMp()+"</td></tr>");
  6215. -            html1.append("<tr><td>P.Atk.</td><td>"+getPAtk(null)+"</td><td>M.Atk.</td><td>"+getMAtk(null,null)+"</td></tr>");
  6216. -            html1.append("<tr><td>P.Def.</td><td>"+getPDef(null)+"</td><td>M.Def.</td><td>"+getMDef(null,null)+"</td></tr>");
  6217. -            html1.append("<tr><td>Accuracy</td><td>"+getAccuracy()+"</td><td>Evasion</td><td>"+getEvasionRate(null)+"</td></tr>");
  6218. -            html1.append("<tr><td>Critical</td><td>"+getCriticalHit(null,null)+"</td><td>Speed</td><td>"+getRunSpeed()+"</td></tr>");
  6219. -            html1.append("<tr><td>Atk.Speed</td><td>"+getPAtkSpd()+"</td><td>Cast.Speed</td><td>"+getMAtkSpd()+"</td></tr>");
  6220. -            html1.append("<tr><td>Race</td><td>"+getTemplate().race+"</td><td></td><td></td></tr>");
  6221. -            html1.append("</table>");
  6222. -
  6223. -            html1.append("<br><center><font color=\"LEVEL\">[Basic Stats]</font></center>");
  6224. -            html1.append("<table border=0 width=\"100%\">");
  6225. -            html1.append("<tr><td>STR</td><td>"+getSTR()+"</td><td>DEX</td><td>"+getDEX()+"</td><td>CON</td><td>"+getCON()+"</td></tr>");
  6226. -            html1.append("<tr><td>INT</td><td>"+getINT()+"</td><td>WIT</td><td>"+getWIT()+"</td><td>MEN</td><td>"+getMEN()+"</td></tr>");
  6227. -            html1.append("</table>");
  6228. -            
  6229. -            html1.append("<br><center><font color=\"LEVEL\">[Drop Info]</font></center>");
  6230. -            html1.append("Rates legend: <font color=\"ff0000\">50%+</font> <font color=\"00ff00\">30%+</font> <font color=\"0000ff\">less than 30%</font>");
  6231. -            html1.append("<table border=0 width=\"100%\">");
  6232. -
  6233. -
  6234. -            if (getTemplate().getDropData() != null)
  6235. -            {
  6236. -               for (L2DropData drop : getTemplate().getDropData())
  6237. -               {
  6238. -                   String name = ItemTable.getInstance().getTemplate(drop.getItemId()).getName();
  6239. -
  6240. -                   if (drop.getChance() >= 600000)
  6241. -                   html1.append("<tr><td><font color=\"ff0000\">" + name + "</font></td><td>" + (drop.isQuestDrop()?"Quest":(drop.isSweep()?"Sweep":"Drop")) + "</td></tr>");
  6242. -                   else if(drop.getChance() >= 300000)
  6243. -                   html1.append("<tr><td><font color=\"00ff00\">" + name + "</font></td><td>" + (drop.isQuestDrop()?"Quest":(drop.isSweep()?"Sweep":"Drop")) + "</td></tr>");
  6244. -                   else
  6245. -                   html1.append("<tr><td><font color=\"0000ff\">" + name + "</font></td><td>" + (drop.isQuestDrop()?"Quest":(drop.isSweep()?"Sweep":"Drop")) + "</td></tr>");
  6246. -                }
  6247. -           }
  6248. -          
  6249. -           html1.append("</table>");
  6250. -           html1.append("</body></html>");
  6251. -
  6252. -            html.setHtml(html1.toString());
  6253. -            player.sendPacket(html);
  6254. -        }
  6255. -        
  6256. -        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  6257. -        player.sendPacket(new ActionFailed());
  6258. -    }
  6259. -    
  6260. -    /** Return the L2Castle this L2NpcInstance belongs to. */
  6261. -    public final Castle getCastle()
  6262. -    {
  6263. -
  6264. -
  6265. -        if (_castleIndex < 0)
  6266. -        {
  6267. -
  6268. -            L2TownZone town = TownManager.getInstance().getTown(getX(), getY(), getZ());
  6269. -            if (town != null)
  6270. -                _castleIndex = CastleManager.getInstance().getCastleIndex(town.getTaxById());
  6271. -
  6272. -
  6273. -
  6274. -            if (_castleIndex < 0)
  6275. -                _castleIndex = CastleManager.getInstance().findNearestCastleIndex(this);
  6276. -            else
  6277. -
  6278. -                _isInTown = true; // Npc was spawned in town
  6279. -
  6280. -        }
  6281. -
  6282. -        if (_castleIndex < 0)
  6283. -            return null;
  6284. -
  6285. -
  6286. -        return CastleManager.getInstance().getCastles().get(_castleIndex);
  6287. -
  6288. -    }
  6289. -
  6290. -
  6291. -    public boolean getIsInCastleTown()
  6292. -    {
  6293. -        if (_castleIndex < 0)
  6294. -            getCastle();
  6295. -
  6296. -        return _isInTown;
  6297. -    }
  6298. -
  6299. -    /**
  6300. -     * Open a quest or chat window on client with the text of the L2NpcInstance in function of the command.<BR><BR>
  6301. -     *
  6302. -     * <B><U> Example of use </U> :</B><BR><BR>
  6303. -     * <li> Client packet : RequestBypassToServer</li><BR><BR>
  6304. -     *
  6305. -     * @param command The command string received from client
  6306. -     *
  6307. -     */
  6308. -    public void onBypassFeedback(L2PcInstance player, String command)
  6309. -    {
  6310. -
  6311. -        if (isBusy() && getBusyMessage().length() > 0)
  6312. -        {
  6313. -            player.sendPacket(new ActionFailed());
  6314. -            NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  6315. -            html.setFile("data/html/npcbusy.htm");
  6316. -            html.replace("%busymessage%", getBusyMessage());
  6317. -            html.replace("%npcname%", getName());
  6318. -            html.replace("%playername%", player.getName());
  6319. -            player.sendPacket(html);
  6320. -        }
  6321. -
  6322. -        else if (command.equalsIgnoreCase("TerritoryStatus"))
  6323. -        {
  6324. -            NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  6325. -            html.setFile("data/html/territorystatus.htm");
  6326. -            html.replace("%objectId%", String.valueOf(getObjectId()));
  6327. -            html.replace("%npcname%", getName());
  6328. -
  6329. -
  6330. -            if (getIsInCastleTown())
  6331. -            {
  6332. -                html.replace("%castlename%", getCastle().getName());
  6333. -                html.replace("%taxpercent%", "" + getCastle().getTaxPercent());
  6334. -
  6335. -
  6336. -                if (getCastle().getOwnerId() > 0)
  6337. -                {
  6338. -                    L2Clan clan = ClanTable.getInstance().getClan(getCastle().getOwnerId());
  6339. -                    html.replace("%clanname%", clan.getName());
  6340. -                    html.replace("%clanleadername%", clan.getLeaderName());
  6341. -                }
  6342. -                else
  6343. -                {
  6344. -                    html.replace("%clanname%", "NPC");
  6345. -                    html.replace("%clanleadername%", "NPC");
  6346. -                }
  6347. -            }
  6348. -            else
  6349. -            {
  6350. -                html.replace("%castlename%", "Open");
  6351. -                html.replace("%taxpercent%", "0");
  6352. -
  6353. -
  6354. -                html.replace("%clanname%", "No");
  6355. -                html.replace("%clanleadername%", "None");
  6356. -            }
  6357. -
  6358. -
  6359. -            player.sendPacket(html);
  6360. -        }
  6361. -        else if (command.startsWith("Quest"))
  6362. -        {
  6363. -            String quest = "";
  6364. -            try
  6365. -            {
  6366. -                quest = command.substring(5).trim();
  6367. -            }
  6368. -            catch (IndexOutOfBoundsException ioobe) {}
  6369. -
  6370. -            if (quest.length() == 0)
  6371. -                showQuestWindow(player);
  6372. -            else
  6373. -                showQuestWindow(player, quest);
  6374. -        }
  6375. -        else if (command.startsWith("Chat"))
  6376. -        {
  6377. -            int val = 0;
  6378. -            try
  6379. -            {
  6380. -                val = Integer.parseInt(command.substring(5));
  6381. -            }
  6382. -            catch (IndexOutOfBoundsException ioobe)
  6383. -{
  6384. -}
  6385. -            catch (NumberFormatException nfe) {}
  6386. -
  6387. -            showChatWindow(player, val);
  6388. -        }
  6389. -        else if (command.startsWith("Link"))
  6390. -        {
  6391. -            String path = command.substring(5).trim();
  6392. -            if (path.indexOf("..") != -1)
  6393. -                return;
  6394. -
  6395. -            String filename = "data/html/"+path;
  6396. -            NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  6397. -            html.setFile(filename);
  6398. -            html.replace("%objectId%", String.valueOf(getObjectId()));
  6399. -            player.sendPacket(html);
  6400. -        }
  6401. -        else if (command.startsWith("NobleTeleport"))
  6402. -        {
  6403. -            if (!player.isNoble())
  6404. -            {
  6405. -                String filename = "data/html/teleporter/nobleteleporter-no.htm";
  6406. -                NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  6407. -                html.setFile(filename);
  6408. -                html.replace("%objectId%", String.valueOf(getObjectId()));
  6409. -                html.replace("%npcname%", getName());
  6410. -                player.sendPacket(html);
  6411. -                return;
  6412. -            }
  6413. -
  6414. -            int val = 0;
  6415. -            try
  6416. -            {
  6417. -                val = Integer.parseInt(command.substring(14));
  6418. -            }
  6419. -            catch (IndexOutOfBoundsException ioobe) {
  6420. -}
  6421. -            catch (NumberFormatException nfe) {}
  6422. -
  6423. -            showChatWindow(player, val);
  6424. -        }
  6425. -        else if (command.startsWith("Loto"))
  6426. -        {
  6427. -            int val = 0;
  6428. -            try
  6429. -            {
  6430. -                val = Integer.parseInt(command.substring(5));
  6431. -            }
  6432. -            catch (IndexOutOfBoundsException ioobe) {
  6433. -}
  6434. -            catch (NumberFormatException nfe) {}
  6435. -
  6436. -            if (val == 0)
  6437. -            {
  6438. -                // new loto ticket
  6439. -                for (int i=0;i<5;i++)
  6440. -                    player.setLoto(i,0);
  6441. -            }
  6442. -            showLotoWindow(player, val);
  6443. -        }
  6444. -        else if (command.startsWith("CPRecovery"))
  6445. -        {
  6446. -            makeCPRecovery(player);
  6447. -        }
  6448. -        else if (command.startsWith("SupportMagic"))
  6449. -        {
  6450. -            makeSupportMagic(player);
  6451. -        }
  6452. -        else if (command.startsWith("multisell"))
  6453. -        {
  6454. -            L2Multisell.getInstance().createMultiSell(Integer.parseInt(command.substring(9).trim()), player, false, this);
  6455. -        }
  6456. -        else if (command.startsWith("exc_multisell"))
  6457. -        {
  6458. -            L2Multisell.getInstance().createMultiSell(Integer.parseInt(command.substring(13).trim()), player, true, this);
  6459. -        }
  6460. -        else if (command.startsWith("npcfind_byid"))
  6461. -        {
  6462. -            try
  6463. -            {
  6464. -                L2Spawn spawn = SpawnTable.getInstance().getTemplate(Integer.parseInt(command.substring(12).trim()));
  6465. -
  6466. -
  6467. -                if (spawn!=null)
  6468. -                    player.sendPacket(new RadarControl(0,1,spawn.getLocx(),spawn.getLocy(),spawn.getLocz()));
  6469. -            }
  6470. -            catch (NumberFormatException nfe)
  6471. -            {
  6472. -                player.sendMessage("Wrong command parameters");
  6473. -            }
  6474. -        }
  6475. -
  6476. -    }
  6477. -    
  6478. -    /**
  6479. -     * Return null (regular NPCs don't have weapons instancies).<BR><BR>
  6480. -     */
  6481. -    public L2ItemInstance getActiveWeaponInstance()
  6482. -    {
  6483. -        // regular NPCs dont have weapons instancies
  6484. -        return null;
  6485. -    }
  6486. -    
  6487. -    /**
  6488. -     * Return the weapon item equiped in the right hand of the L2NpcInstance or null.<BR><BR>
  6489. -     */
  6490. -    public L2Weapon getActiveWeaponItem()
  6491. -    {
  6492. -        // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  6493. -        int weaponId = getTemplate().rhand;
  6494. -        
  6495. -        if (weaponId < 1)
  6496. -            return null;
  6497. -        
  6498. -        // Get the weapon item equiped in the right hand of the L2NpcInstance
  6499. -        L2Item item = ItemTable.getInstance().getTemplate(getTemplate().rhand);
  6500. -        
  6501. -        if (!(item instanceof L2Weapon))
  6502. -            return null;
  6503. -        
  6504. -        return (L2Weapon)item;
  6505. -    }
  6506. -    
  6507. -    /**
  6508. -     * Return null (regular NPCs don't have weapons instancies).<BR><BR>
  6509. -     */
  6510. -    public L2ItemInstance getSecondaryWeaponInstance()
  6511. -    {
  6512. -        // regular NPCs dont have weapons instancies
  6513. -        return null;
  6514. -    }
  6515. -    
  6516. -    /**
  6517. -     * Return the weapon item equiped in the left hand of the L2NpcInstance or null.<BR><BR>
  6518. -     */
  6519. -    public L2Weapon getSecondaryWeaponItem()
  6520. -    {
  6521. -        // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  6522. -        int weaponId = getTemplate().lhand;
  6523. -        
  6524. -        if (weaponId < 1)
  6525. -            return null;
  6526. -        
  6527. -        // Get the weapon item equiped in the right hand of the L2NpcInstance
  6528. -        L2Item item = ItemTable.getInstance().getTemplate(getTemplate().lhand);
  6529. -        
  6530. -        if (!(item instanceof L2Weapon))
  6531. -            return null;
  6532. -        
  6533. -        return (L2Weapon)item;
  6534. -    }
  6535. -    
  6536. -    /**
  6537. -     * Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance.<BR><BR>
  6538. -     *
  6539. -     * @param player The L2PcInstance who talks with the L2NpcInstance
  6540. -     * @param content The text of the L2NpcMessage
  6541. -     *
  6542. -     */
  6543. -    public void insertObjectIdAndShowChatWindow(L2PcInstance player, String content)
  6544. -    {
  6545. -        // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  6546. -        content = content.replaceAll("%objectId%", String.valueOf(getObjectId()));
  6547. -        NpcHtmlMessage npcReply = new NpcHtmlMessage(getObjectId());
  6548. -        npcReply.setHtml(content);
  6549. -        player.sendPacket(npcReply);
  6550. -    }
  6551. -    
  6552. -    /**
  6553. -     * Return the pathfile of the selected HTML file in function of the npcId and of the page number.<BR><BR>
  6554. -     *  
  6555. -     * <B><U> Format of the pathfile </U> :</B><BR><BR>
  6556. -     * <li> if the file exists on the server (page number = 0) : <B>data/html/default/12006.htm</B> (npcId-page number)</li>
  6557. -     * <li> if the file exists on the server (page number > 0) : <B>data/html/default/12006-1.htm</B> (npcId-page number)</li>
  6558. -     * <li> if the file doesn't exist on the server : <B>data/html/npcdefault.htm</B> (message : "I have nothing to say to you")</li><BR><BR>
  6559. -     *
  6560. -     * <B><U> Overriden in </U> :</B><BR><BR>
  6561. -     * <li> L2GuardInstance : Set the pathfile to data/html/guard/12006-1.htm (npcId-page number)</li><BR><BR>
  6562. -     *
  6563. -     * @param npcId The Identifier of the L2NpcInstance whose text must be display
  6564. -     * @param val The number of the page to display
  6565. -     *
  6566. -     */
  6567. -    public String getHtmlPath(int npcId, int val)
  6568. -    {
  6569. -        String pom = "";
  6570. -        
  6571. -        if (val == 0)
  6572. -            pom = "" + npcId;
  6573. -        else
  6574. -            pom = npcId + "-" + val;
  6575. -        
  6576. -        String temp = "data/html/default/" + pom + ".htm";
  6577. -        
  6578. -        if (!Config.LAZY_CACHE)
  6579. -        {
  6580. -           // If not running lazy cache the file must be in the cache or it doesnt exist
  6581. -           if (HtmCache.getInstance().contains(temp))
  6582. -               return temp;
  6583. -        }
  6584. -        else
  6585. -        {
  6586. -           if (HtmCache.getInstance().isLoadable(temp))
  6587. -               return temp;
  6588. -        }
  6589. -        
  6590. -        // If the file is not found, the standard message "I have nothing to say to you" is returned
  6591. -        return "data/html/npcdefault.htm";
  6592. -    }
  6593. -
  6594. -    public void showBuyWindow(L2PcInstance player, int val)
  6595. -    {
  6596. -        double taxRate = 0;
  6597. -        if (getIsInCastleTown())
  6598. -            taxRate = getCastle().getTaxRate();
  6599. -
  6600. -        player.tempInventoryDisable();
  6601. -
  6602. -        if (Config.DEBUG) _log.fine("Showing buylist");
  6603. -
  6604. -        L2TradeList list = TradeController.getInstance().getBuyList(val);
  6605. -
  6606. -        if (list != null && list.getNpcId().equals(String.valueOf(getNpcId())))
  6607. -
  6608. -            player.sendPacket(new BuyList(list, player.getAdena(), taxRate));
  6609. -
  6610. -        else
  6611. -        {
  6612. -            _log.warning("possible client hacker: " + player.getName()
  6613. -                + " attempting to buy from GM shop! < Ban him!");
  6614. -            _log.warning("buylist id:" + val);
  6615. -        }
  6616. -
  6617. -        player.sendPacket(new ActionFailed());
  6618. -    }
  6619. -
  6620. -    /**
  6621. -     * Open a choose quest window on client with all quests available of the L2NpcInstance.<BR><BR>
  6622. -     *
  6623. -     * <B><U> Actions</U> :</B><BR><BR>
  6624. -     * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li><BR><BR>
  6625. -     *
  6626. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  6627. -     * @param quests The table containing quests of the L2NpcInstance
  6628. -     *
  6629. -     */
  6630. -    public void showQuestChooseWindow(L2PcInstance player, Quest[] quests)
  6631. -    {
  6632. -        TextBuilder sb = new TextBuilder();
  6633. -        
  6634. -        sb.append("<html><body><title>Talk about:</title><br>");
  6635. -        
  6636. -        for (Quest q : quests)
  6637. -        {
  6638. -            sb.append("<a action=\"bypass -h npc_").append(getObjectId())
  6639. -            .append("_Quest ").append(q.getName()).append("\">")
  6640. -            .append(q.getDescr()).append("</a><br>");
  6641. -        }
  6642. -        
  6643. -        sb.append("</body></html>");
  6644. -        
  6645. -        // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  6646. -        insertObjectIdAndShowChatWindow(player, sb.toString());
  6647. -    }
  6648. -    
  6649. -    /**
  6650. -     * Open a quest window on client with the text of the L2NpcInstance.<BR><BR>
  6651. -     *
  6652. -     * <B><U> Actions</U> :</B><BR><BR>
  6653. -     * <li>Get the text of the quest state in the folder data/jscript/quests/questId/stateId.htm </li>
  6654. -     * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  6655. -     * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR><BR>
  6656. -     *
  6657. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  6658. -     * @param questId The Identifier of the quest to display the message
  6659. -     *
  6660. -     */
  6661. -    public void showQuestWindow(L2PcInstance player, String questId)
  6662. -    {
  6663. -        String content;
  6664. -
  6665. -
  6666. -        // Get the state of the selected quest
  6667. -        QuestState qs = player.getQuestState(questId);
  6668. -        
  6669. -        if (qs != null)
  6670. -        {
  6671. -            // If the quest is already started, no need to show a window
  6672. -            if (!qs.getQuest().notifyTalk(this, qs))
  6673. -                return;
  6674. -        }
  6675. -        else
  6676. -        {
  6677. -            Quest q = QuestManager.getInstance().getQuest(questId);
  6678. -            if (q != null)
  6679. -            {
  6680. -                if (q.getQuestIntId() >= 1 && q.getQuestIntId() < 1000)
  6681. -                {
  6682. -                    Quest[] questList = player.getAllActiveQuests();
  6683. -                    if (questList.length >= 15) // if too many ongoing quests, don't show window and send message
  6684. -                    {
  6685. -                        player.sendPacket(new SystemMessage(401));
  6686. -                        return;
  6687. -                    }
  6688. -
  6689. -                    if (player.getWeightPenalty() >= 3 || player.getInventoryLimit() * 0.8 <= player.getInventory().getSize())
  6690. -                    { 
  6691. -                        player.sendPacket(new SystemMessage(1118));
  6692. -                        return;
  6693. -                    }
  6694. -                }
  6695. -
  6696. -                // check for start point
  6697. -                Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  6698. -                
  6699. -                if (qlst != null && qlst.length > 0)
  6700. -                {
  6701. -                    for (int i=0; i < qlst.length; i++)
  6702. -                    {
  6703. -                        if (qlst[i] == q)
  6704. -                        {
  6705. -                            qs = q.newQuestState(player);
  6706. -                            //disabled by mr. because quest dialog only show on second click.
  6707. -                            //if(qs.getState().getName().equalsIgnoreCase("completed"))
  6708. -                            //{
  6709. -                            if (!qs.getQuest().notifyTalk(this, qs))
  6710. -                                return; // no need to show a window
  6711. -                            //}
  6712. -                            break;
  6713. -                        }
  6714. -                    }
  6715. -                }
  6716. -            }
  6717. -        }
  6718. -        
  6719. -        if (qs == null)
  6720. -        {
  6721. -            // no quests found
  6722. -            content = "<html><body>I have no tasks for you right now.</body></html>";
  6723. -        }
  6724. -        else
  6725. -        {
  6726. -            questId = qs.getQuest().getName();
  6727. -            String stateId = qs.getStateId();
  6728. -            String path = "data/jscript/quests/"+questId+"/"+stateId+".htm";
  6729. -            content = HtmCache.getInstance().getHtm(path); //TODO path for quests html
  6730. -            
  6731. -            if (Config.DEBUG)
  6732. -            {
  6733. -                if (content != null)
  6734. -                {
  6735. -                    _log.fine("Showing quest window for quest "+questId+" html path: " + path);
  6736. -                }
  6737. -                else
  6738. -                {
  6739. -                    _log.fine("File not exists for quest "+questId+" html path: " + path);
  6740. -                }
  6741. -            }
  6742. -        }
  6743. -        
  6744. -        // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  6745. -        if (content != null)
  6746. -            insertObjectIdAndShowChatWindow(player, content);
  6747. -        
  6748. -        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  6749. -        player.sendPacket(new ActionFailed());
  6750. -    }
  6751. -    
  6752. -    /**
  6753. -     * Collect awaiting quests/start points and display a QuestChooseWindow (if several available) or QuestWindow.<BR><BR>
  6754. -     *
  6755. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  6756. -     *
  6757. -     */
  6758. -    public void showQuestWindow(L2PcInstance player)
  6759. -    {
  6760. -        // collect awaiting quests and start points
  6761. -        List<Quest> options = new FastList<Quest>();
  6762. -        
  6763. -        QuestState[] awaits = player.getQuestsForTalk(getTemplate().npcId);
  6764. -        Quest[] starts = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  6765. -        
  6766. -        // Quests are limited between 1 and 999 because those are the quests that are supported by the client.
  6767. -        if (awaits != null)
  6768. -        {
  6769. -            for (QuestState x : awaits)
  6770. -            {
  6771. -                if (!options.contains(x))
  6772. -                    if((x.getQuest().getQuestIntId()>0) && (x.getQuest().getQuestIntId()<1000))
  6773. -                        options.add(x.getQuest());
  6774. -            }
  6775. -        }
  6776. -        
  6777. -        if (starts != null)
  6778. -        {
  6779. -            for (Quest x : starts)
  6780. -            {
  6781. -                if (!options.contains(x))
  6782. -                    if((x.getQuestIntId()>0) && (x.getQuestIntId()<1000))
  6783. -                        options.add(x);
  6784. -            }
  6785. -        }
  6786. -        
  6787. -        // Display a QuestChooseWindow (if several quests are available) or QuestWindow
  6788. -        if (options.size() > 1)
  6789. -        {
  6790. -            showQuestChooseWindow(player, options.toArray(new Quest[options.size()]));
  6791. -        }
  6792. -        else if (options.size() == 1)
  6793. -        {
  6794. -            showQuestWindow(player, options.get(0).getName());
  6795. -        }
  6796. -        else
  6797. -        {
  6798. -            showQuestWindow(player, "");
  6799. -        }
  6800. -    }
  6801. -    
  6802. -    /**
  6803. -     * Open a Loto window on client with the text of the L2NpcInstance.<BR><BR>
  6804. -     *
  6805. -     * <B><U> Actions</U> :</B><BR><BR>
  6806. -     * <li>Get the text of the selected HTML file in function of the npcId and of the page number </li>
  6807. -     * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  6808. -     * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR>
  6809. -     *
  6810. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  6811. -     * @param val The number of the page of the L2NpcInstance to display
  6812. -     *
  6813. -     */
  6814. -    // 0 - first buy lottery ticket window
  6815. -    // 1-20 - buttons
  6816. -    // 21 - second buy lottery ticket window
  6817. -    // 22 - selected ticket with 5 numbers
  6818. -    // 23 - current lottery jackpot
  6819. -    // 24 - Previous winning numbers/Prize claim
  6820. -    // >24 - check lottery ticket by item object id
  6821. -    public void showLotoWindow(L2PcInstance player, int val)
  6822. -    {
  6823. -        int npcId = getTemplate().npcId;
  6824. -        String filename;
  6825. -        SystemMessage sm;
  6826. -        NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  6827. -        
  6828. -        if (val == 0) // 0 - first buy lottery ticket window
  6829. -        {
  6830. -            filename = (getHtmlPath(npcId, 1));
  6831. -            html.setFile(filename);
  6832. -        }
  6833. -        else if (val >= 1 && val <= 21) // 1-20 - buttons, 21 - second buy lottery ticket window
  6834. -        {
  6835. -           if (!Lottery.getInstance().isStarted())
  6836. -            {
  6837. -                //tickets can't be sold
  6838. -                player.sendPacket(new SystemMessage(930));
  6839. -                return;
  6840. -            }
  6841. -            if (!Lottery.getInstance().isSellableTickets())
  6842. -            {
  6843. -                //tickets can't be sold
  6844. -                player.sendPacket(new SystemMessage(784));
  6845. -                return;
  6846. -            }
  6847. -
  6848. +   // private static Logger _log = Logger.getLogger(L2NpcInstance.class.getName());
  6849. +  
  6850. +   /** The interaction distance of the L2NpcInstance(is used as offset in MovetoLocation method) */
  6851. +   public static final int INTERACTION_DISTANCE = 150;
  6852. +  
  6853. +   /** The L2Spawn object that manage this L2NpcInstance */
  6854. +   private L2Spawn _spawn;
  6855. +  
  6856. +   /** The flag to specify if this L2NpcInstance is busy */
  6857. +   private boolean _IsBusy = false;
  6858. +  
  6859. +   /** The busy message for this L2NpcInstance */
  6860. +   private String _BusyMessage = "";
  6861. +  
  6862. +   /** True if endDecayTask has already been called */
  6863. +   volatile boolean _isDecayed = false;
  6864. +  
  6865. +   /** True if a Dwarf has used Spoil on this L2NpcInstance */
  6866. +   private boolean _IsSpoil = false;
  6867. +  
  6868. +   /** The castle index in the array of L2Castle this L2NpcInstance belongs to */
  6869. +   private int _castleIndex = -2;
  6870. +  
  6871. +   public boolean isEventMob = false;
  6872. +  
  6873. +   private boolean _isInTown = false;
  6874. +  
  6875. +   private int _isSpoiledBy = 0;
  6876. +  
  6877. +   protected RandomAnimationTask _rAniTask = null;
  6878. +  
  6879. +   private int _currentCollisionHeight;
  6880. +   private int _currentCollisionRadius;
  6881. +  
  6882. +   /** Task launching the function onRandomAnimation() */
  6883. +   protected class RandomAnimationTask implements Runnable
  6884. +   {
  6885. +       @Override
  6886. +       public void run()
  6887. +       {
  6888. +           try
  6889. +           {
  6890. +               if (this != _rAniTask)
  6891. +               {
  6892. +                   return;
  6893. +               }
  6894. +              
  6895. +               if (L2NpcInstance.this instanceof L2Attackable)
  6896. +               {
  6897. +                   if (getAI().getIntention() != AI_INTENTION_ACTIVE)
  6898. +                   {
  6899. +                       return;
  6900. +                   }
  6901. +               }
  6902. +              
  6903. +               else
  6904. +               {
  6905. +                   if (!isInActiveRegion())
  6906. +                   {
  6907. +                       return;
  6908. +                   }
  6909. +               }
  6910. +              
  6911. +               if (!(isDead() || isStunned() || isSleeping() || isParalyzed()))
  6912. +               {
  6913. +                   onRandomAnimation();
  6914. +               }
  6915. +              
  6916. +               startRandomAnimationTimer();
  6917. +           }
  6918. +           catch (Throwable t)
  6919. +           {
  6920. +           }
  6921. +       }
  6922. +   }
  6923. +  
  6924. +   /**
  6925. +    * Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance and create a new RandomAnimation Task.<BR>
  6926. +    * <BR>
  6927. +    */
  6928. +   public void onRandomAnimation()
  6929. +   {
  6930. +       // Send a packet SocialAction to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  6931. +       SocialAction sa = new SocialAction(getObjectId(), Rnd.get(1, 3));
  6932. +       broadcastPacket(sa);
  6933. +   }
  6934. +  
  6935. +   /**
  6936. +    * Create a RandomAnimation Task that will be launched after the calculated delay.<BR>
  6937. +    * <BR>
  6938. +    */
  6939. +   public void startRandomAnimationTimer()
  6940. +   {
  6941. +       if (!hasRandomAnimation())
  6942. +       {
  6943. +           return;
  6944. +       }
  6945. +      
  6946. +       int minWait = this instanceof L2Attackable ? Config.MIN_MONSTER_ANIMATION : Config.MIN_NPC_ANIMATION;
  6947. +       int maxWait = this instanceof L2Attackable ? Config.MAX_MONSTER_ANIMATION : Config.MAX_NPC_ANIMATION;
  6948. +      
  6949. +       // Calculate the delay before the next animation
  6950. +       int interval = Rnd.get(minWait, maxWait) * 1000;
  6951. +      
  6952. +       // Create a RandomAnimation Task that will be launched after the calculated delay
  6953. +       _rAniTask = new RandomAnimationTask();
  6954. +       ThreadPoolManager.getInstance().scheduleGeneral(_rAniTask, interval);
  6955. +   }
  6956. +  
  6957. +   /**
  6958. +    * Check if the server allows Random Animation.<BR>
  6959. +    * <BR>
  6960. +    */
  6961. +   public boolean hasRandomAnimation()
  6962. +   {
  6963. +       return (Config.MAX_NPC_ANIMATION > 0);
  6964. +   }
  6965. +  
  6966. +   /**
  6967. +    * Constructor of L2NpcInstance (use L2Character constructor).<BR>
  6968. +    * <BR>
  6969. +    * <B><U> Actions</U> :</B><BR>
  6970. +    * <BR>
  6971. +    * <li>Call the L2Character constructor to set the _template of the L2Character (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR)</li> <li>Set the name of the L2Character</li> <li>Create a RandomAnimation Task that will be launched after the calculated delay if
  6972. +    * the server allow it</li><BR>
  6973. +    * <BR>
  6974. +    * @param objectId Identifier of the object to initialized
  6975. +    * @param template The L2NpcTemplate to apply to the NPC
  6976. +    */
  6977. +   public L2NpcInstance(int objectId, L2NpcTemplate template)
  6978. +   {
  6979. +       // Call the L2Character constructor to set the _template of the L2Character, copy skills from template to object
  6980. +       // and link _calculators to NPC_STD_CALCULATOR
  6981. +       super(objectId, template);
  6982. +       getKnownList();
  6983. +       getStat();
  6984. +       getStatus();
  6985. +      
  6986. +       super.initCharStatusUpdateValues(); // init status update values
  6987. +      
  6988. +       _currentCollisionHeight = getTemplate().collisionHeight;
  6989. +       _currentCollisionRadius = getTemplate().collisionRadius;
  6990. +      
  6991. +       if (template == null)
  6992. +       {
  6993. +           _log.severe("No template for Npc. Please check your datapack is setup correctly.");
  6994. +           return;
  6995. +       }
  6996. +      
  6997. +       // Set the name of the L2Character
  6998. +       setName(template.name);
  6999. +   }
  7000. +  
  7001. +   @Override
  7002. +   public NpcKnownList getKnownList()
  7003. +   {
  7004. +       if ((super.getKnownList() == null) || !(super.getKnownList() instanceof NpcKnownList))
  7005. +       {
  7006. +           setKnownList(new NpcKnownList(this));
  7007. +       }
  7008. +       return (NpcKnownList) super.getKnownList();
  7009. +   }
  7010. +  
  7011. +   @Override
  7012. +   public NpcStat getStat()
  7013. +   {
  7014. +       if ((super.getStat() == null) || !(super.getStat() instanceof NpcStat))
  7015. +       {
  7016. +           setStat(new NpcStat(this));
  7017. +       }
  7018. +       return (NpcStat) super.getStat();
  7019. +   }
  7020. +  
  7021. +   @Override
  7022. +   public NpcStatus getStatus()
  7023. +   {
  7024. +       if ((super.getStatus() == null) || !(super.getStatus() instanceof NpcStatus))
  7025. +       {
  7026. +           setStatus(new NpcStatus(this));
  7027. +       }
  7028. +       return (NpcStatus) super.getStatus();
  7029. +   }
  7030. +  
  7031. +   /** Return the L2NpcTemplate of the L2NpcInstance. */
  7032. +   @Override
  7033. +   public final L2NpcTemplate getTemplate()
  7034. +   {
  7035. +       return (L2NpcTemplate) super.getTemplate();
  7036. +   }
  7037. +  
  7038. +   /**
  7039. +    * Return the generic Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7040. +    * <BR>
  7041. +    */
  7042. +   public int getNpcId()
  7043. +   {
  7044. +       return getTemplate().npcId;
  7045. +   }
  7046. +  
  7047. +   @Override
  7048. +   public boolean isAttackable()
  7049. +   {
  7050. +       return true;
  7051. +   }
  7052. +  
  7053. +   /**
  7054. +    * Return the faction Identifier of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7055. +    * <BR>
  7056. +    * <B><U> Concept</U> :</B><BR>
  7057. +    * <BR>
  7058. +    * If a NPC belows to a Faction, other NPC of the faction inside the Faction range will help it if it's attacked<BR>
  7059. +    * <BR>
  7060. +    */
  7061. +   public final String getFactionId()
  7062. +   {
  7063. +       return getTemplate().factionId;
  7064. +   }
  7065. +  
  7066. +   /**
  7067. +    * Return the Level of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7068. +    * <BR>
  7069. +    */
  7070. +   @Override
  7071. +   public final int getLevel()
  7072. +   {
  7073. +       return getTemplate().level;
  7074. +   }
  7075. +  
  7076. +   /**
  7077. +    * Return True if the L2NpcInstance is agressive (ex : L2MonsterInstance in function of aggroRange).<BR>
  7078. +    * <BR>
  7079. +    */
  7080. +   public boolean isAggressive()
  7081. +   {
  7082. +       return false;
  7083. +   }
  7084. +  
  7085. +   /**
  7086. +    * Return the Aggro Range of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7087. +    * <BR>
  7088. +    */
  7089. +   public int getAggroRange()
  7090. +   {
  7091. +       return getTemplate().aggroRange;
  7092. +   }
  7093. +  
  7094. +   /**
  7095. +    * Return the Faction Range of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7096. +    * <BR>
  7097. +    */
  7098. +   public int getFactionRange()
  7099. +   {
  7100. +       return getTemplate().factionRange;
  7101. +   }
  7102. +  
  7103. +   /**
  7104. +    * Return True if this L2NpcInstance is undead in function of the L2NpcTemplate.<BR>
  7105. +    * <BR>
  7106. +    */
  7107. +   @Override
  7108. +   public boolean isUndead()
  7109. +   {
  7110. +       return getTemplate().isUndead;
  7111. +   }
  7112. +  
  7113. +   /**
  7114. +    * Send a packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance.<BR>
  7115. +    * <BR>
  7116. +    */
  7117. +   @Override
  7118. +   public void updateAbnormalEffect()
  7119. +   {
  7120. +      
  7121. +       // Send a Server->Client packet NpcInfo with state of abnormal effect to all L2PcInstance in the _KnownPlayers of the L2NpcInstance
  7122. +       for (L2PcInstance player : getKnownList().getKnownPlayers().values())
  7123. +       {
  7124. +           if (player != null)
  7125. +           {
  7126. +               if (getRunSpeed() == 0)
  7127. +               {
  7128. +                   player.sendPacket(new ServerObjectInfo(this, player));
  7129. +               }
  7130. +               else
  7131. +               {
  7132. +                   player.sendPacket(new NpcInfo(this, player));
  7133. +               }
  7134. +           }
  7135. +       }
  7136. +   }
  7137. +  
  7138. +   /**
  7139. +    * Return the distance under which the object must be add to _knownObject in function of the object type.<BR>
  7140. +    * <BR>
  7141. +    * <B><U> Values </U> :</B><BR>
  7142. +    * <BR>
  7143. +    * <li>object is a L2FolkInstance : 0 (don't remember it)</li> <li>object is a L2Character : 0 (don't remember it)</li> <li>object is a L2PlayableInstance : 1500</li> <li>others : 500</li><BR>
  7144. +    * <BR>
  7145. +    * <B><U> Overriden in </U> :</B><BR>
  7146. +    * <BR>
  7147. +    * <li>L2Attackable</li><BR>
  7148. +    * <BR>
  7149. +    * @param object The Object to add to _knownObject
  7150. +    */
  7151. +   public int getDistanceToWatchObject(L2Object object)
  7152. +   {
  7153. +       if (object instanceof L2FestivalGuideInstance)
  7154. +       {
  7155. +           return 10000;
  7156. +       }
  7157. +      
  7158. +       if ((object instanceof L2FolkInstance) || !(object instanceof L2Character))
  7159. +       {
  7160. +           return 0;
  7161. +       }
  7162. +      
  7163. +       if (object instanceof L2PlayableInstance)
  7164. +       {
  7165. +           return 1500;
  7166. +       }
  7167. +      
  7168. +       return 500;
  7169. +   }
  7170. +  
  7171. +   /**
  7172. +    * Return the distance after which the object must be remove from _knownObject in function of the object type.<BR>
  7173. +    * <BR>
  7174. +    * <B><U> Values </U> :</B><BR>
  7175. +    * <BR>
  7176. +    * <li>object is not a L2Character : 0 (don't remember it)</li> <li>object is a L2FolkInstance : 0 (don't remember it)</li> <li>object is a L2PlayableInstance : 3000</li> <li>others : 1000</li><BR>
  7177. +    * <BR>
  7178. +    * <B><U> Overriden in </U> :</B><BR>
  7179. +    * <BR>
  7180. +    * <li>L2Attackable</li><BR>
  7181. +    * <BR>
  7182. +    * @param object The Object to remove from _knownObject
  7183. +    */
  7184. +   public int getDistanceToForgetObject(L2Object object)
  7185. +   {
  7186. +       return 2 * getDistanceToWatchObject(object);
  7187. +   }
  7188. +  
  7189. +   /**
  7190. +    * Return False.<BR>
  7191. +    * <BR>
  7192. +    * <B><U> Overriden in </U> :</B><BR>
  7193. +    * <BR>
  7194. +    * <li>L2MonsterInstance : Check if the attacker is not another L2MonsterInstance</li> <li>L2PcInstance</li><BR>
  7195. +    * <BR>
  7196. +    */
  7197. +   @Override
  7198. +   public boolean isAutoAttackable(@SuppressWarnings("unused") L2Character attacker)
  7199. +   {
  7200. +       return false;
  7201. +   }
  7202. +  
  7203. +   /**
  7204. +    * Return the Identifier of the item in the left hand of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7205. +    * <BR>
  7206. +    */
  7207. +   public int getLeftHandItem()
  7208. +   {
  7209. +       return getTemplate().lhand;
  7210. +   }
  7211. +  
  7212. +   /**
  7213. +    * Return the Identifier of the item in the right hand of this L2NpcInstance contained in the L2NpcTemplate.<BR>
  7214. +    * <BR>
  7215. +    */
  7216. +   public int getRightHandItem()
  7217. +   {
  7218. +       return getTemplate().rhand;
  7219. +   }
  7220. +  
  7221. +   /**
  7222. +    * Return True if this L2NpcInstance has drops that can be sweeped.<BR>
  7223. +    * <BR>
  7224. +    */
  7225. +   public boolean isSpoil()
  7226. +   {
  7227. +       return _IsSpoil;
  7228. +   }
  7229. +  
  7230. +   /**
  7231. +    * Set the spoil state of this L2NpcInstance.<BR>
  7232. +    * <BR>
  7233. +    */
  7234. +   public void setSpoil(boolean isSpoil)
  7235. +   {
  7236. +       _IsSpoil = isSpoil;
  7237. +   }
  7238. +  
  7239. +   public final int getIsSpoiledBy()
  7240. +   {
  7241. +       return _isSpoiledBy;
  7242. +   }
  7243. +  
  7244. +   public final void setIsSpoiledBy(int value)
  7245. +   {
  7246. +       _isSpoiledBy = value;
  7247. +   }
  7248. +  
  7249. +   /**
  7250. +    * Return the busy status of this L2NpcInstance.<BR>
  7251. +    * <BR>
  7252. +    */
  7253. +   public final boolean isBusy()
  7254. +   {
  7255. +       return _IsBusy;
  7256. +   }
  7257. +  
  7258. +   /**
  7259. +    * Set the busy status of this L2NpcInstance.<BR>
  7260. +    * <BR>
  7261. +    */
  7262. +   public void setBusy(boolean isBusy)
  7263. +   {
  7264. +       _IsBusy = isBusy;
  7265. +   }
  7266. +  
  7267. +   /**
  7268. +    * Return the busy message of this L2NpcInstance.<BR>
  7269. +    * <BR>
  7270. +    */
  7271. +   public final String getBusyMessage()
  7272. +   {
  7273. +       return _BusyMessage;
  7274. +   }
  7275. +  
  7276. +   /**
  7277. +    * Set the busy message of this L2NpcInstance.<BR>
  7278. +    * <BR>
  7279. +    */
  7280. +   public void setBusyMessage(String message)
  7281. +   {
  7282. +       _BusyMessage = message;
  7283. +   }
  7284. +  
  7285. +   protected boolean canTarget(L2PcInstance player)
  7286. +   {
  7287. +       if (player.isConfused())
  7288. +       {
  7289. +           player.sendPacket(new ActionFailed());
  7290. +           return false;
  7291. +       }
  7292. +       // TODO: More checks...
  7293. +      
  7294. +       return true;
  7295. +   }
  7296. +  
  7297. +   public boolean canInteract(L2PcInstance player)
  7298. +   {
  7299. +       // TODO: NPC busy check etc...
  7300. +      
  7301. +       if (player.isCastingNow() || player.isSitting())
  7302. +       {
  7303. +           return false;
  7304. +       }
  7305. +      
  7306. +       if (player.isDead() || player.isFakeDeath())
  7307. +       {
  7308. +           return false;
  7309. +       }
  7310. +      
  7311. +       if (player.getPrivateStoreType() != 0)
  7312. +       {
  7313. +           return false;
  7314. +       }
  7315. +      
  7316. +       if (!isInsideRadius(player, INTERACTION_DISTANCE, false, false))
  7317. +       {
  7318. +           return false;
  7319. +       }
  7320. +      
  7321. +       return true;
  7322. +   }
  7323. +  
  7324. +   /**
  7325. +    * Manage actions when a player click on the L2NpcInstance.<BR>
  7326. +    * <BR>
  7327. +    * <B><U> Actions on first click on the L2NpcInstance (Select it)</U> :</B><BR>
  7328. +    * <BR>
  7329. +    * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li> <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li> <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the
  7330. +    * L2PcInstance in order to update L2NpcInstance HP bar</li> <li>Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client</li><BR>
  7331. +    * <BR>
  7332. +    * <B><U> Actions on second click on the L2NpcInstance (Attack it/Intercat with it)</U> :</B><BR>
  7333. +    * <BR>
  7334. +    * <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li> <li>If L2NpcInstance is autoAttackable, notify the L2PcInstance AI with AI_INTENTION_ATTACK (after a height verification)</li> <li>If L2NpcInstance is NOT autoAttackable, notify the
  7335. +    * L2PcInstance AI with AI_INTENTION_INTERACT (after a distance verification) and show message</li><BR>
  7336. +    * <BR>
  7337. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid that client wait an other packet</B></FONT><BR>
  7338. +    * <BR>
  7339. +    * <B><U> Example of use </U> :</B><BR>
  7340. +    * <BR>
  7341. +    * <li>Client packet : Action, AttackRequest</li><BR>
  7342. +    * <BR>
  7343. +    * <B><U> Overriden in </U> :</B><BR>
  7344. +    * <BR>
  7345. +    * <li>L2ArtefactInstance : Manage only fisrt click to select Artefact</li><BR>
  7346. +    * <BR>
  7347. +    * <li>L2GuardInstance :</li><BR>
  7348. +    * <BR>
  7349. +    * @param player The L2PcInstance that start an action on the L2NpcInstance
  7350. +    */
  7351. +   @Override
  7352. +   public void onAction(L2PcInstance player)
  7353. +   {
  7354. +       if (!canTarget(player))
  7355. +       {
  7356. +           return;
  7357. +       }
  7358. +      
  7359. +       // Check if the L2PcInstance already target the L2NpcInstance
  7360. +       if (this != player.getTarget())
  7361. +       {
  7362. +           if (Config.DEBUG)
  7363. +           {
  7364. +               _log.fine("new target selected:" + getObjectId());
  7365. +           }
  7366. +          
  7367. +           // Set the target of the L2PcInstance player
  7368. +           player.setTarget(this);
  7369. +          
  7370. +           // Check if the player is attackable (without a forced attack)
  7371. +           if (isAutoAttackable(player))
  7372. +           {
  7373. +               // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  7374. +               // The player.getLevel() - getLevel() permit to display the correct color in the select window
  7375. +               MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  7376. +               player.sendPacket(my);
  7377. +              
  7378. +               // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  7379. +               StatusUpdate su = new StatusUpdate(getObjectId());
  7380. +               su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  7381. +               su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  7382. +               player.sendPacket(su);
  7383. +           }
  7384. +           else
  7385. +           {
  7386. +               // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  7387. +               MyTargetSelected my = new MyTargetSelected(getObjectId(), 0);
  7388. +               player.sendPacket(my);
  7389. +           }
  7390. +          
  7391. +           // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client
  7392. +           player.sendPacket(new ValidateLocation(this));
  7393. +       }
  7394. +       else
  7395. +       {
  7396. +           player.sendPacket(new ValidateLocation(this));
  7397. +           // Check if the player is attackable (without a forced attack) and isn't dead
  7398. +           if (isAutoAttackable(player) && !isAlikeDead())
  7399. +           {
  7400. +               // Check the height difference
  7401. +               if (Math.abs(player.getZ() - getZ()) < 400) // this max heigth difference might need some tweaking
  7402. +               {
  7403. +                   // Set the L2PcInstance Intention to AI_INTENTION_ATTACK
  7404. +                   player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
  7405. +                  
  7406. +               }
  7407. +               else
  7408. +               {
  7409. +                   // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  7410. +                   player.sendPacket(new ActionFailed());
  7411. +               }
  7412. +           }
  7413. +           else if (!isAutoAttackable(player))
  7414. +           {
  7415. +               // Calculate the distance between the L2PcInstance and the L2NpcInstance
  7416. +               if (!canInteract(player))
  7417. +               {
  7418. +                   // Notify the L2PcInstance AI with AI_INTENTION_INTERACT
  7419. +                   player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
  7420. +               }
  7421. +               else
  7422. +               {
  7423. +                   // Send a Server->Client packet SocialAction to the all L2PcInstance on the _knownPlayer of the L2NpcInstance
  7424. +                   // to display a social action of the L2NpcInstance on their client
  7425. +                   SocialAction sa = new SocialAction(getObjectId(), Rnd.get(8));
  7426. +                   broadcastPacket(sa);
  7427. +                  
  7428. +                   // Open a chat window on client with the text of the L2NpcInstance
  7429. +                   if (isEventMob)
  7430. +                   {
  7431. +                       L2Event.showEventHtml(player, String.valueOf(getObjectId()));
  7432. +                   }
  7433. +                   else
  7434. +                   {
  7435. +                       Quest[] qlsa = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  7436. +                       if ((qlsa != null) && (qlsa.length > 0))
  7437. +                       {
  7438. +                           player.setLastQuestNpcObject(getObjectId());
  7439. +                       }
  7440. +                      
  7441. +                       Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.NPC_FIRST_TALK);
  7442. +                       if ((qlst != null) && (qlst.length == 1))
  7443. +                       {
  7444. +                           qlst[0].notifyFirstTalk(this, player);
  7445. +                       }
  7446. +                       else
  7447. +                       {
  7448. +                           showChatWindow(player, 0);
  7449. +                       }
  7450. +                   }
  7451. +                  
  7452. +               }
  7453. +           }
  7454. +           else
  7455. +           {
  7456. +               player.sendPacket(new ActionFailed());
  7457. +           }
  7458. +       }
  7459. +   }
  7460. +  
  7461. +   /**
  7462. +    * Manage and Display the GM console to modify the L2NpcInstance (GM only).<BR>
  7463. +    * <BR>
  7464. +    * <B><U> Actions (If the L2PcInstance is a GM only)</U> :</B><BR>
  7465. +    * <BR>
  7466. +    * <li>Set the L2NpcInstance as target of the L2PcInstance player (if necessary)</li> <li>Send a Server->Client packet MyTargetSelected to the L2PcInstance player (display the select window)</li> <li>If L2NpcInstance is autoAttackable, send a Server->Client packet StatusUpdate to the
  7467. +    * L2PcInstance in order to update L2NpcInstance HP bar</li> <li>Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance</li><BR>
  7468. +    * <BR>
  7469. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : Each group of Server->Client packet must be terminated by a ActionFailed packet in order to avoid that client wait an other packet</B></FONT><BR>
  7470. +    * <BR>
  7471. +    * <B><U> Example of use </U> :</B><BR>
  7472. +    * <BR>
  7473. +    * <li>Client packet : Action</li><BR>
  7474. +    * <BR>
  7475. +    * @param client The thread that manage the player that pessed Shift and click on the L2NpcInstance
  7476. +    */
  7477. +   @Override
  7478. +   public void onActionShift(ClientThread client)
  7479. +   {
  7480. +       // Get the L2PcInstance corresponding to the thread
  7481. +       L2PcInstance player = client.getActiveChar();
  7482. +      
  7483. +       if (player == null)
  7484. +       {
  7485. +           return;
  7486. +       }
  7487. +      
  7488. +       // Check if the L2PcInstance is a GM
  7489. +       if (player.getAccessLevel() >= Config.GM_ACCESSLEVEL)
  7490. +       {
  7491. +           // Set the target of the L2PcInstance player
  7492. +           player.setTarget(this);
  7493. +          
  7494. +           // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  7495. +           // The player.getLevel() - getLevel() permit to display the correct color in the select window
  7496. +           MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  7497. +           player.sendPacket(my);
  7498. +          
  7499. +           // Check if the player is attackable (without a forced attack)
  7500. +           if (isAutoAttackable(player))
  7501. +           {
  7502. +               // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  7503. +               StatusUpdate su = new StatusUpdate(getObjectId());
  7504. +               su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  7505. +               su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  7506. +               player.sendPacket(su);
  7507. +           }
  7508. +          
  7509. +           // Send a Server->Client NpcHtmlMessage() containing the GM console about this L2NpcInstance
  7510. +           NpcHtmlMessage html = new NpcHtmlMessage(0);
  7511. +           TextBuilder html1 = new TextBuilder("<html><body><center><font color=\"LEVEL\">NPC Information</font></center>");
  7512. +           String className = getClass().getName().substring(43);
  7513. +          
  7514. +           html1.append("<br>");
  7515. +          
  7516. +           html1.append("Instance Type: " + className + "<br1>Faction: " + getFactionId() + "<br1>Location ID: " + (getSpawn() != null ? getSpawn().getLocation() : 0) + "<br1>");
  7517. +          
  7518. +           if (this instanceof L2ControllableMobInstance)
  7519. +           {
  7520. +               html1.append("Mob Group: " + MobGroupTable.getInstance().getGroupForMob((L2ControllableMobInstance) this).getGroupId() + "<br>");
  7521. +           }
  7522. +           else
  7523. +           {
  7524. +               html1.append("Respawn Time: " + (getSpawn() != null ? (getSpawn().getRespawnDelay() / 1000) + "  Seconds<br>" : "?  Seconds<br>"));
  7525. +           }
  7526. +          
  7527. +           html1.append("<table border=\"0\" width=\"100%\">");
  7528. +           html1.append("<tr><td>Object ID</td><td>" + getObjectId() + "</td><td>NPC ID</td><td>" + getTemplate().npcId + "</td></tr>");
  7529. +          
  7530. +           html1.append("<tr><td>Castle</td><td>" + (getCastle() != null ? getCastle().getCastleId() : 0) + "</td><td>Coords</td><td>" + getX() + "," + getY() + "," + getZ() + "</td></tr>");
  7531. +          
  7532. +           html1.append("<tr><td>Level</td><td>" + getLevel() + "</td><td>Aggro</td><td>" + ((this instanceof L2Attackable) ? ((L2Attackable) this).getAggroRange() : 0) + "</td></tr>");
  7533. +           html1.append("</table><br>");
  7534. +          
  7535. +           html1.append("<font color=\"LEVEL\">Combat</font>");
  7536. +           html1.append("<table border=\"0\" width=\"100%\">");
  7537. +           html1.append("<tr><td>Current HP</td><td>" + getCurrentHp() + "</td><td>Current MP</td><td>" + getCurrentMp() + "</td></tr>");
  7538. +           html1.append("<tr><td>Max.HP</td><td>" + (int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null)) + "*" + getStat().calcStat(Stats.MAX_HP, 1, this, null) + "</td><td>Max.MP</td><td>" + getMaxMp() + "</td></tr>");
  7539. +           html1.append("<tr><td>P.Atk.</td><td>" + getPAtk(null) + "</td><td>M.Atk.</td><td>" + getMAtk(null, null) + "</td></tr>");
  7540. +           html1.append("<tr><td>P.Def.</td><td>" + getPDef(null) + "</td><td>M.Def.</td><td>" + getMDef(null, null) + "</td></tr>");
  7541. +           html1.append("<tr><td>Accuracy</td><td>" + getAccuracy() + "</td><td>Evasion</td><td>" + getEvasionRate(null) + "</td></tr>");
  7542. +           html1.append("<tr><td>Critical</td><td>" + getCriticalHit(null, null) + "</td><td>Speed</td><td>" + getRunSpeed() + "</td></tr>");
  7543. +           html1.append("<tr><td>Atk.Speed</td><td>" + getPAtkSpd() + "</td><td>Cast.Speed</td><td>" + getMAtkSpd() + "</td></tr>");
  7544. +           html1.append("</table><br>");
  7545. +          
  7546. +           html1.append("<font color=\"LEVEL\">Basic Stats</font>");
  7547. +           html1.append("<table border=\"0\" width=\"100%\">");
  7548. +           html1.append("<tr><td>STR</td><td>" + getSTR() + "</td><td>DEX</td><td>" + getDEX() + "</td><td>CON</td><td>" + getCON() + "</td></tr>");
  7549. +           html1.append("<tr><td>INT</td><td>" + getINT() + "</td><td>WIT</td><td>" + getWIT() + "</td><td>MEN</td><td>" + getMEN() + "</td></tr>");
  7550. +           html1.append("</table>");
  7551. +          
  7552. +           html1.append("<br><center><table><tr><td><button value=\"Edit NPC\" action=\"bypass -h admin_edit_npc " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"><br1></td>");
  7553. +           html1.append("<td><button value=\"Kill\" action=\"bypass -h admin_kill\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td><br1></tr>");
  7554. +           html1.append("<tr><td><button value=\"Show DropList\" action=\"bypass -h admin_show_droplist " + getTemplate().npcId + "\" width=100 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");
  7555. +           html1.append("<td><button value=\"Delete\" action=\"bypass -h admin_delete\" width=40 height=15 back=\"sek.cbui94\" fore=\"sek.cbui92\"></td></tr>");
  7556. +           html1.append("</table></center><br>");
  7557. +           html1.append("</body></html>");
  7558. +          
  7559. +           html.setHtml(html1.toString());
  7560. +           player.sendPacket(html);
  7561. +       }
  7562. +       else if (Config.ALT_GAME_VIEWNPC)
  7563. +       {
  7564. +           // Set the target of the L2PcInstance player
  7565. +           player.setTarget(this);
  7566. +          
  7567. +           // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  7568. +           // The player.getLevel() - getLevel() permit to display the correct color in the select window
  7569. +           MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
  7570. +           player.sendPacket(my);
  7571. +          
  7572. +           // Check if the player is attackable (without a forced attack)
  7573. +           if (isAutoAttackable(player))
  7574. +           {
  7575. +               // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to update its HP bar
  7576. +               StatusUpdate su = new StatusUpdate(getObjectId());
  7577. +               su.addAttribute(StatusUpdate.CUR_HP, (int) getCurrentHp());
  7578. +               su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
  7579. +               player.sendPacket(su);
  7580. +           }
  7581. +          
  7582. +           NpcHtmlMessage html = new NpcHtmlMessage(0);
  7583. +           TextBuilder html1 = new TextBuilder("<html><body>");
  7584. +          
  7585. +           html1.append("<br><center><font color=\"LEVEL\">[Combat Stats]</font></center>");
  7586. +           html1.append("<table border=0 width=\"100%\">");
  7587. +           html1.append("<tr><td>Max.HP</td><td>" + (int) (getMaxHp() / getStat().calcStat(Stats.MAX_HP, 1, this, null)) + "*" + (int) getStat().calcStat(Stats.MAX_HP, 1, this, null) + "</td><td>Max.MP</td><td>" + getMaxMp() + "</td></tr>");
  7588. +           html1.append("<tr><td>P.Atk.</td><td>" + getPAtk(null) + "</td><td>M.Atk.</td><td>" + getMAtk(null, null) + "</td></tr>");
  7589. +           html1.append("<tr><td>P.Def.</td><td>" + getPDef(null) + "</td><td>M.Def.</td><td>" + getMDef(null, null) + "</td></tr>");
  7590. +           html1.append("<tr><td>Accuracy</td><td>" + getAccuracy() + "</td><td>Evasion</td><td>" + getEvasionRate(null) + "</td></tr>");
  7591. +           html1.append("<tr><td>Critical</td><td>" + getCriticalHit(null, null) + "</td><td>Speed</td><td>" + getRunSpeed() + "</td></tr>");
  7592. +           html1.append("<tr><td>Atk.Speed</td><td>" + getPAtkSpd() + "</td><td>Cast.Speed</td><td>" + getMAtkSpd() + "</td></tr>");
  7593. +           html1.append("<tr><td>Race</td><td>" + getTemplate().race + "</td><td></td><td></td></tr>");
  7594. +           html1.append("</table>");
  7595. +          
  7596. +           html1.append("<br><center><font color=\"LEVEL\">[Basic Stats]</font></center>");
  7597. +           html1.append("<table border=0 width=\"100%\">");
  7598. +           html1.append("<tr><td>STR</td><td>" + getSTR() + "</td><td>DEX</td><td>" + getDEX() + "</td><td>CON</td><td>" + getCON() + "</td></tr>");
  7599. +           html1.append("<tr><td>INT</td><td>" + getINT() + "</td><td>WIT</td><td>" + getWIT() + "</td><td>MEN</td><td>" + getMEN() + "</td></tr>");
  7600. +           html1.append("</table>");
  7601. +          
  7602. +           html1.append("<br><center><font color=\"LEVEL\">[Drop Info]</font></center>");
  7603. +           html1.append("Rates legend: <font color=\"ff0000\">50%+</font> <font color=\"00ff00\">30%+</font> <font color=\"0000ff\">less than 30%</font>");
  7604. +           html1.append("<table border=0 width=\"100%\">");
  7605. +          
  7606. +           for (L2DropCategory cat : getTemplate().getDropData())
  7607. +           {
  7608. +               for (L2DropData drop : cat.getAllDrops())
  7609. +               {
  7610. +                   String name = ItemTable.getInstance().getTemplate(drop.getItemId()).getName();
  7611. +                  
  7612. +                   if (drop.getChance() >= 600000)
  7613. +                   {
  7614. +                       html1.append("<tr><td><font color=\"ff0000\">" + name + "</font></td><td>" + (drop.isQuestDrop() ? "Quest" : (cat.isSweep() ? "Sweep" : "Drop")) + "</td></tr>");
  7615. +                   }
  7616. +                   else if (drop.getChance() >= 300000)
  7617. +                   {
  7618. +                       html1.append("<tr><td><font color=\"00ff00\">" + name + "</font></td><td>" + (drop.isQuestDrop() ? "Quest" : (cat.isSweep() ? "Sweep" : "Drop")) + "</td></tr>");
  7619. +                   }
  7620. +                   else
  7621. +                   {
  7622. +                       html1.append("<tr><td><font color=\"0000ff\">" + name + "</font></td><td>" + (drop.isQuestDrop() ? "Quest" : (cat.isSweep() ? "Sweep" : "Drop")) + "</td></tr>");
  7623. +                   }
  7624. +               }
  7625. +           }
  7626. +          
  7627. +           html1.append("</table>");
  7628. +           html1.append("</body></html>");
  7629. +          
  7630. +           html.setHtml(html1.toString());
  7631. +           player.sendPacket(html);
  7632. +       }
  7633. +      
  7634. +       // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  7635. +       player.sendPacket(new ActionFailed());
  7636. +   }
  7637. +  
  7638. +   /** Return the L2Castle this L2NpcInstance belongs to. */
  7639. +   public final Castle getCastle()
  7640. +   {
  7641. +      
  7642. +       if (_castleIndex < 0)
  7643. +       {
  7644. +          
  7645. +           L2TownZone town = TownManager.getInstance().getTown(getX(), getY(), getZ());
  7646. +           if (town != null)
  7647. +           {
  7648. +               _castleIndex = CastleManager.getInstance().getCastleIndex(town.getTaxById());
  7649. +           }
  7650. +          
  7651. +           if (_castleIndex < 0)
  7652. +           {
  7653. +               _castleIndex = CastleManager.getInstance().findNearestCastleIndex(this);
  7654. +           }
  7655. +           else
  7656. +           {
  7657. +               _isInTown = true; // Npc was spawned in town
  7658. +           }
  7659. +          
  7660. +       }
  7661. +      
  7662. +       if (_castleIndex < 0)
  7663. +       {
  7664. +           return null;
  7665. +       }
  7666. +      
  7667. +       return CastleManager.getInstance().getCastles().get(_castleIndex);
  7668. +      
  7669. +   }
  7670. +  
  7671. +   public boolean getIsInCastleTown()
  7672. +   {
  7673. +       if (_castleIndex < 0)
  7674. +       {
  7675. +           getCastle();
  7676. +       }
  7677. +      
  7678. +       return _isInTown;
  7679. +   }
  7680. +  
  7681. +   /**
  7682. +    * Open a quest or chat window on client with the text of the L2NpcInstance in function of the command.<BR>
  7683. +    * <BR>
  7684. +    * <B><U> Example of use </U> :</B><BR>
  7685. +    * <BR>
  7686. +    * <li>Client packet : RequestBypassToServer</li><BR>
  7687. +    * <BR>
  7688. +    * @param command The command string received from client
  7689. +    */
  7690. +   public void onBypassFeedback(L2PcInstance player, String command)
  7691. +   {
  7692. +      
  7693. +       if (isBusy() && (getBusyMessage().length() > 0))
  7694. +       {
  7695. +           player.sendPacket(new ActionFailed());
  7696. +           NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  7697. +           html.setFile("data/html/npcbusy.htm");
  7698. +           html.replace("%busymessage%", getBusyMessage());
  7699. +           html.replace("%npcname%", getName());
  7700. +           html.replace("%playername%", player.getName());
  7701. +           player.sendPacket(html);
  7702. +       }
  7703. +      
  7704. +       else if (command.equalsIgnoreCase("TerritoryStatus"))
  7705. +       {
  7706. +           NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  7707. +           html.setFile("data/html/territorystatus.htm");
  7708. +           html.replace("%objectId%", String.valueOf(getObjectId()));
  7709. +           html.replace("%npcname%", getName());
  7710. +          
  7711. +           if (getIsInCastleTown())
  7712. +           {
  7713. +               html.replace("%castlename%", getCastle().getName());
  7714. +               html.replace("%taxpercent%", "" + getCastle().getTaxPercent());
  7715. +              
  7716. +               if (getCastle().getOwnerId() > 0)
  7717. +               {
  7718. +                   L2Clan clan = ClanTable.getInstance().getClan(getCastle().getOwnerId());
  7719. +                   html.replace("%clanname%", clan.getName());
  7720. +                   html.replace("%clanleadername%", clan.getLeaderName());
  7721. +               }
  7722. +               else
  7723. +               {
  7724. +                   html.replace("%clanname%", "NPC");
  7725. +                   html.replace("%clanleadername%", "NPC");
  7726. +               }
  7727. +           }
  7728. +           else
  7729. +           {
  7730. +               html.replace("%castlename%", "Open");
  7731. +               html.replace("%taxpercent%", "0");
  7732. +              
  7733. +               html.replace("%clanname%", "No");
  7734. +               html.replace("%clanleadername%", "None");
  7735. +           }
  7736. +          
  7737. +           player.sendPacket(html);
  7738. +       }
  7739. +       else if (command.startsWith("Quest"))
  7740. +       {
  7741. +           String quest = "";
  7742. +           try
  7743. +           {
  7744. +               quest = command.substring(5).trim();
  7745. +           }
  7746. +           catch (IndexOutOfBoundsException ioobe)
  7747. +           {
  7748. +           }
  7749. +          
  7750. +           if (quest.length() == 0)
  7751. +           {
  7752. +               showQuestWindow(player);
  7753. +           }
  7754. +           else
  7755. +           {
  7756. +               showQuestWindow(player, quest);
  7757. +           }
  7758. +       }
  7759. +       else if (command.startsWith("Chat"))
  7760. +       {
  7761. +           int val = 0;
  7762. +           try
  7763. +           {
  7764. +               val = Integer.parseInt(command.substring(5));
  7765. +           }
  7766. +           catch (IndexOutOfBoundsException ioobe)
  7767. +           {
  7768. +           }
  7769. +           catch (NumberFormatException nfe)
  7770. +           {
  7771. +           }
  7772. +          
  7773. +           showChatWindow(player, val);
  7774. +       }
  7775. +       else if (command.startsWith("Link"))
  7776. +       {
  7777. +           String path = command.substring(5).trim();
  7778. +           if (path.indexOf("..") != -1)
  7779. +           {
  7780. +               return;
  7781. +           }
  7782. +          
  7783. +           String filename = "data/html/" + path;
  7784. +           NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  7785. +           html.setFile(filename);
  7786. +           html.replace("%objectId%", String.valueOf(getObjectId()));
  7787. +           player.sendPacket(html);
  7788. +       }
  7789. +       else if (command.startsWith("NobleTeleport"))
  7790. +       {
  7791. +           if (!player.isNoble())
  7792. +           {
  7793. +               String filename = "data/html/teleporter/nobleteleporter-no.htm";
  7794. +               NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  7795. +               html.setFile(filename);
  7796. +               html.replace("%objectId%", String.valueOf(getObjectId()));
  7797. +               html.replace("%npcname%", getName());
  7798. +               player.sendPacket(html);
  7799. +               return;
  7800. +           }
  7801. +          
  7802. +           int val = 0;
  7803. +           try
  7804. +           {
  7805. +               val = Integer.parseInt(command.substring(14));
  7806. +           }
  7807. +           catch (IndexOutOfBoundsException ioobe)
  7808. +           {
  7809. +           }
  7810. +           catch (NumberFormatException nfe)
  7811. +           {
  7812. +           }
  7813. +          
  7814. +           showChatWindow(player, val);
  7815. +       }
  7816. +       else if (command.startsWith("Loto"))
  7817. +       {
  7818. +           int val = 0;
  7819. +           try
  7820. +           {
  7821. +               val = Integer.parseInt(command.substring(5));
  7822. +           }
  7823. +           catch (IndexOutOfBoundsException ioobe)
  7824. +           {
  7825. +           }
  7826. +           catch (NumberFormatException nfe)
  7827. +           {
  7828. +           }
  7829. +          
  7830. +           if (val == 0)
  7831. +           {
  7832. +               // new loto ticket
  7833. +               for (int i = 0; i < 5; i++)
  7834. +               {
  7835. +                   player.setLoto(i, 0);
  7836. +               }
  7837. +           }
  7838. +           showLotoWindow(player, val);
  7839. +       }
  7840. +       else if (command.startsWith("CPRecovery"))
  7841. +       {
  7842. +           makeCPRecovery(player);
  7843. +       }
  7844. +       else if (command.startsWith("SupportMagic"))
  7845. +       {
  7846. +           makeSupportMagic(player);
  7847. +       }
  7848. +       else if (command.startsWith("multisell"))
  7849. +       {
  7850. +           L2Multisell.getInstance().createMultiSell(Integer.parseInt(command.substring(9).trim()), player, false, this);
  7851. +       }
  7852. +       else if (command.startsWith("exc_multisell"))
  7853. +       {
  7854. +           L2Multisell.getInstance().createMultiSell(Integer.parseInt(command.substring(13).trim()), player, true, this);
  7855. +       }
  7856. +       else if (command.startsWith("npcfind_byid"))
  7857. +       {
  7858. +           try
  7859. +           {
  7860. +               L2Spawn spawn = SpawnTable.getInstance().getTemplate(Integer.parseInt(command.substring(12).trim()));
  7861. +              
  7862. +               if (spawn != null)
  7863. +               {
  7864. +                   player.sendPacket(new RadarControl(0, 1, spawn.getLocx(), spawn.getLocy(), spawn.getLocz()));
  7865. +               }
  7866. +           }
  7867. +           catch (NumberFormatException nfe)
  7868. +           {
  7869. +               player.sendMessage("Wrong command parameters");
  7870. +           }
  7871. +       }
  7872. +      
  7873. +   }
  7874. +  
  7875. +   /**
  7876. +    * Return null (regular NPCs don't have weapons instancies).<BR>
  7877. +    * <BR>
  7878. +    */
  7879. +   @Override
  7880. +   public L2ItemInstance getActiveWeaponInstance()
  7881. +   {
  7882. +       // regular NPCs dont have weapons instancies
  7883. +       return null;
  7884. +   }
  7885. +  
  7886. +   /**
  7887. +    * Return the weapon item equiped in the right hand of the L2NpcInstance or null.<BR>
  7888. +    * <BR>
  7889. +    */
  7890. +   @Override
  7891. +   public L2Weapon getActiveWeaponItem()
  7892. +   {
  7893. +       // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  7894. +       int weaponId = getTemplate().rhand;
  7895. +      
  7896. +       if (weaponId < 1)
  7897. +       {
  7898. +           return null;
  7899. +       }
  7900. +      
  7901. +       // Get the weapon item equiped in the right hand of the L2NpcInstance
  7902. +       L2Item item = ItemTable.getInstance().getTemplate(getTemplate().rhand);
  7903. +      
  7904. +       if (!(item instanceof L2Weapon))
  7905. +       {
  7906. +           return null;
  7907. +       }
  7908. +      
  7909. +       return (L2Weapon) item;
  7910. +   }
  7911. +  
  7912. +   /**
  7913. +    * Return null (regular NPCs don't have weapons instancies).<BR>
  7914. +    * <BR>
  7915. +    */
  7916. +   @Override
  7917. +   public L2ItemInstance getSecondaryWeaponInstance()
  7918. +   {
  7919. +       // regular NPCs dont have weapons instancies
  7920. +       return null;
  7921. +   }
  7922. +  
  7923. +   /**
  7924. +    * Return the weapon item equiped in the left hand of the L2NpcInstance or null.<BR>
  7925. +    * <BR>
  7926. +    */
  7927. +   @Override
  7928. +   public L2Weapon getSecondaryWeaponItem()
  7929. +   {
  7930. +       // Get the weapon identifier equiped in the right hand of the L2NpcInstance
  7931. +       int weaponId = getTemplate().lhand;
  7932. +      
  7933. +       if (weaponId < 1)
  7934. +       {
  7935. +           return null;
  7936. +       }
  7937. +      
  7938. +       // Get the weapon item equiped in the right hand of the L2NpcInstance
  7939. +       L2Item item = ItemTable.getInstance().getTemplate(getTemplate().lhand);
  7940. +      
  7941. +       if (!(item instanceof L2Weapon))
  7942. +       {
  7943. +           return null;
  7944. +       }
  7945. +      
  7946. +       return (L2Weapon) item;
  7947. +   }
  7948. +  
  7949. +   /**
  7950. +    * Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance.<BR>
  7951. +    * <BR>
  7952. +    * @param player The L2PcInstance who talks with the L2NpcInstance
  7953. +    * @param content The text of the L2NpcMessage
  7954. +    */
  7955. +   public void insertObjectIdAndShowChatWindow(L2PcInstance player, String content)
  7956. +   {
  7957. +       // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  7958. +       content = content.replaceAll("%objectId%", String.valueOf(getObjectId()));
  7959. +       NpcHtmlMessage npcReply = new NpcHtmlMessage(getObjectId());
  7960. +       npcReply.setHtml(content);
  7961. +       player.sendPacket(npcReply);
  7962. +   }
  7963. +  
  7964. +   /**
  7965. +    * Return the pathfile of the selected HTML file in function of the npcId and of the page number.<BR>
  7966. +    * <BR>
  7967. +    * <B><U> Format of the pathfile </U> :</B><BR>
  7968. +    * <BR>
  7969. +    * <li>if the file exists on the server (page number = 0) : <B>data/html/default/12006.htm</B> (npcId-page number)</li> <li>if the file exists on the server (page number > 0) : <B>data/html/default/12006-1.htm</B> (npcId-page number)</li> <li>if the file doesn't exist on the server :
  7970. +    * <B>data/html/npcdefault.htm</B> (message : "I have nothing to say to you")</li><BR>
  7971. +    * <BR>
  7972. +    * <B><U> Overriden in </U> :</B><BR>
  7973. +    * <BR>
  7974. +    * <li>L2GuardInstance : Set the pathfile to data/html/guard/12006-1.htm (npcId-page number)</li><BR>
  7975. +    * <BR>
  7976. +    * @param npcId The Identifier of the L2NpcInstance whose text must be display
  7977. +    * @param val The number of the page to display
  7978. +    */
  7979. +   public String getHtmlPath(int npcId, int val)
  7980. +   {
  7981. +       String pom = "";
  7982. +      
  7983. +       if (val == 0)
  7984. +       {
  7985. +           pom = "" + npcId;
  7986. +       }
  7987. +       else
  7988. +       {
  7989. +           pom = npcId + "-" + val;
  7990. +       }
  7991. +      
  7992. +       String temp = "data/html/default/" + pom + ".htm";
  7993. +      
  7994. +       if (!Config.LAZY_CACHE)
  7995. +       {
  7996. +           // If not running lazy cache the file must be in the cache or it doesnt exist
  7997. +           if (HtmCache.getInstance().contains(temp))
  7998. +           {
  7999. +               return temp;
  8000. +           }
  8001. +       }
  8002. +       else
  8003. +       {
  8004. +           if (HtmCache.getInstance().isLoadable(temp))
  8005. +           {
  8006. +               return temp;
  8007. +           }
  8008. +       }
  8009. +      
  8010. +       // If the file is not found, the standard message "I have nothing to say to you" is returned
  8011. +       return "data/html/npcdefault.htm";
  8012. +   }
  8013. +  
  8014. +   public void showBuyWindow(L2PcInstance player, int val)
  8015. +   {
  8016. +       double taxRate = 0;
  8017. +       if (getIsInCastleTown())
  8018. +       {
  8019. +           taxRate = getCastle().getTaxRate();
  8020. +       }
  8021. +      
  8022. +       player.tempInventoryDisable();
  8023. +      
  8024. +       if (Config.DEBUG)
  8025. +       {
  8026. +           _log.fine("Showing buylist");
  8027. +       }
  8028. +      
  8029. +       L2TradeList list = TradeController.getInstance().getBuyList(val);
  8030. +      
  8031. +       if ((list != null) && list.getNpcId().equals(String.valueOf(getNpcId())))
  8032. +       {
  8033. +           player.sendPacket(new BuyList(list, player.getAdena(), taxRate));
  8034. +       }
  8035. +       else
  8036. +       {
  8037. +           _log.warning("possible client hacker: " + player.getName() + " attempting to buy from GM shop! < Ban him!");
  8038. +           _log.warning("buylist id:" + val);
  8039. +       }
  8040. +      
  8041. +       player.sendPacket(new ActionFailed());
  8042. +   }
  8043. +  
  8044. +   /**
  8045. +    * Open a choose quest window on client with all quests available of the L2NpcInstance.<BR>
  8046. +    * <BR>
  8047. +    * <B><U> Actions</U> :</B><BR>
  8048. +    * <BR>
  8049. +    * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance</li><BR>
  8050. +    * <BR>
  8051. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  8052. +    * @param quests The table containing quests of the L2NpcInstance
  8053. +    */
  8054. +   public void showQuestChooseWindow(L2PcInstance player, Quest[] quests)
  8055. +   {
  8056. +       TextBuilder sb = new TextBuilder();
  8057. +      
  8058. +       sb.append("<html><body><title>Talk about:</title><br>");
  8059. +      
  8060. +       for (Quest q : quests)
  8061. +       {
  8062. +           sb.append("<a action=\"bypass -h npc_").append(getObjectId()).append("_Quest ").append(q.getName()).append("\">").append(q.getDescr()).append("</a><br>");
  8063. +       }
  8064. +      
  8065. +       sb.append("</body></html>");
  8066. +      
  8067. +       // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  8068. +       insertObjectIdAndShowChatWindow(player, sb.toString());
  8069. +   }
  8070. +  
  8071. +   /**
  8072. +    * Open a quest window on client with the text of the L2NpcInstance.<BR>
  8073. +    * <BR>
  8074. +    * <B><U> Actions</U> :</B><BR>
  8075. +    * <BR>
  8076. +    * <li>Get the text of the quest state in the folder data/jscript/quests/questId/stateId.htm</li> <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance</li> <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the
  8077. +    * client wait another packet</li><BR>
  8078. +    * <BR>
  8079. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  8080. +    * @param questId The Identifier of the quest to display the message
  8081. +    */
  8082. +   public void showQuestWindow(L2PcInstance player, String questId)
  8083. +   {
  8084. +       String content;
  8085. +      
  8086. +       // Get the state of the selected quest
  8087. +       QuestState qs = player.getQuestState(questId);
  8088. +      
  8089. +       if (qs != null)
  8090. +       {
  8091. +           // If the quest is already started, no need to show a window
  8092. +           if (!qs.getQuest().notifyTalk(this, qs))
  8093. +           {
  8094. +               return;
  8095. +           }
  8096. +       }
  8097. +       else
  8098. +       {
  8099. +           Quest q = QuestManager.getInstance().getQuest(questId);
  8100. +           if (q != null)
  8101. +           {
  8102. +               if ((q.getQuestIntId() >= 1) && (q.getQuestIntId() < 1000))
  8103. +               {
  8104. +                   Quest[] questList = player.getAllActiveQuests();
  8105. +                   if (questList.length >= 15) // if too many ongoing quests, don't show window and send message
  8106. +                   {
  8107. +                       player.sendPacket(new SystemMessage(401));
  8108. +                       return;
  8109. +                   }
  8110. +                  
  8111. +                   if ((player.getWeightPenalty() >= 3) || ((player.getInventoryLimit() * 0.8) <= player.getInventory().getSize()))
  8112. +                   {
  8113. +                       player.sendPacket(new SystemMessage(1118));
  8114. +                       return;
  8115. +                   }
  8116. +               }
  8117. +              
  8118. +               // check for start point
  8119. +               Quest[] qlst = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  8120. +              
  8121. +               if ((qlst != null) && (qlst.length > 0))
  8122. +               {
  8123. +                   for (Quest element : qlst)
  8124. +                   {
  8125. +                       if (element == q)
  8126. +                       {
  8127. +                           qs = q.newQuestState(player);
  8128. +                           // disabled by mr. because quest dialog only show on second click.
  8129. +                           // if(qs.getState().getName().equalsIgnoreCase("completed"))
  8130. +                           // {
  8131. +                           if (!qs.getQuest().notifyTalk(this, qs))
  8132. +                           {
  8133. +                               return; // no need to show a window
  8134. +                           }
  8135. +                           // }
  8136. +                           break;
  8137. +                       }
  8138. +                   }
  8139. +               }
  8140. +           }
  8141. +       }
  8142. +      
  8143. +       if (qs == null)
  8144. +       {
  8145. +           // no quests found
  8146. +           content = "<html><body>I have no tasks for you right now.</body></html>";
  8147. +       }
  8148. +       else
  8149. +       {
  8150. +           questId = qs.getQuest().getName();
  8151. +           String stateId = qs.getStateId();
  8152. +           String path = "data/jscript/quests/" + questId + "/" + stateId + ".htm";
  8153. +           content = HtmCache.getInstance().getHtm(path); // TODO path for quests html
  8154. +          
  8155. +           if (Config.DEBUG)
  8156. +           {
  8157. +               if (content != null)
  8158. +               {
  8159. +                   _log.fine("Showing quest window for quest " + questId + " html path: " + path);
  8160. +               }
  8161. +               else
  8162. +               {
  8163. +                   _log.fine("File not exists for quest " + questId + " html path: " + path);
  8164. +               }
  8165. +           }
  8166. +       }
  8167. +      
  8168. +       // Send a Server->Client packet NpcHtmlMessage to the L2PcInstance in order to display the message of the L2NpcInstance
  8169. +       if (content != null)
  8170. +       {
  8171. +           insertObjectIdAndShowChatWindow(player, content);
  8172. +       }
  8173. +      
  8174. +       // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  8175. +       player.sendPacket(new ActionFailed());
  8176. +   }
  8177. +  
  8178. +   /**
  8179. +    * Collect awaiting quests/start points and display a QuestChooseWindow (if several available) or QuestWindow.<BR>
  8180. +    * <BR>
  8181. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  8182. +    */
  8183. +   public void showQuestWindow(L2PcInstance player)
  8184. +   {
  8185. +       // collect awaiting quests and start points
  8186. +       List<Quest> options = new FastList<Quest>();
  8187. +      
  8188. +       QuestState[] awaits = player.getQuestsForTalk(getTemplate().npcId);
  8189. +       Quest[] starts = getTemplate().getEventQuests(Quest.QuestEventType.QUEST_START);
  8190. +      
  8191. +       // Quests are limited between 1 and 999 because those are the quests that are supported by the client.
  8192. +       if (awaits != null)
  8193. +       {
  8194. +           for (QuestState x : awaits)
  8195. +           {
  8196. +               if (!options.contains(x))
  8197. +               {
  8198. +                   if ((x.getQuest().getQuestIntId() > 0) && (x.getQuest().getQuestIntId() < 1000))
  8199. +                   {
  8200. +                       options.add(x.getQuest());
  8201. +                   }
  8202. +               }
  8203. +           }
  8204. +       }
  8205. +      
  8206. +       if (starts != null)
  8207. +       {
  8208. +           for (Quest x : starts)
  8209. +           {
  8210. +               if (!options.contains(x))
  8211. +               {
  8212. +                   if ((x.getQuestIntId() > 0) && (x.getQuestIntId() < 1000))
  8213. +                   {
  8214. +                       options.add(x);
  8215. +                   }
  8216. +               }
  8217. +           }
  8218. +       }
  8219. +      
  8220. +       // Display a QuestChooseWindow (if several quests are available) or QuestWindow
  8221. +       if (options.size() > 1)
  8222. +       {
  8223. +           showQuestChooseWindow(player, options.toArray(new Quest[options.size()]));
  8224. +       }
  8225. +       else if (options.size() == 1)
  8226. +       {
  8227. +           showQuestWindow(player, options.get(0).getName());
  8228. +       }
  8229. +       else
  8230. +       {
  8231. +           showQuestWindow(player, "");
  8232. +       }
  8233. +   }
  8234. +  
  8235. +   /**
  8236. +    * Open a Loto window on client with the text of the L2NpcInstance.<BR>
  8237. +    * <BR>
  8238. +    * <B><U> Actions</U> :</B><BR>
  8239. +    * <BR>
  8240. +    * <li>Get the text of the selected HTML file in function of the npcId and of the page number</li> <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance</li> <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the
  8241. +    * client wait another packet</li><BR>
  8242. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  8243. +    * @param val The number of the page of the L2NpcInstance to display
  8244. +    */
  8245. +   // 0 - first buy lottery ticket window
  8246. +   // 1-20 - buttons
  8247. +   // 21 - second buy lottery ticket window
  8248. +   // 22 - selected ticket with 5 numbers
  8249. +   // 23 - current lottery jackpot
  8250. +   // 24 - Previous winning numbers/Prize claim
  8251. +   // >24 - check lottery ticket by item object id
  8252. +   public void showLotoWindow(L2PcInstance player, int val)
  8253. +   {
  8254. +       int npcId = getTemplate().npcId;
  8255. +       String filename;
  8256. +       SystemMessage sm;
  8257. +       NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  8258. +      
  8259. +       if (val == 0) // 0 - first buy lottery ticket window
  8260. +       {
  8261. +           filename = (getHtmlPath(npcId, 1));
  8262. +           html.setFile(filename);
  8263. +       }
  8264. +       else if ((val >= 1) && (val <= 21)) // 1-20 - buttons, 21 - second buy lottery ticket window
  8265. +       {
  8266. +           if (!Lottery.getInstance().isStarted())
  8267. +           {
  8268. +               // tickets can't be sold
  8269. +               player.sendPacket(new SystemMessage(930));
  8270. +               return;
  8271. +           }
  8272. +           if (!Lottery.getInstance().isSellableTickets())
  8273. +           {
  8274. +               // tickets can't be sold
  8275. +               player.sendPacket(new SystemMessage(784));
  8276. +               return;
  8277. +           }
  8278. +          
  8279.             filename = (getHtmlPath(npcId, 5));
  8280.             html.setFile(filename);
  8281.            
  8282.             int count = 0;
  8283.             int found = 0;
  8284.             // counting buttons and unsetting button if found
  8285. -            for (int i = 0; i < 5; i++)
  8286. -            {
  8287. -                if (player.getLoto(i) == val)
  8288. -                {
  8289. -                         //unsetting button
  8290. -                    player.setLoto(i, 0);
  8291. -                    found = 1;
  8292. -                }
  8293. -                else if (player.getLoto(i) > 0)
  8294. -                {
  8295. -                   count++;
  8296. -                }
  8297. -            }
  8298. -            
  8299. -                 //if not rearched limit 5 and not unseted value
  8300. -            if (count < 5 && found == 0 && val <= 20)
  8301. -                for (int i = 0; i < 5; i++)
  8302. -                    if (player.getLoto(i) == 0)
  8303. -                    {
  8304. -                        player.setLoto(i, val);
  8305. -                        break;
  8306. -                    }
  8307. -            
  8308. -            //setting pusshed buttons
  8309. -            count = 0;
  8310. -            for (int i = 0; i < 5; i++)
  8311. -                if (player.getLoto(i) > 0)
  8312. -                {
  8313. -                    count++;
  8314. -                    String button = String.valueOf(player.getLoto(i));
  8315. -                    if (player.getLoto(i) < 10) button = "0" + button;
  8316. -                    String search = "fore=\"L2UI.lottoNum" + button + "\" back=\"L2UI.lottoNum" + button + "a_check\"";
  8317. -                    String replace = "fore=\"L2UI.lottoNum" + button + "a_check\" back=\"L2UI.lottoNum" + button + "\"";
  8318. -                    html.replace(search, replace);
  8319. -                }
  8320. -            
  8321. -            if (count == 5)
  8322. -            {
  8323. -                String search = "0\">Return";
  8324. -                String replace = "22\">The winner selected the numbers above.";
  8325. -                html.replace(search, replace);
  8326. -            }
  8327. -        }
  8328. -        else if (val == 22) //22 - selected ticket with 5 numbers
  8329. -        {
  8330. -            if (!Lottery.getInstance().isStarted())
  8331. -            {
  8332. -                //tickets can't be sold
  8333. -                player.sendPacket(new SystemMessage(930));
  8334. -                return;
  8335. -            }
  8336. -            if (!Lottery.getInstance().isSellableTickets())
  8337. -            {
  8338. -                //tickets can't be sold
  8339. -                player.sendPacket(new SystemMessage(784));
  8340. -                return;
  8341. -            }
  8342. -                
  8343. -            int price = Config.ALT_LOTTERY_TICKET_PRICE;
  8344. -            int lotonumber = Lottery.getInstance().getId();
  8345. -            int enchant = 0;
  8346. -            int type2 = 0;
  8347. -                
  8348. -            for (int i = 0; i < 5; i++)
  8349. -            {
  8350. -                if (player.getLoto(i) == 0) return;
  8351. -                    
  8352. -                if (player.getLoto(i) < 17) enchant += Math.pow(2, player.getLoto(i) - 1);
  8353. -                else type2 += Math.pow(2, player.getLoto(i) - 17);
  8354. -            }
  8355. -            if (player.getAdena() < price)
  8356. -            {
  8357. -                     sm = new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA);
  8358. -                     player.sendPacket(sm);
  8359. -                     return;
  8360. -            }
  8361. -            if (!player.reduceAdena("Loto", price, this, true)) return;
  8362. -            Lottery.getInstance().increasePrize(price);
  8363. -
  8364. -            sm = new SystemMessage(SystemMessage.ACQUIRED);
  8365. -            sm.addNumber(lotonumber);
  8366. -            sm.addItemName(4442);
  8367. -            player.sendPacket(sm);
  8368. -            
  8369. -            L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), 4442);
  8370. +           for (int i = 0; i < 5; i++)
  8371. +           {
  8372. +               if (player.getLoto(i) == val)
  8373. +               {
  8374. +                   // unsetting button
  8375. +                   player.setLoto(i, 0);
  8376. +                   found = 1;
  8377. +               }
  8378. +               else if (player.getLoto(i) > 0)
  8379. +               {
  8380. +                   count++;
  8381. +               }
  8382. +           }
  8383. +          
  8384. +           // if not rearched limit 5 and not unseted value
  8385. +           if ((count < 5) && (found == 0) && (val <= 20))
  8386. +           {
  8387. +               for (int i = 0; i < 5; i++)
  8388. +               {
  8389. +                   if (player.getLoto(i) == 0)
  8390. +                   {
  8391. +                       player.setLoto(i, val);
  8392. +                       break;
  8393. +                   }
  8394. +               }
  8395. +           }
  8396. +          
  8397. +           // setting pusshed buttons
  8398. +           count = 0;
  8399. +           for (int i = 0; i < 5; i++)
  8400. +           {
  8401. +               if (player.getLoto(i) > 0)
  8402. +               {
  8403. +                   count++;
  8404. +                   String button = String.valueOf(player.getLoto(i));
  8405. +                   if (player.getLoto(i) < 10)
  8406. +                   {
  8407. +                       button = "0" + button;
  8408. +                   }
  8409. +                   String search = "fore=\"L2UI.lottoNum" + button + "\" back=\"L2UI.lottoNum" + button + "a_check\"";
  8410. +                   String replace = "fore=\"L2UI.lottoNum" + button + "a_check\" back=\"L2UI.lottoNum" + button + "\"";
  8411. +                   html.replace(search, replace);
  8412. +               }
  8413. +           }
  8414. +          
  8415. +           if (count == 5)
  8416. +           {
  8417. +               String search = "0\">Return";
  8418. +               String replace = "22\">The winner selected the numbers above.";
  8419. +               html.replace(search, replace);
  8420. +           }
  8421. +       }
  8422. +       else if (val == 22) // 22 - selected ticket with 5 numbers
  8423. +       {
  8424. +           if (!Lottery.getInstance().isStarted())
  8425. +           {
  8426. +               // tickets can't be sold
  8427. +               player.sendPacket(new SystemMessage(930));
  8428. +               return;
  8429. +           }
  8430. +           if (!Lottery.getInstance().isSellableTickets())
  8431. +           {
  8432. +               // tickets can't be sold
  8433. +               player.sendPacket(new SystemMessage(784));
  8434. +               return;
  8435. +           }
  8436. +          
  8437. +           int price = Config.ALT_LOTTERY_TICKET_PRICE;
  8438. +           int lotonumber = Lottery.getInstance().getId();
  8439. +           int enchant = 0;
  8440. +           int type2 = 0;
  8441. +          
  8442. +           for (int i = 0; i < 5; i++)
  8443. +           {
  8444. +               if (player.getLoto(i) == 0)
  8445. +               {
  8446. +                   return;
  8447. +               }
  8448. +              
  8449. +               if (player.getLoto(i) < 17)
  8450. +               {
  8451. +                   enchant += Math.pow(2, player.getLoto(i) - 1);
  8452. +               }
  8453. +               else
  8454. +               {
  8455. +                   type2 += Math.pow(2, player.getLoto(i) - 17);
  8456. +               }
  8457. +           }
  8458. +           if (player.getAdena() < price)
  8459. +           {
  8460. +               sm = new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA);
  8461. +               player.sendPacket(sm);
  8462. +               return;
  8463. +           }
  8464. +           if (!player.reduceAdena("Loto", price, this, true))
  8465. +           {
  8466. +               return;
  8467. +           }
  8468. +           Lottery.getInstance().increasePrize(price);
  8469. +          
  8470. +           sm = new SystemMessage(SystemMessage.ACQUIRED);
  8471. +           sm.addNumber(lotonumber);
  8472. +           sm.addItemName(4442);
  8473. +           player.sendPacket(sm);
  8474. +          
  8475. +           L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), 4442);
  8476.             item.setCount(1);
  8477.             item.setCustomType1(lotonumber);
  8478.             item.setEnchantLevel(enchant);
  8479. @@ -1504,720 +1651,812 @@
  8480.             L2ItemInstance adenaupdate = player.getInventory().getItemByItemId(57);
  8481.             iu.addModifiedItem(adenaupdate);
  8482.             player.sendPacket(iu);
  8483. -            
  8484. -            filename = (getHtmlPath(npcId, 3));
  8485. -            html.setFile(filename);
  8486. -        }
  8487. -        else if (val == 23) //23 - current lottery jackpot
  8488. -        {
  8489. -            filename = (getHtmlPath(npcId, 3));
  8490. -            html.setFile(filename);
  8491. -        }
  8492. -        else if (val == 24) // 24 - Previous winning numbers/Prize claim
  8493. -        {
  8494. -            filename = (getHtmlPath(npcId, 4));
  8495. -            html.setFile(filename);
  8496. -            
  8497. -            int lotonumber = Lottery.getInstance().getId();
  8498. -            String message = "";
  8499. -            for (L2ItemInstance item : player.getInventory().getItems())
  8500. -            {
  8501. -                if (item == null) continue;
  8502. -                if (item.getItemId() == 4442 && item.getCustomType1() < lotonumber)
  8503. -                {
  8504. -                    message = message + "<a action=\"bypass -h npc_%objectId%_Loto "
  8505. -                    + item.getObjectId() + "\">" + item.getCustomType1() + " Event Number ";
  8506. -                    int[] numbers = Lottery.getInstance().decodeNumbers(item.getEnchantLevel(),
  8507. -                                                                        item.getCustomType2());
  8508. -                    for (int i = 0; i < 5; i++)
  8509. -                    {
  8510. -                        message += numbers[i] + " ";
  8511. -                    }
  8512. -                    int[] check = Lottery.getInstance().checkTicket(item);
  8513. -                    if (check[0] > 0)
  8514. -                    {
  8515. -                        switch (check[0])
  8516. -                        {
  8517. -                            case 1:
  8518. -                                message += "- 1st Prize";
  8519. -                                break;
  8520. -                            case 2:
  8521. -                                message += "- 2nd Prize";
  8522. -                                break;
  8523. -                            case 3:
  8524. -                                message += "- 3th Prize";
  8525. -                                break;
  8526. -                            case 4:
  8527. -                                message += "- 4th Prize";
  8528. -                                break;
  8529. -                        }
  8530. -                        message += " " + check[1] + "a.";
  8531. -                    }
  8532. -                    message += "</a><br>";
  8533. -                }
  8534. -            }
  8535. -            if (message == "")
  8536. -            {
  8537. -                message += "There is no winning lottery ticket...<br>";
  8538. -            }
  8539. -            html.replace("%result%", message);
  8540. -        }
  8541. -        else if (val > 24) // >24 - check lottery ticket by item object id
  8542. -        {
  8543. -            int lotonumber = Lottery.getInstance().getId();
  8544. -            L2ItemInstance item = player.getInventory().getItemByObjectId(val);
  8545. -            if (item == null || item.getItemId() != 4442 || item.getCustomType1() >= lotonumber) return;
  8546. -            int[] check = Lottery.getInstance().checkTicket(item);
  8547. -            
  8548. -            sm = new SystemMessage(SystemMessage.DISSAPEARED_ITEM);
  8549. -            sm.addItemName(4442);
  8550. -            player.sendPacket(sm);
  8551. -            
  8552. -            int adena = check[1];
  8553. -            if (adena > 0)
  8554. -                player.addAdena("Loto", adena, this, true);
  8555. -            player.destroyItem("Loto", item, this, false);
  8556. -            return;
  8557. -        }
  8558. -        html.replace("%objectId%", String.valueOf(getObjectId()));
  8559. -        html.replace("%race%", "" + Lottery.getInstance().getId());
  8560. -        html.replace("%adena%", "" + Lottery.getInstance().getPrize());
  8561. -        html.replace("%ticket_price%", "" + Config.ALT_LOTTERY_TICKET_PRICE);
  8562. -        html.replace("%prize5%", "" + (Config.ALT_LOTTERY_5_NUMBER_RATE * 100));
  8563. -        html.replace("%prize4%", "" + (Config.ALT_LOTTERY_4_NUMBER_RATE * 100));
  8564. -        html.replace("%prize3%", "" + (Config.ALT_LOTTERY_3_NUMBER_RATE * 100));
  8565. -        html.replace("%prize2%", "" + Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE);
  8566. -        html.replace("%enddate%", "" + DateFormat.getDateInstance().format(Lottery.getInstance().getEndDate()));
  8567. -        player.sendPacket(html);
  8568. -            
  8569. -        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  8570. -        player.sendPacket(new ActionFailed());
  8571. -    }
  8572. -    
  8573. -    public void makeCPRecovery(L2PcInstance player)
  8574. -    {
  8575. -        if (getNpcId() != 8225 && getNpcId() != 8226)
  8576. -            return;
  8577. -
  8578. -        int neededmoney = 100;
  8579. -
  8580. -        if (!player.reduceAdena("RestoreCP", neededmoney, player.getLastFolkNPC(), true))
  8581. -            return;
  8582. -
  8583. -        L2Skill skill = SkillTable.getInstance().getInfo(4380, 1);
  8584. -        if (skill != null)
  8585. -        {
  8586. -            setTarget(player);
  8587. -            doCast(skill);
  8588. -        }
  8589. -        player.sendPacket(new ActionFailed());
  8590. -    }
  8591. -
  8592. -  
  8593. -    /**
  8594. -     * Add Newbie helper buffs to L2Player according to its level.<BR><BR>
  8595. -     *
  8596. -     * <B><U> Actions</U> :</B><BR><BR>
  8597. -     * <li>Get the range level in wich player must be to obtain buff </li>
  8598. -     * <li>If player level is out of range, display a message and return </li>
  8599. -     * <li>According to player level cast buff </li><BR><BR>
  8600. -     *
  8601. -     * <FONT COLOR=#FF0000><B> Newbie Helper Buff list is define in sql table helper_buff_list</B></FONT><BR><BR>
  8602. -     *
  8603. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  8604. -     *
  8605. -     */
  8606. -    public void makeSupportMagic(L2PcInstance player)
  8607. -    {
  8608. -        int player_level = player.getLevel();        
  8609. -        int lowestLevel;
  8610. -        int higestLevel;
  8611. -        L2Skill skill;
  8612. -        
  8613. -        
  8614. -        // Select the player
  8615. -        setTarget(player);
  8616. -        
  8617. -        
  8618. -        // Calculate the min and max level between wich the player must be to obtain buff
  8619. -        if(player.isMageClass())
  8620. -        {
  8621. -            lowestLevel = HelperBuffTable.getInstance().getMagicClassLowestLevel();
  8622. -            higestLevel = HelperBuffTable.getInstance().getMagicClassHighestLevel();
  8623. -        }
  8624. -        else
  8625. -        {
  8626. -            lowestLevel = HelperBuffTable.getInstance().getPhysicClassLowestLevel();
  8627. -            higestLevel = HelperBuffTable.getInstance().getPhysicClassHighestLevel();
  8628. -        }
  8629. -        
  8630. -      
  8631. -        // If the player is too high level, display a message and return
  8632. -        if (player_level > higestLevel)
  8633. -        {
  8634. -            String content = "<html><body>Newbie Guide:<br>Only a <font color=\"LEVEL\">novice character of level "+ higestLevel +" or less</font> can receive my support magic.<br>Your novice character is the first one that you created and raised in this world.</body></html>";
  8635. -            insertObjectIdAndShowChatWindow(player, content);
  8636. -            return;
  8637. -        }
  8638. -        
  8639. -        
  8640. -        // If the player is too low level, display a message and return
  8641. -        if (player_level < lowestLevel)
  8642. -        {
  8643. -            String content = "<html><body>Come back here when you have reached level "+ lowestLevel +". I will give you support magic then.</body></html>";
  8644. -            insertObjectIdAndShowChatWindow(player, content);
  8645. -            return;
  8646. -        }
  8647. -        
  8648. -        
  8649. -        // Go through the Helper Buff list define in sql table helper_buff_list and cast skill
  8650. -        for (L2HelperBuff helperBuffItem : HelperBuffTable.getInstance().getHelperBuffTable())
  8651. -        {
  8652. -           if( helperBuffItem.isMagicClassBuff() == player.isMageClass())
  8653. -           {
  8654. -              if(player_level>=helperBuffItem.getLowerLevel() && player_level<=helperBuffItem.getUpperLevel())
  8655. -              {
  8656. -                  skill = SkillTable.getInstance().getInfo(helperBuffItem.getSkillID(),helperBuffItem.getSkillLevel());
  8657. -                  if (skill.getSkillType() == SkillType.SUMMON)
  8658. -                      player.doCast(skill);
  8659. -                  else
  8660. -                      doCast(skill);
  8661. -              }
  8662. -           }
  8663. -        }
  8664. -        
  8665. -        
  8666. -    }
  8667. -    
  8668. -    public void showChatWindow(L2PcInstance player)
  8669. -    {
  8670. -        showChatWindow(player, 0);
  8671. -    }
  8672. -
  8673. -    /**
  8674. -     * Open a chat window on client with the text of the L2NpcInstance.<BR><BR>
  8675. -     *
  8676. -     * <B><U> Actions</U> :</B><BR><BR>
  8677. -     * <li>Get the text of the selected HTML file in function of the npcId and of the page number </li>
  8678. -     * <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance </li>
  8679. -     * <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet </li><BR>
  8680. -     *
  8681. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  8682. -     * @param val The number of the page of the L2NpcInstance to display
  8683. -     *
  8684. -     */
  8685. -    public void showChatWindow(L2PcInstance player, int val)
  8686. -    {
  8687. -        if (getTemplate().type == "L2Auctioneer" && val==0)
  8688. -            return;
  8689. -        int npcId = getTemplate().npcId;
  8690. -        
  8691. -        /* For use with Seven Signs implementation */
  8692. -        String filename = SevenSigns.SEVEN_SIGNS_HTML_PATH;
  8693. -        int sealAvariceOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_AVARICE);
  8694. -        int sealGnosisOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_GNOSIS);
  8695. -        int playerCabal = SevenSigns.getInstance().getPlayerCabal(player);
  8696. -        boolean isSealValidationPeriod = SevenSigns.getInstance().isSealValidationPeriod();
  8697. -        int compWinner = SevenSigns.getInstance().getCabalHighestScore();
  8698. -        
  8699. -        switch (npcId) {
  8700. -            case 8078:
  8701. -            case 8079:
  8702. -            case 8080:
  8703. -            case 8081:
  8704. -            case 8082: // Dawn Priests
  8705. -            case 8083:
  8706. -            case 8084:
  8707. -            case 8168:
  8708. -            case 8692:
  8709. -            case 8694:
  8710. -                switch (playerCabal)
  8711. -                {
  8712. -                    case SevenSigns.CABAL_DAWN:
  8713. -                        if (isSealValidationPeriod)
  8714. -                            if (compWinner == SevenSigns.CABAL_DAWN)
  8715. -                               if (compWinner != sealGnosisOwner)
  8716. -                                   filename += "dawn_priest_2c.htm";
  8717. -                               else
  8718. -                                   filename += "dawn_priest_2a.htm";
  8719. -                            else
  8720. -                                filename += "dawn_priest_2b.htm";
  8721. -                        else
  8722. -                            filename += "dawn_priest_1b.htm";
  8723. -                        break;
  8724. -                    case SevenSigns.CABAL_DUSK:
  8725. -                        if (isSealValidationPeriod)
  8726. -                            filename += "dawn_priest_3b.htm";
  8727. -                        else
  8728. -                            filename += "dawn_priest_3a.htm";
  8729. -                        break;
  8730. -                    default:
  8731. -                        if (isSealValidationPeriod)
  8732. -                            if (compWinner == SevenSigns.CABAL_DAWN)
  8733. -                                filename += "dawn_priest_4.htm";
  8734. -                            else
  8735. -                                filename += "dawn_priest_2b.htm";  
  8736. -                        else
  8737. -                            filename += "dawn_priest_1a.htm";
  8738. -                    break;
  8739. -                }
  8740. -                break;
  8741. -            case 8085:
  8742. -            case 8086:
  8743. -            case 8087:
  8744. -            case 8088: // Dusk Priest
  8745. -            case 8089:
  8746. -            case 8090:
  8747. -            case 8091:
  8748. -            case 8169:
  8749. -            case 8693:
  8750. -            case 8695:
  8751. -                switch (playerCabal)
  8752. -                {
  8753. -                    case SevenSigns.CABAL_DUSK:
  8754. -                        if (isSealValidationPeriod)
  8755. -                            if (compWinner == SevenSigns.CABAL_DUSK)
  8756. -                               if (compWinner != sealGnosisOwner)
  8757. -                                   filename += "dusk_priest_2c.htm";
  8758. -                               else
  8759. -                                   filename += "dusk_priest_2a.htm";
  8760. -                            else
  8761. -                                filename += "dusk_priest_2b.htm";
  8762. -                        else
  8763. -                            filename += "dusk_priest_1b.htm";
  8764. -                        break;
  8765. -                    case SevenSigns.CABAL_DAWN:
  8766. -                        if (isSealValidationPeriod)
  8767. -                            filename += "dusk_priest_3b.htm";
  8768. -                        else
  8769. -                            filename += "dusk_priest_3a.htm";
  8770. -                        break;
  8771. -                    default:
  8772. -                        if (isSealValidationPeriod)
  8773. -                            if (compWinner == SevenSigns.CABAL_DUSK)
  8774. -                                filename += "dusk_priest_4.htm";
  8775. -                            else
  8776. -                                filename += "dusk_priest_2b.htm";
  8777. -                        else
  8778. -                            filename += "dusk_priest_1a.htm";
  8779. -                    break;
  8780. -                }
  8781. -                break;
  8782. -            case 8095: //
  8783. -            case 8096: //
  8784. -            case 8097: //
  8785. -            case 8098: // Enter Necropolises
  8786. -            case 8099: //
  8787. -            case 8100: //
  8788. -            case 8101: //
  8789. -            case 8102: //
  8790. -                if (isSealValidationPeriod)
  8791. -                {
  8792. -                        if (playerCabal != compWinner || sealAvariceOwner != compWinner)
  8793. -                   {
  8794. -                           switch (compWinner)
  8795. -                           {
  8796. -                                   case SevenSigns.CABAL_DAWN:
  8797. -                                                player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  8798. -                                                filename += "necro_no.htm";
  8799. -                                       break;
  8800. -                               case SevenSigns.CABAL_DUSK:
  8801. -                                                player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  8802. -                                                filename += "necro_no.htm";
  8803. -                                   break;
  8804. -                               case SevenSigns.CABAL_NULL:
  8805. -                                           filename = (getHtmlPath(npcId, val)); // do the default!
  8806. -                                       break;
  8807. -                       }
  8808. -               }
  8809. -               else
  8810. -                               filename = (getHtmlPath(npcId, val)); // do the default!
  8811. -                }
  8812. -                else
  8813. -                {
  8814. -                    if (playerCabal == SevenSigns.CABAL_NULL)
  8815. -                        filename += "necro_no.htm";
  8816. -                    else
  8817. -                        filename = (getHtmlPath(npcId, val)); // do the default!    
  8818. -                }
  8819. -                break;
  8820. -            case 8114: //
  8821. -            case 8115: //
  8822. -            case 8116: // Enter Catacombs
  8823. -            case 8117: //
  8824. -            case 8118: //
  8825. -            case 8119: //
  8826. -                if (isSealValidationPeriod)
  8827. -                {
  8828. -                    if (playerCabal != compWinner || sealGnosisOwner != compWinner)
  8829. -               {
  8830. -                   switch (compWinner)
  8831. -                   {
  8832. -                       case SevenSigns.CABAL_DAWN:
  8833. -                                        player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  8834. -                                        filename += "cata_no.htm";
  8835. -                           break;
  8836. -                       case SevenSigns.CABAL_DUSK:
  8837. -                                        player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  8838. -                                        filename += "cata_no.htm";
  8839. -                           break;
  8840. -                       case SevenSigns.CABAL_NULL:
  8841. -                               filename = (getHtmlPath(npcId, val)); // do the default!
  8842. -                               break;
  8843. -                   }
  8844. -               }
  8845. -               else
  8846. -                       filename = (getHtmlPath(npcId, val)); // do the default!
  8847. -                }
  8848. -                else
  8849. -                {
  8850. -                    if (playerCabal == SevenSigns.CABAL_NULL)
  8851. -                        filename += "cata_no.htm";
  8852. -                    else
  8853. -                        filename = (getHtmlPath(npcId, val)); // do the default!    
  8854. -                }
  8855. -                break;
  8856. -            case 8111: // Gatekeeper Spirit (Disciples)
  8857. -               if (playerCabal == sealAvariceOwner && playerCabal == compWinner)
  8858. -               {
  8859. -                   switch (sealAvariceOwner)
  8860. -                   {
  8861. -                       case SevenSigns.CABAL_DAWN:
  8862. -                           filename += "spirit_dawn.htm";
  8863. -                           break;
  8864. -                       case SevenSigns.CABAL_DUSK:
  8865. -                           filename += "spirit_dusk.htm";
  8866. -                           break;
  8867. -                       case SevenSigns.CABAL_NULL:
  8868. -                           filename += "spirit_null.htm";
  8869. -                           break;
  8870. -                   }
  8871. -               }
  8872. -               else
  8873. -               {
  8874. -                   filename += "spirit_null.htm";
  8875. -               }
  8876. -                break;
  8877. -            case 8112: // Gatekeeper Spirit (Disciples)
  8878. -               filename += "spirit_exit.htm";
  8879. -               break;
  8880. -            case 8127: //
  8881. -            case 8128: //
  8882. -            case 8129: // Dawn Festival Guides
  8883. -            case 8130: //
  8884. -            case 8131: //
  8885. -                filename += "festival/dawn_guide.htm";
  8886. -                break;
  8887. -            case 8137: //
  8888. -            case 8138: //
  8889. -            case 8139: // Dusk Festival Guides
  8890. -            case 8140: //
  8891. -            case 8141: //
  8892. -                filename += "festival/dusk_guide.htm";
  8893. -                break;
  8894. -            case 8092: // Black Marketeer of Mammon
  8895. -               filename += "blkmrkt_1.htm";
  8896. -               break;
  8897. -            case 8113: // Merchant of Mammon
  8898. -                switch (compWinner)
  8899. -                {
  8900. -                    case SevenSigns.CABAL_DAWN:
  8901. -                        if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
  8902. -                        {
  8903. -                            player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  8904. -                            player.sendPacket(new ActionFailed());
  8905. -                            return;
  8906. -                        }
  8907. -                        break;
  8908. -                    case SevenSigns.CABAL_DUSK:
  8909. -                        if (playerCabal != compWinner || playerCabal != sealAvariceOwner)
  8910. -                        {
  8911. -                            player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  8912. -                            player.sendPacket(new ActionFailed());
  8913. -                            return;
  8914. -                        }
  8915. -                        break;
  8916. -                }
  8917. -               filename += "mammmerch_1.htm";
  8918. -               break;
  8919. -            case 8126: // Blacksmith of Mammon
  8920. -                switch (compWinner)
  8921. -                {
  8922. -                    case SevenSigns.CABAL_DAWN:
  8923. -                        if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
  8924. -                        {
  8925. -                            player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  8926. -                            player.sendPacket(new ActionFailed());
  8927. -                            return;
  8928. -                        }
  8929. -                        break;
  8930. -                    case SevenSigns.CABAL_DUSK:
  8931. -                        if (playerCabal != compWinner || playerCabal != sealGnosisOwner)
  8932. -                        {
  8933. -                            player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  8934. -                            player.sendPacket(new ActionFailed());
  8935. -                            return;
  8936. -                        }
  8937. -                        break;
  8938. -                }
  8939. -               filename += "mammblack_1.htm";
  8940. -               break;
  8941. -            case 8132:
  8942. -            case 8133:
  8943. -            case 8134:
  8944. -            case 8135:
  8945. -            case 8136:  // Festival Witches
  8946. -            case 8142:
  8947. -            case 8143:
  8948. -            case 8144:
  8949. -            case 8145:
  8950. -            case 8146:            
  8951. -                filename += "festival/festival_witch.htm";
  8952. -                break;
  8953. -            case 8688:
  8954. -                if (player.isNoble())
  8955. -                    filename = Olympiad.OLYMPIAD_HTML_FILE + "noble_main.htm";
  8956. -                else
  8957. -                    filename = (getHtmlPath(npcId, val));
  8958. -                break;
  8959. -            case 8690:
  8960. -            case 8769:
  8961. -            case 8770:
  8962. -            case 8771:
  8963. -            case 8772:
  8964. -                if (player.isHero())
  8965. -                    filename = Olympiad.OLYMPIAD_HTML_FILE + "hero_main.htm";
  8966. -                else
  8967. -                    filename = (getHtmlPath(npcId, val));
  8968. -                break;
  8969. -            default:
  8970. -                if ((npcId >= 8093 && npcId <= 8094) ||
  8971. -                        (npcId >= 8172 && npcId <= 8201) ||
  8972. -                        (npcId >= 8239 && npcId <= 8254))
  8973. -                    return;
  8974. -            // Get the text of the selected HTML file in function of the npcId and of the page number
  8975. -            filename = (getHtmlPath(npcId, val));
  8976. -            break;
  8977. -        }
  8978. -        
  8979. -        // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  8980. -        NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  8981. -        html.setFile(filename);
  8982. -        
  8983. -        //String word = "npc-"+npcId+(val>0 ? "-"+val : "" )+"-dialog-append";
  8984. -        
  8985. -        if (this instanceof L2MerchantInstance)
  8986. -            if (Config.LIST_PET_RENT_NPC.contains(npcId))
  8987. -                html.replace("_Quest", "_RentPet\">Rent Pet</a><br><a action=\"bypass -h npc_%objectId%_Quest");
  8988. -        
  8989. -        html.replace("%objectId%", String.valueOf(getObjectId()));
  8990. -        html.replace("%festivalMins%", SevenSignsFestival.getInstance().getTimeToNextFestivalStr());        
  8991. -        player.sendPacket(html);
  8992. -        
  8993. -        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  8994. -        player.sendPacket( new ActionFailed());
  8995. -    }
  8996. -    
  8997. -    /**
  8998. -     * Open a chat window on client with the text specified by the given file name and path,<BR>
  8999. -     * relative to the datapack root.
  9000. -     * <BR><BR>
  9001. -     * Added by Tempy
  9002. -     * @param player The L2PcInstance that talk with the L2NpcInstance
  9003. -     * @param filename The filename that contains the text to send
  9004. -     *  
  9005. -     */
  9006. -    public void showChatWindow(L2PcInstance player, String filename)
  9007. -    {
  9008. -        // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  9009. -        NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  9010. -        html.setFile(filename);
  9011. -        html.replace("%objectId%",String.valueOf(getObjectId()));
  9012. -        player.sendPacket(html);
  9013. -        
  9014. -        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  9015. -        player.sendPacket( new ActionFailed() );
  9016. -    }
  9017. -    
  9018. -    /**
  9019. -     * Return the Exp Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_XP).<BR><BR>
  9020. -     */
  9021. -    public int getExpReward()
  9022. -    {
  9023. -        double rateXp = getStat().calcStat(Stats.MAX_HP , 1, this, null);
  9024. -        return (int)(getTemplate().rewardExp * rateXp * Config.RATE_XP);
  9025. -    }
  9026. -    
  9027. -    /**
  9028. -     * Return the SP Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_SP).<BR><BR>
  9029. -     */
  9030. -    public int getSpReward()
  9031. -    {
  9032. -        double rateSp = getStat().calcStat(Stats.MAX_HP , 1, this, null);
  9033. -        return (int)(getTemplate().rewardSp * rateSp * Config.RATE_SP);
  9034. -    }
  9035. -    
  9036. -    /**
  9037. -     * Kill the L2NpcInstance (the corpse disappeared after 7 seconds).<BR><BR>
  9038. -     *
  9039. -     * <B><U> Actions</U> :</B><BR><BR>
  9040. -     * <li>Create a DecayTask to remove the corpse of the L2NpcInstance after 7 seconds </li>
  9041. -     * <li>Set target to null and cancel Attack or Cast </li>
  9042. -     * <li>Stop movement </li>
  9043. -     * <li>Stop HP/MP/CP Regeneration task </li>
  9044. -     * <li>Stop all active skills effects in progress on the L2Character </li>
  9045. -     * <li>Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform </li>
  9046. -     * <li>Notify L2Character AI </li><BR><BR>
  9047. -     *
  9048. -     * <B><U> Overriden in </U> :</B><BR><BR>
  9049. -     * <li> L2Attackable </li><BR><BR>
  9050. -     *
  9051. -     * @param killer The L2Character who killed it
  9052. -     *
  9053. -     */
  9054. -    public boolean doDie(L2Character killer)
  9055. -    {
  9056. -        if (!super.doDie(killer))
  9057. -            return false;
  9058. -
  9059. -        _currentCollisionHeight = getTemplate().collisionHeight;
  9060. -        _currentCollisionRadius = getTemplate().collisionRadius;
  9061. -        DecayTaskManager.getInstance().addDecayTask(this);
  9062. -        return true;
  9063. -    }
  9064. -
  9065. -    /**
  9066. -     * Set the spawn of the L2NpcInstance.<BR><BR>
  9067. -     *
  9068. -     * @param spawn The L2Spawn that manage the L2NpcInstance
  9069. -     *
  9070. -     */
  9071. -    public void setSpawn(L2Spawn spawn)
  9072. -    {
  9073. -        _spawn = spawn;
  9074. -    }
  9075. -
  9076. -    @Override
  9077. -    public void onSpawn()
  9078. -    {
  9079. -        super.onSpawn();
  9080. -    }
  9081. -
  9082. -    /**
  9083. -     * Remove the L2NpcInstance from the world and update its spawn object (for a complete removal use the deleteMe method).<BR><BR>
  9084. -     *
  9085. -     * <B><U> Actions</U> :</B><BR><BR>
  9086. -     * <li>Remove the L2NpcInstance from the world when the decay task is launched </li>
  9087. -     * <li>Decrease its spawn counter </li>
  9088. -     * <li>Manage Siege task (killFlag, killCT) </li><BR><BR>
  9089. -     *
  9090. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
  9091. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR><BR>
  9092. -     *
  9093. -     */
  9094. -    public void onDecay()
  9095. -    {
  9096. -        if (isDecayed()) return;
  9097. -        setDecayed(true);
  9098. -
  9099. -        // Manage Life Control Tower
  9100. -        if (this instanceof L2ControlTowerInstance)
  9101. -            ((L2ControlTowerInstance)this).onDeath();
  9102. -        
  9103. -        // Remove the L2NpcInstance from the world when the decay task is launched
  9104. -        super.onDecay();
  9105. -        
  9106. -        // Decrease its spawn counter
  9107. -        if (_spawn != null)
  9108. -            _spawn.decreaseCount(this);
  9109. -    }
  9110. -    
  9111. -    /**
  9112. -     * Remove PROPERLY the L2NpcInstance from the world.<BR><BR>
  9113. -     *
  9114. -     * <B><U> Actions</U> :</B><BR><BR>
  9115. -     * <li>Remove the L2NpcInstance from the world and update its spawn object </li>
  9116. -     * <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2NpcInstance then cancel Attak or Cast and notify AI </li>
  9117. -     * <li>Remove L2Object object from _allObjects of L2World </li><BR><BR>
  9118. -     *
  9119. -     * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR><BR>
  9120. -     *
  9121. -     */
  9122. -    public void deleteMe()
  9123. -    {
  9124. -        L2WorldRegion oldRegion = getWorldRegion();
  9125. -        
  9126. -        try
  9127. -        {
  9128. -            decayMe();
  9129. -        }
  9130. -        catch (Throwable t)
  9131. -        {
  9132. -            _log.severe("deletedMe(): " + t);
  9133. -        }
  9134. -
  9135. -
  9136. -        if (oldRegion != null)
  9137. -            oldRegion.removeFromZones(this);
  9138. -
  9139. -        // Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI
  9140. -        try { getKnownList().removeAllKnownObjects(); } catch (Throwable t) {_log.severe("deletedMe(): " + t); }
  9141. -        
  9142. -        // Remove L2Object object from _allObjects of L2World
  9143. -        L2World.getInstance().removeObject(this);
  9144. -    }
  9145. -    
  9146. -    /**
  9147. -     * Return the L2Spawn object that manage this L2NpcInstance.<BR><BR>
  9148. -     */
  9149. -    public L2Spawn getSpawn()
  9150. -    {
  9151. -        return _spawn;
  9152. -    }
  9153. -    
  9154. -    public String toString()
  9155. -    {
  9156. -        return getTemplate().name;
  9157. -    }
  9158. -
  9159. -    public boolean isDecayed()
  9160. -    {
  9161. -        return _isDecayed;
  9162. -    }
  9163. -
  9164. -    public void setDecayed(boolean decayed)
  9165. -    {
  9166. -        _isDecayed = decayed;
  9167. -    }
  9168. -
  9169. -    public void endDecayTask()
  9170. -    {
  9171. -        if (!isDecayed())
  9172. -        {
  9173. -
  9174. -            DecayTaskManager.getInstance().cancelDecayTask(this);
  9175. -            onDecay();
  9176. -        }
  9177. -    }
  9178. -
  9179. -
  9180. -    public void setCollisionHeight(int height)
  9181. -    {
  9182. -        _currentCollisionHeight = height;
  9183. -    }
  9184. -
  9185. -    public void setCollisionRadius(int radius)
  9186. -    {
  9187. -        _currentCollisionRadius = radius;
  9188. -    }
  9189. -
  9190. -    public int getCollisionHeight()
  9191. -    {
  9192. -        return _currentCollisionHeight;
  9193. -    }
  9194. -
  9195. -    public int getCollisionRadius()
  9196. -    {
  9197. -        return _currentCollisionRadius;
  9198. -    }
  9199. +          
  9200. +           filename = (getHtmlPath(npcId, 3));
  9201. +           html.setFile(filename);
  9202. +       }
  9203. +       else if (val == 23) // 23 - current lottery jackpot
  9204. +       {
  9205. +           filename = (getHtmlPath(npcId, 3));
  9206. +           html.setFile(filename);
  9207. +       }
  9208. +       else if (val == 24) // 24 - Previous winning numbers/Prize claim
  9209. +       {
  9210. +           filename = (getHtmlPath(npcId, 4));
  9211. +           html.setFile(filename);
  9212. +          
  9213. +           int lotonumber = Lottery.getInstance().getId();
  9214. +           String message = "";
  9215. +           for (L2ItemInstance item : player.getInventory().getItems())
  9216. +           {
  9217. +               if (item == null)
  9218. +               {
  9219. +                   continue;
  9220. +               }
  9221. +               if ((item.getItemId() == 4442) && (item.getCustomType1() < lotonumber))
  9222. +               {
  9223. +                   message = message + "<a action=\"bypass -h npc_%objectId%_Loto " + item.getObjectId() + "\">" + item.getCustomType1() + " Event Number ";
  9224. +                   int[] numbers = Lottery.getInstance().decodeNumbers(item.getEnchantLevel(), item.getCustomType2());
  9225. +                   for (int i = 0; i < 5; i++)
  9226. +                   {
  9227. +                       message += numbers[i] + " ";
  9228. +                   }
  9229. +                   int[] check = Lottery.getInstance().checkTicket(item);
  9230. +                   if (check[0] > 0)
  9231. +                   {
  9232. +                       switch (check[0])
  9233. +                       {
  9234. +                           case 1:
  9235. +                               message += "- 1st Prize";
  9236. +                               break;
  9237. +                           case 2:
  9238. +                               message += "- 2nd Prize";
  9239. +                               break;
  9240. +                           case 3:
  9241. +                               message += "- 3th Prize";
  9242. +                               break;
  9243. +                           case 4:
  9244. +                               message += "- 4th Prize";
  9245. +                               break;
  9246. +                       }
  9247. +                       message += " " + check[1] + "a.";
  9248. +                   }
  9249. +                   message += "</a><br>";
  9250. +               }
  9251. +           }
  9252. +           if (message == "")
  9253. +           {
  9254. +               message += "There is no winning lottery ticket...<br>";
  9255. +           }
  9256. +           html.replace("%result%", message);
  9257. +       }
  9258. +       else if (val > 24) // >24 - check lottery ticket by item object id
  9259. +       {
  9260. +           int lotonumber = Lottery.getInstance().getId();
  9261. +           L2ItemInstance item = player.getInventory().getItemByObjectId(val);
  9262. +           if ((item == null) || (item.getItemId() != 4442) || (item.getCustomType1() >= lotonumber))
  9263. +           {
  9264. +               return;
  9265. +           }
  9266. +           int[] check = Lottery.getInstance().checkTicket(item);
  9267. +          
  9268. +           sm = new SystemMessage(SystemMessage.DISSAPEARED_ITEM);
  9269. +           sm.addItemName(4442);
  9270. +           player.sendPacket(sm);
  9271. +          
  9272. +           int adena = check[1];
  9273. +           if (adena > 0)
  9274. +           {
  9275. +               player.addAdena("Loto", adena, this, true);
  9276. +           }
  9277. +           player.destroyItem("Loto", item, this, false);
  9278. +           return;
  9279. +       }
  9280. +       html.replace("%objectId%", String.valueOf(getObjectId()));
  9281. +       html.replace("%race%", "" + Lottery.getInstance().getId());
  9282. +       html.replace("%adena%", "" + Lottery.getInstance().getPrize());
  9283. +       html.replace("%ticket_price%", "" + Config.ALT_LOTTERY_TICKET_PRICE);
  9284. +       html.replace("%prize5%", "" + (Config.ALT_LOTTERY_5_NUMBER_RATE * 100));
  9285. +       html.replace("%prize4%", "" + (Config.ALT_LOTTERY_4_NUMBER_RATE * 100));
  9286. +       html.replace("%prize3%", "" + (Config.ALT_LOTTERY_3_NUMBER_RATE * 100));
  9287. +       html.replace("%prize2%", "" + Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE);
  9288. +       html.replace("%enddate%", "" + DateFormat.getDateInstance().format(Lottery.getInstance().getEndDate()));
  9289. +       player.sendPacket(html);
  9290. +      
  9291. +       // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  9292. +       player.sendPacket(new ActionFailed());
  9293. +   }
  9294. +  
  9295. +   public void makeCPRecovery(L2PcInstance player)
  9296. +   {
  9297. +       if ((getNpcId() != 8225) && (getNpcId() != 8226))
  9298. +       {
  9299. +           return;
  9300. +       }
  9301. +      
  9302. +       int neededmoney = 100;
  9303. +      
  9304. +       if (!player.reduceAdena("RestoreCP", neededmoney, player.getLastFolkNPC(), true))
  9305. +       {
  9306. +           return;
  9307. +       }
  9308. +      
  9309. +       L2Skill skill = SkillTable.getInstance().getInfo(4380, 1);
  9310. +       if (skill != null)
  9311. +       {
  9312. +           setTarget(player);
  9313. +           doCast(skill);
  9314. +       }
  9315. +       player.sendPacket(new ActionFailed());
  9316. +   }
  9317. +  
  9318. +   /**
  9319. +    * Add Newbie helper buffs to L2Player according to its level.<BR>
  9320. +    * <BR>
  9321. +    * <B><U> Actions</U> :</B><BR>
  9322. +    * <BR>
  9323. +    * <li>Get the range level in wich player must be to obtain buff</li> <li>If player level is out of range, display a message and return</li> <li>According to player level cast buff</li><BR>
  9324. +    * <BR>
  9325. +    * <FONT COLOR=#FF0000><B> Newbie Helper Buff list is define in sql table helper_buff_list</B></FONT><BR>
  9326. +    * <BR>
  9327. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  9328. +    */
  9329. +   public void makeSupportMagic(L2PcInstance player)
  9330. +   {
  9331. +       int player_level = player.getLevel();
  9332. +       int lowestLevel;
  9333. +       int higestLevel;
  9334. +       L2Skill skill;
  9335. +      
  9336. +       // Select the player
  9337. +       setTarget(player);
  9338. +      
  9339. +       // Calculate the min and max level between wich the player must be to obtain buff
  9340. +       if (player.isMageClass())
  9341. +       {
  9342. +           lowestLevel = HelperBuffTable.getInstance().getMagicClassLowestLevel();
  9343. +           higestLevel = HelperBuffTable.getInstance().getMagicClassHighestLevel();
  9344. +       }
  9345. +       else
  9346. +       {
  9347. +           lowestLevel = HelperBuffTable.getInstance().getPhysicClassLowestLevel();
  9348. +           higestLevel = HelperBuffTable.getInstance().getPhysicClassHighestLevel();
  9349. +       }
  9350. +      
  9351. +       // If the player is too high level, display a message and return
  9352. +       if (player_level > higestLevel)
  9353. +       {
  9354. +           String content = "<html><body>Newbie Guide:<br>Only a <font color=\"LEVEL\">novice character of level " + higestLevel + " or less</font> can receive my support magic.<br>Your novice character is the first one that you created and raised in this world.</body></html>";
  9355. +           insertObjectIdAndShowChatWindow(player, content);
  9356. +           return;
  9357. +       }
  9358. +      
  9359. +       // If the player is too low level, display a message and return
  9360. +       if (player_level < lowestLevel)
  9361. +       {
  9362. +           String content = "<html><body>Come back here when you have reached level " + lowestLevel + ". I will give you support magic then.</body></html>";
  9363. +           insertObjectIdAndShowChatWindow(player, content);
  9364. +           return;
  9365. +       }
  9366. +      
  9367. +       // Go through the Helper Buff list define in sql table helper_buff_list and cast skill
  9368. +       for (L2HelperBuff helperBuffItem : HelperBuffTable.getInstance().getHelperBuffTable())
  9369. +       {
  9370. +           if (helperBuffItem.isMagicClassBuff() == player.isMageClass())
  9371. +           {
  9372. +               if ((player_level >= helperBuffItem.getLowerLevel()) && (player_level <= helperBuffItem.getUpperLevel()))
  9373. +               {
  9374. +                   skill = SkillTable.getInstance().getInfo(helperBuffItem.getSkillID(), helperBuffItem.getSkillLevel());
  9375. +                   if (skill.getSkillType() == SkillType.SUMMON)
  9376. +                   {
  9377. +                       player.doCast(skill);
  9378. +                   }
  9379. +                   else
  9380. +                   {
  9381. +                       doCast(skill);
  9382. +                   }
  9383. +               }
  9384. +           }
  9385. +       }
  9386. +      
  9387. +   }
  9388. +  
  9389. +   public void showChatWindow(L2PcInstance player)
  9390. +   {
  9391. +       showChatWindow(player, 0);
  9392. +   }
  9393. +  
  9394. +   /**
  9395. +    * Open a chat window on client with the text of the L2NpcInstance.<BR>
  9396. +    * <BR>
  9397. +    * <B><U> Actions</U> :</B><BR>
  9398. +    * <BR>
  9399. +    * <li>Get the text of the selected HTML file in function of the npcId and of the page number</li> <li>Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance</li> <li>Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the
  9400. +    * client wait another packet</li><BR>
  9401. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  9402. +    * @param val The number of the page of the L2NpcInstance to display
  9403. +    */
  9404. +   public void showChatWindow(L2PcInstance player, int val)
  9405. +   {
  9406. +       if ((getTemplate().type == "L2Auctioneer") && (val == 0))
  9407. +       {
  9408. +           return;
  9409. +       }
  9410. +       int npcId = getTemplate().npcId;
  9411. +      
  9412. +       /* For use with Seven Signs implementation */
  9413. +       String filename = SevenSigns.SEVEN_SIGNS_HTML_PATH;
  9414. +       int sealAvariceOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_AVARICE);
  9415. +       int sealGnosisOwner = SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_GNOSIS);
  9416. +       int playerCabal = SevenSigns.getInstance().getPlayerCabal(player);
  9417. +       boolean isSealValidationPeriod = SevenSigns.getInstance().isSealValidationPeriod();
  9418. +       int compWinner = SevenSigns.getInstance().getCabalHighestScore();
  9419. +      
  9420. +       switch (npcId)
  9421. +       {
  9422. +           case 8078:
  9423. +           case 8079:
  9424. +           case 8080:
  9425. +           case 8081:
  9426. +           case 8082: // Dawn Priests
  9427. +           case 8083:
  9428. +           case 8084:
  9429. +           case 8168:
  9430. +           case 8692:
  9431. +           case 8694:
  9432. +               switch (playerCabal)
  9433. +               {
  9434. +                   case SevenSigns.CABAL_DAWN:
  9435. +                       if (isSealValidationPeriod)
  9436. +                       {
  9437. +                           if (compWinner == SevenSigns.CABAL_DAWN)
  9438. +                           {
  9439. +                               if (compWinner != sealGnosisOwner)
  9440. +                               {
  9441. +                                   filename += "dawn_priest_2c.htm";
  9442. +                               }
  9443. +                               else
  9444. +                               {
  9445. +                                   filename += "dawn_priest_2a.htm";
  9446. +                               }
  9447. +                           }
  9448. +                           else
  9449. +                           {
  9450. +                               filename += "dawn_priest_2b.htm";
  9451. +                           }
  9452. +                       }
  9453. +                       else
  9454. +                       {
  9455. +                           filename += "dawn_priest_1b.htm";
  9456. +                       }
  9457. +                       break;
  9458. +                   case SevenSigns.CABAL_DUSK:
  9459. +                       if (isSealValidationPeriod)
  9460. +                       {
  9461. +                           filename += "dawn_priest_3b.htm";
  9462. +                       }
  9463. +                       else
  9464. +                       {
  9465. +                           filename += "dawn_priest_3a.htm";
  9466. +                       }
  9467. +                       break;
  9468. +                   default:
  9469. +                       if (isSealValidationPeriod)
  9470. +                       {
  9471. +                           if (compWinner == SevenSigns.CABAL_DAWN)
  9472. +                           {
  9473. +                               filename += "dawn_priest_4.htm";
  9474. +                           }
  9475. +                           else
  9476. +                           {
  9477. +                               filename += "dawn_priest_2b.htm";
  9478. +                           }
  9479. +                       }
  9480. +                       else
  9481. +                       {
  9482. +                           filename += "dawn_priest_1a.htm";
  9483. +                       }
  9484. +                       break;
  9485. +               }
  9486. +               break;
  9487. +           case 8085:
  9488. +           case 8086:
  9489. +           case 8087:
  9490. +           case 8088: // Dusk Priest
  9491. +           case 8089:
  9492. +           case 8090:
  9493. +           case 8091:
  9494. +           case 8169:
  9495. +           case 8693:
  9496. +           case 8695:
  9497. +               switch (playerCabal)
  9498. +               {
  9499. +                   case SevenSigns.CABAL_DUSK:
  9500. +                       if (isSealValidationPeriod)
  9501. +                       {
  9502. +                           if (compWinner == SevenSigns.CABAL_DUSK)
  9503. +                           {
  9504. +                               if (compWinner != sealGnosisOwner)
  9505. +                               {
  9506. +                                   filename += "dusk_priest_2c.htm";
  9507. +                               }
  9508. +                               else
  9509. +                               {
  9510. +                                   filename += "dusk_priest_2a.htm";
  9511. +                               }
  9512. +                           }
  9513. +                           else
  9514. +                           {
  9515. +                               filename += "dusk_priest_2b.htm";
  9516. +                           }
  9517. +                       }
  9518. +                       else
  9519. +                       {
  9520. +                           filename += "dusk_priest_1b.htm";
  9521. +                       }
  9522. +                       break;
  9523. +                   case SevenSigns.CABAL_DAWN:
  9524. +                       if (isSealValidationPeriod)
  9525. +                       {
  9526. +                           filename += "dusk_priest_3b.htm";
  9527. +                       }
  9528. +                       else
  9529. +                       {
  9530. +                           filename += "dusk_priest_3a.htm";
  9531. +                       }
  9532. +                       break;
  9533. +                   default:
  9534. +                       if (isSealValidationPeriod)
  9535. +                       {
  9536. +                           if (compWinner == SevenSigns.CABAL_DUSK)
  9537. +                           {
  9538. +                               filename += "dusk_priest_4.htm";
  9539. +                           }
  9540. +                           else
  9541. +                           {
  9542. +                               filename += "dusk_priest_2b.htm";
  9543. +                           }
  9544. +                       }
  9545. +                       else
  9546. +                       {
  9547. +                           filename += "dusk_priest_1a.htm";
  9548. +                       }
  9549. +                       break;
  9550. +               }
  9551. +               break;
  9552. +           case 8095: //
  9553. +           case 8096: //
  9554. +           case 8097: //
  9555. +           case 8098: // Enter Necropolises
  9556. +           case 8099: //
  9557. +           case 8100: //
  9558. +           case 8101: //
  9559. +           case 8102: //
  9560. +               if (isSealValidationPeriod)
  9561. +               {
  9562. +                   if ((playerCabal != compWinner) || (sealAvariceOwner != compWinner))
  9563. +                   {
  9564. +                       switch (compWinner)
  9565. +                       {
  9566. +                           case SevenSigns.CABAL_DAWN:
  9567. +                               player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  9568. +                               filename += "necro_no.htm";
  9569. +                               break;
  9570. +                           case SevenSigns.CABAL_DUSK:
  9571. +                               player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  9572. +                               filename += "necro_no.htm";
  9573. +                               break;
  9574. +                           case SevenSigns.CABAL_NULL:
  9575. +                               filename = (getHtmlPath(npcId, val)); // do the default!
  9576. +                               break;
  9577. +                       }
  9578. +                   }
  9579. +                   else
  9580. +                   {
  9581. +                       filename = (getHtmlPath(npcId, val)); // do the default!
  9582. +                   }
  9583. +               }
  9584. +               else
  9585. +               {
  9586. +                   if (playerCabal == SevenSigns.CABAL_NULL)
  9587. +                   {
  9588. +                       filename += "necro_no.htm";
  9589. +                   }
  9590. +                   else
  9591. +                   {
  9592. +                       filename = (getHtmlPath(npcId, val)); // do the default!
  9593. +                   }
  9594. +               }
  9595. +               break;
  9596. +           case 8114: //
  9597. +           case 8115: //
  9598. +           case 8116: // Enter Catacombs
  9599. +           case 8117: //
  9600. +           case 8118: //
  9601. +           case 8119: //
  9602. +               if (isSealValidationPeriod)
  9603. +               {
  9604. +                   if ((playerCabal != compWinner) || (sealGnosisOwner != compWinner))
  9605. +                   {
  9606. +                       switch (compWinner)
  9607. +                       {
  9608. +                           case SevenSigns.CABAL_DAWN:
  9609. +                               player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  9610. +                               filename += "cata_no.htm";
  9611. +                               break;
  9612. +                           case SevenSigns.CABAL_DUSK:
  9613. +                               player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  9614. +                               filename += "cata_no.htm";
  9615. +                               break;
  9616. +                           case SevenSigns.CABAL_NULL:
  9617. +                               filename = (getHtmlPath(npcId, val)); // do the default!
  9618. +                               break;
  9619. +                       }
  9620. +                   }
  9621. +                   else
  9622. +                   {
  9623. +                       filename = (getHtmlPath(npcId, val)); // do the default!
  9624. +                   }
  9625. +               }
  9626. +               else
  9627. +               {
  9628. +                   if (playerCabal == SevenSigns.CABAL_NULL)
  9629. +                   {
  9630. +                       filename += "cata_no.htm";
  9631. +                   }
  9632. +                   else
  9633. +                   {
  9634. +                       filename = (getHtmlPath(npcId, val)); // do the default!
  9635. +                   }
  9636. +               }
  9637. +               break;
  9638. +           case 8111: // Gatekeeper Spirit (Disciples)
  9639. +               if ((playerCabal == sealAvariceOwner) && (playerCabal == compWinner))
  9640. +               {
  9641. +                   switch (sealAvariceOwner)
  9642. +                   {
  9643. +                       case SevenSigns.CABAL_DAWN:
  9644. +                           filename += "spirit_dawn.htm";
  9645. +                           break;
  9646. +                       case SevenSigns.CABAL_DUSK:
  9647. +                           filename += "spirit_dusk.htm";
  9648. +                           break;
  9649. +                       case SevenSigns.CABAL_NULL:
  9650. +                           filename += "spirit_null.htm";
  9651. +                           break;
  9652. +                   }
  9653. +               }
  9654. +               else
  9655. +               {
  9656. +                   filename += "spirit_null.htm";
  9657. +               }
  9658. +               break;
  9659. +           case 8112: // Gatekeeper Spirit (Disciples)
  9660. +               filename += "spirit_exit.htm";
  9661. +               break;
  9662. +           case 8127: //
  9663. +           case 8128: //
  9664. +           case 8129: // Dawn Festival Guides
  9665. +           case 8130: //
  9666. +           case 8131: //
  9667. +               filename += "festival/dawn_guide.htm";
  9668. +               break;
  9669. +           case 8137: //
  9670. +           case 8138: //
  9671. +           case 8139: // Dusk Festival Guides
  9672. +           case 8140: //
  9673. +           case 8141: //
  9674. +               filename += "festival/dusk_guide.htm";
  9675. +               break;
  9676. +           case 8092: // Black Marketeer of Mammon
  9677. +               filename += "blkmrkt_1.htm";
  9678. +               break;
  9679. +           case 8113: // Merchant of Mammon
  9680. +               switch (compWinner)
  9681. +               {
  9682. +                   case SevenSigns.CABAL_DAWN:
  9683. +                       if ((playerCabal != compWinner) || (playerCabal != sealAvariceOwner))
  9684. +                       {
  9685. +                           player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  9686. +                           player.sendPacket(new ActionFailed());
  9687. +                           return;
  9688. +                       }
  9689. +                       break;
  9690. +                   case SevenSigns.CABAL_DUSK:
  9691. +                       if ((playerCabal != compWinner) || (playerCabal != sealAvariceOwner))
  9692. +                       {
  9693. +                           player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  9694. +                           player.sendPacket(new ActionFailed());
  9695. +                           return;
  9696. +                       }
  9697. +                       break;
  9698. +               }
  9699. +               filename += "mammmerch_1.htm";
  9700. +               break;
  9701. +           case 8126: // Blacksmith of Mammon
  9702. +               switch (compWinner)
  9703. +               {
  9704. +                   case SevenSigns.CABAL_DAWN:
  9705. +                       if ((playerCabal != compWinner) || (playerCabal != sealGnosisOwner))
  9706. +                       {
  9707. +                           player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DAWN));
  9708. +                           player.sendPacket(new ActionFailed());
  9709. +                           return;
  9710. +                       }
  9711. +                       break;
  9712. +                   case SevenSigns.CABAL_DUSK:
  9713. +                       if ((playerCabal != compWinner) || (playerCabal != sealGnosisOwner))
  9714. +                       {
  9715. +                           player.sendPacket(new SystemMessage(SystemMessage.CAN_BE_USED_BY_DUSK));
  9716. +                           player.sendPacket(new ActionFailed());
  9717. +                           return;
  9718. +                       }
  9719. +                       break;
  9720. +               }
  9721. +               filename += "mammblack_1.htm";
  9722. +               break;
  9723. +           case 8132:
  9724. +           case 8133:
  9725. +           case 8134:
  9726. +           case 8135:
  9727. +           case 8136: // Festival Witches
  9728. +           case 8142:
  9729. +           case 8143:
  9730. +           case 8144:
  9731. +           case 8145:
  9732. +           case 8146:
  9733. +               filename += "festival/festival_witch.htm";
  9734. +               break;
  9735. +           case 8688:
  9736. +               if (player.isNoble())
  9737. +               {
  9738. +                   filename = Olympiad.OLYMPIAD_HTML_FILE + "noble_main.htm";
  9739. +               }
  9740. +               else
  9741. +               {
  9742. +                   filename = (getHtmlPath(npcId, val));
  9743. +               }
  9744. +               break;
  9745. +           case 8690:
  9746. +           case 8769:
  9747. +           case 8770:
  9748. +           case 8771:
  9749. +           case 8772:
  9750. +               if (player.isHero())
  9751. +               {
  9752. +                   filename = Olympiad.OLYMPIAD_HTML_FILE + "hero_main.htm";
  9753. +               }
  9754. +               else
  9755. +               {
  9756. +                   filename = (getHtmlPath(npcId, val));
  9757. +               }
  9758. +               break;
  9759. +           default:
  9760. +               if (((npcId >= 8093) && (npcId <= 8094)) || ((npcId >= 8172) && (npcId <= 8201)) || ((npcId >= 8239) && (npcId <= 8254)))
  9761. +               {
  9762. +                   return;
  9763. +               }
  9764. +               // Get the text of the selected HTML file in function of the npcId and of the page number
  9765. +               filename = (getHtmlPath(npcId, val));
  9766. +               break;
  9767. +       }
  9768. +      
  9769. +       // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  9770. +       NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  9771. +       html.setFile(filename);
  9772. +      
  9773. +       // String word = "npc-"+npcId+(val>0 ? "-"+val : "" )+"-dialog-append";
  9774. +      
  9775. +       if (this instanceof L2MerchantInstance)
  9776. +       {
  9777. +           if (Config.LIST_PET_RENT_NPC.contains(npcId))
  9778. +           {
  9779. +               html.replace("_Quest", "_RentPet\">Rent Pet</a><br><a action=\"bypass -h npc_%objectId%_Quest");
  9780. +           }
  9781. +       }
  9782. +      
  9783. +       html.replace("%objectId%", String.valueOf(getObjectId()));
  9784. +       html.replace("%festivalMins%", SevenSignsFestival.getInstance().getTimeToNextFestivalStr());
  9785. +       player.sendPacket(html);
  9786. +      
  9787. +       // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  9788. +       player.sendPacket(new ActionFailed());
  9789. +   }
  9790. +  
  9791. +   /**
  9792. +    * Open a chat window on client with the text specified by the given file name and path,<BR>
  9793. +    * relative to the datapack root. <BR>
  9794. +    * <BR>
  9795. +    * Added by Tempy
  9796. +    * @param player The L2PcInstance that talk with the L2NpcInstance
  9797. +    * @param filename The filename that contains the text to send
  9798. +    */
  9799. +   public void showChatWindow(L2PcInstance player, String filename)
  9800. +   {
  9801. +       // Send a Server->Client NpcHtmlMessage containing the text of the L2NpcInstance to the L2PcInstance
  9802. +       NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  9803. +       html.setFile(filename);
  9804. +       html.replace("%objectId%", String.valueOf(getObjectId()));
  9805. +       player.sendPacket(html);
  9806. +      
  9807. +       // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client wait another packet
  9808. +       player.sendPacket(new ActionFailed());
  9809. +   }
  9810. +  
  9811. +   /**
  9812. +    * Return the Exp Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_XP).<BR>
  9813. +    * <BR>
  9814. +    */
  9815. +   public int getExpReward()
  9816. +   {
  9817. +       double rateXp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
  9818. +       return (int) (getTemplate().rewardExp * rateXp * Config.RATE_XP);
  9819. +   }
  9820. +  
  9821. +   /**
  9822. +    * Return the SP Reward of this L2NpcInstance contained in the L2NpcTemplate (modified by RATE_SP).<BR>
  9823. +    * <BR>
  9824. +    */
  9825. +   public int getSpReward()
  9826. +   {
  9827. +       double rateSp = getStat().calcStat(Stats.MAX_HP, 1, this, null);
  9828. +       return (int) (getTemplate().rewardSp * rateSp * Config.RATE_SP);
  9829. +   }
  9830. +  
  9831. +   /**
  9832. +    * Kill the L2NpcInstance (the corpse disappeared after 7 seconds).<BR>
  9833. +    * <BR>
  9834. +    * <B><U> Actions</U> :</B><BR>
  9835. +    * <BR>
  9836. +    * <li>Create a DecayTask to remove the corpse of the L2NpcInstance after 7 seconds</li> <li>Set target to null and cancel Attack or Cast</li> <li>Stop movement</li> <li>Stop HP/MP/CP Regeneration task</li> <li>Stop all active skills effects in progress on the L2Character</li> <li>Send the
  9837. +    * Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform</li> <li>Notify L2Character AI</li><BR>
  9838. +    * <BR>
  9839. +    * <B><U> Overriden in </U> :</B><BR>
  9840. +    * <BR>
  9841. +    * <li>L2Attackable</li><BR>
  9842. +    * <BR>
  9843. +    * @param killer The L2Character who killed it
  9844. +    */
  9845. +   @Override
  9846. +   public boolean doDie(L2Character killer)
  9847. +   {
  9848. +       if (!super.doDie(killer))
  9849. +       {
  9850. +           return false;
  9851. +       }
  9852. +      
  9853. +       _currentCollisionHeight = getTemplate().collisionHeight;
  9854. +       _currentCollisionRadius = getTemplate().collisionRadius;
  9855. +       DecayTaskManager.getInstance().addDecayTask(this);
  9856. +       return true;
  9857. +   }
  9858. +  
  9859. +   /**
  9860. +    * Set the spawn of the L2NpcInstance.<BR>
  9861. +    * <BR>
  9862. +    * @param spawn The L2Spawn that manage the L2NpcInstance
  9863. +    */
  9864. +   public void setSpawn(L2Spawn spawn)
  9865. +   {
  9866. +       _spawn = spawn;
  9867. +   }
  9868. +  
  9869. +   @Override
  9870. +   public void onSpawn()
  9871. +   {
  9872. +       super.onSpawn();
  9873. +   }
  9874. +  
  9875. +   /**
  9876. +    * Remove the L2NpcInstance from the world and update its spawn object (for a complete removal use the deleteMe method).<BR>
  9877. +    * <BR>
  9878. +    * <B><U> Actions</U> :</B><BR>
  9879. +    * <BR>
  9880. +    * <li>Remove the L2NpcInstance from the world when the decay task is launched</li> <li>Decrease its spawn counter</li> <li>Manage Siege task (killFlag, killCT)</li><BR>
  9881. +    * <BR>
  9882. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
  9883. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR>
  9884. +    * <BR>
  9885. +    */
  9886. +   @Override
  9887. +   public void onDecay()
  9888. +   {
  9889. +       if (isDecayed())
  9890. +       {
  9891. +           return;
  9892. +       }
  9893. +       setDecayed(true);
  9894. +      
  9895. +       // Manage Life Control Tower
  9896. +       if (this instanceof L2ControlTowerInstance)
  9897. +       {
  9898. +           ((L2ControlTowerInstance) this).onDeath();
  9899. +       }
  9900. +      
  9901. +       // Remove the L2NpcInstance from the world when the decay task is launched
  9902. +       super.onDecay();
  9903. +      
  9904. +       // Decrease its spawn counter
  9905. +       if (_spawn != null)
  9906. +       {
  9907. +           _spawn.decreaseCount(this);
  9908. +       }
  9909. +   }
  9910. +  
  9911. +   /**
  9912. +    * Remove PROPERLY the L2NpcInstance from the world.<BR>
  9913. +    * <BR>
  9914. +    * <B><U> Actions</U> :</B><BR>
  9915. +    * <BR>
  9916. +    * <li>Remove the L2NpcInstance from the world and update its spawn object</li> <li>Remove all L2Object from _knownObjects and _knownPlayer of the L2NpcInstance then cancel Attak or Cast and notify AI</li> <li>Remove L2Object object from _allObjects of L2World</li><BR>
  9917. +    * <BR>
  9918. +    * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T SEND Server->Client packets to players</B></FONT><BR>
  9919. +    * <BR>
  9920. +    */
  9921. +   public void deleteMe()
  9922. +   {
  9923. +       L2WorldRegion oldRegion = getWorldRegion();
  9924. +      
  9925. +       try
  9926. +       {
  9927. +           decayMe();
  9928. +       }
  9929. +       catch (Throwable t)
  9930. +       {
  9931. +           _log.severe("deletedMe(): " + t);
  9932. +       }
  9933. +      
  9934. +       if (oldRegion != null)
  9935. +       {
  9936. +           oldRegion.removeFromZones(this);
  9937. +       }
  9938. +      
  9939. +       // Remove all L2Object from _knownObjects and _knownPlayer of the L2Character then cancel Attak or Cast and notify AI
  9940. +       try
  9941. +       {
  9942. +           getKnownList().removeAllKnownObjects();
  9943. +       }
  9944. +       catch (Throwable t)
  9945. +       {
  9946. +           _log.severe("deletedMe(): " + t);
  9947. +       }
  9948. +      
  9949. +       // Remove L2Object object from _allObjects of L2World
  9950. +       L2World.getInstance().removeObject(this);
  9951. +   }
  9952. +  
  9953. +   /**
  9954. +    * Return the L2Spawn object that manage this L2NpcInstance.<BR>
  9955. +    * <BR>
  9956. +    */
  9957. +   public L2Spawn getSpawn()
  9958. +   {
  9959. +       return _spawn;
  9960. +   }
  9961. +  
  9962. +   @Override
  9963. +   public String toString()
  9964. +   {
  9965. +       return getTemplate().name;
  9966. +   }
  9967. +  
  9968. +   public boolean isDecayed()
  9969. +   {
  9970. +       return _isDecayed;
  9971. +   }
  9972. +  
  9973. +   public void setDecayed(boolean decayed)
  9974. +   {
  9975. +       _isDecayed = decayed;
  9976. +   }
  9977. +  
  9978. +   public void endDecayTask()
  9979. +   {
  9980. +       if (!isDecayed())
  9981. +       {
  9982. +          
  9983. +           DecayTaskManager.getInstance().cancelDecayTask(this);
  9984. +           onDecay();
  9985. +       }
  9986. +   }
  9987. +  
  9988. +   public void setCollisionHeight(int height)
  9989. +   {
  9990. +       _currentCollisionHeight = height;
  9991. +   }
  9992. +  
  9993. +   public void setCollisionRadius(int radius)
  9994. +   {
  9995. +       _currentCollisionRadius = radius;
  9996. +   }
  9997. +  
  9998. +   public int getCollisionHeight()
  9999. +   {
  10000. +       return _currentCollisionHeight;
  10001. +   }
  10002. +  
  10003. +   public int getCollisionRadius()
  10004. +   {
  10005. +       return _currentCollisionRadius;
  10006. +   }
  10007.  }
  10008. \ No newline at end of file
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement