Advertisement
Guest User

Untitled

a guest
Sep 13th, 2015
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 123.04 KB | None | 0 0
  1. Index: java/net/sf/l2j/gameserver/skills/l2skills/L2SkillElemental.java
  2. ===================================================================
  3. --- java/net/sf/l2j/gameserver/skills/l2skills/L2SkillElemental.java (revision 1770)
  4. +++ java/net/sf/l2j/gameserver/skills/l2skills/L2SkillElemental.java (revision 1771)
  5. @@ -20,6 +20,7 @@
  6. import net.sf.l2j.gameserver.model.L2Object;
  7. import net.sf.l2j.gameserver.model.L2Skill;
  8. import net.sf.l2j.gameserver.model.L2Summon;
  9. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  10. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  11. import net.sf.l2j.gameserver.network.SystemMessageId;
  12. import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  13. @@ -95,6 +96,11 @@
  14. activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  15. }
  16. }
  17. + else if (activeChar instanceof L2NpcInstance)
  18. + {
  19. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  20. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  21. + }
  22.  
  23. for (int index = 0; index < targets.length; index++)
  24. {
  25. Index: java/net/sf/l2j/gameserver/skills/l2skills/L2SkillDrain.java
  26. ===================================================================
  27. --- java/net/sf/l2j/gameserver/skills/l2skills/L2SkillDrain.java (revision 1770)
  28. +++ java/net/sf/l2j/gameserver/skills/l2skills/L2SkillDrain.java (revision 1771)
  29. @@ -89,6 +89,12 @@
  30. activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  31. }
  32. }
  33. + else if (activeChar instanceof L2NpcInstance)
  34. + {
  35. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  36. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  37. + }
  38. +
  39.  
  40. boolean mcrit = Formulas.getInstance().calcMCrit(activeChar.getMCriticalHit(target, this));
  41. int damage = (int)Formulas.getInstance().calcMagicDam(
  42. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/Heal.java
  43. ===================================================================
  44. --- java/net/sf/l2j/gameserver/handler/skillhandlers/Heal.java (revision 1770)
  45. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/Heal.java (revision 1771)
  46. @@ -23,6 +23,7 @@
  47. import net.sf.l2j.gameserver.model.L2Summon;
  48. import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  49. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  50. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  51. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  52. import net.sf.l2j.gameserver.network.SystemMessageId;
  53. import net.sf.l2j.gameserver.serverpackets.StatusUpdate;
  54. @@ -125,6 +126,10 @@
  55. activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  56. }
  57. }
  58. + else if (activeChar instanceof L2NpcInstance)
  59. + {
  60. + if(((L2NpcInstance)activeChar).isUsingShot(false)) hp *= 1.5;
  61. + }
  62. }
  63.  
  64. //int cLev = activeChar.getLevel();
  65. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/Manadam.java
  66. ===================================================================
  67. --- java/net/sf/l2j/gameserver/handler/skillhandlers/Manadam.java (revision 1770)
  68. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/Manadam.java (revision 1771)
  69. @@ -1,128 +1,149 @@
  70. -/*
  71. - * This program is free software: you can redistribute it and/or modify it under
  72. - * the terms of the GNU General Public License as published by the Free Software
  73. - * Foundation, either version 3 of the License, or (at your option) any later
  74. - * version.
  75. - *
  76. - * This program is distributed in the hope that it will be useful, but WITHOUT
  77. - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  78. - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  79. - * details.
  80. - *
  81. - * You should have received a copy of the GNU General Public License along with
  82. - * this program. If not, see <http://www.gnu.org/licenses/>.
  83. - */
  84. -package net.sf.l2j.gameserver.handler.skillhandlers;
  85. -
  86. -import net.sf.l2j.gameserver.handler.ISkillHandler;
  87. -import net.sf.l2j.gameserver.model.L2Character;
  88. -import net.sf.l2j.gameserver.model.L2ItemInstance;
  89. -import net.sf.l2j.gameserver.model.L2Object;
  90. -import net.sf.l2j.gameserver.model.L2Skill;
  91. -import net.sf.l2j.gameserver.model.L2Summon;
  92. -import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  93. -import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  94. -import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  95. -import net.sf.l2j.gameserver.network.SystemMessageId;
  96. -import net.sf.l2j.gameserver.serverpackets.StatusUpdate;
  97. -import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  98. -import net.sf.l2j.gameserver.skills.Formulas;
  99. -
  100. -/**
  101. - * Class handling the Mana damage skill
  102. - *
  103. - * @author slyce
  104. - */
  105. -public class Manadam implements ISkillHandler
  106. -{
  107. -private static final SkillType[] SKILL_IDS = { SkillType.MANADAM };
  108. -
  109. -public void useSkill(@SuppressWarnings("unused")
  110. -L2Character activeChar, L2Skill skill, L2Object[] targets)
  111. -{
  112. - L2Character target = null;
  113. -
  114. - if (activeChar.isAlikeDead())
  115. - return;
  116. -
  117. - boolean ss = false;
  118. - boolean bss = false;
  119. -
  120. - L2ItemInstance weaponInst = activeChar.getActiveWeaponInstance();
  121. -
  122. - if (weaponInst != null)
  123. - {
  124. - if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
  125. - {
  126. - bss = true;
  127. - weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
  128. - } else if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_SPIRITSHOT)
  129. - {
  130. - ss = true;
  131. - weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
  132. - }
  133. - }
  134. - for (int index = 0; index < targets.length; index++)
  135. - {
  136. - target = (L2Character) targets[index];
  137. -
  138. - if (target.reflectSkill(skill))
  139. - target = activeChar;
  140. -
  141. - boolean acted = Formulas.getInstance().calcMagicAffected(activeChar, target, skill);
  142. - if (target.isInvul() || !acted)
  143. - {
  144. - activeChar.sendPacket(new SystemMessage(SystemMessageId.MISSED_TARGET));
  145. - } else
  146. - {
  147. - double damage = Formulas.getInstance().calcManaDam(activeChar, target, skill, ss, bss);
  148. -
  149. - double mp = (damage > target.getCurrentMp() ? target.getCurrentMp() : damage);
  150. - target.reduceCurrentMp(mp);
  151. - if (damage > 0)
  152. - {
  153. - if (target.isSleeping())
  154. - {
  155. - target.stopSleeping(null);
  156. - }
  157. - else if (target.isImmobileUntilAttacked())
  158. - {
  159. - target.stopImmobileUntilAttacked(null);
  160. - }
  161. - }
  162. -
  163. - StatusUpdate sump = new StatusUpdate(target.getObjectId());
  164. - sump.addAttribute(StatusUpdate.CUR_MP, (int) target.getCurrentMp());
  165. - // [L2J_JP EDIT START - TSL]
  166. - target.sendPacket(sump);
  167. - SystemMessage sm = new SystemMessage(SystemMessageId.S2_MP_HAS_BEEN_DRAINED_BY_S1);
  168. - if (activeChar instanceof L2NpcInstance)
  169. - {
  170. - int mobId = ((L2NpcInstance) activeChar).getNpcId();
  171. - sm.addNpcName(mobId);
  172. - } else if (activeChar instanceof L2Summon)
  173. - {
  174. - int mobId = ((L2Summon) activeChar).getNpcId();
  175. - sm.addNpcName(mobId);
  176. - } else
  177. - {
  178. - sm.addString(activeChar.getName());
  179. - }
  180. - sm.addNumber((int) mp);
  181. - target.sendPacket(sm);
  182. - if (activeChar instanceof L2PcInstance)
  183. - {
  184. - SystemMessage sm2 = new SystemMessage(SystemMessageId.YOUR_OPPONENTS_MP_WAS_REDUCED_BY_S1);
  185. - sm2.addNumber((int) mp);
  186. - activeChar.sendPacket(sm2);
  187. - }
  188. - // [L2J_JP EDIT END - TSL]
  189. - }
  190. - }
  191. -}
  192. -
  193. -public SkillType[] getSkillIds()
  194. -{
  195. - return SKILL_IDS;
  196. -}
  197. -}
  198. +/*
  199. + * This program is free software: you can redistribute it and/or modify it under
  200. + * the terms of the GNU General Public License as published by the Free Software
  201. + * Foundation, either version 3 of the License, or (at your option) any later
  202. + * version.
  203. + *
  204. + * This program is distributed in the hope that it will be useful, but WITHOUT
  205. + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  206. + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  207. + * details.
  208. + *
  209. + * You should have received a copy of the GNU General Public License along with
  210. + * this program. If not, see <http://www.gnu.org/licenses/>.
  211. + */
  212. +package net.sf.l2j.gameserver.handler.skillhandlers;
  213. +
  214. +import net.sf.l2j.gameserver.handler.ISkillHandler;
  215. +import net.sf.l2j.gameserver.model.L2Character;
  216. +import net.sf.l2j.gameserver.model.L2ItemInstance;
  217. +import net.sf.l2j.gameserver.model.L2Object;
  218. +import net.sf.l2j.gameserver.model.L2Skill;
  219. +import net.sf.l2j.gameserver.model.L2Summon;
  220. +import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  221. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  222. +import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  223. +import net.sf.l2j.gameserver.network.SystemMessageId;
  224. +import net.sf.l2j.gameserver.serverpackets.StatusUpdate;
  225. +import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  226. +import net.sf.l2j.gameserver.skills.Formulas;
  227. +
  228. +/**
  229. + * Class handling the Mana damage skill
  230. + *
  231. + * @author slyce
  232. + */
  233. +public class Manadam implements ISkillHandler
  234. +{
  235. +private static final SkillType[] SKILL_IDS = { SkillType.MANADAM };
  236. +
  237. +public void useSkill(@SuppressWarnings("unused")
  238. +L2Character activeChar, L2Skill skill, L2Object[] targets)
  239. +{
  240. + L2Character target = null;
  241. +
  242. + if (activeChar.isAlikeDead())
  243. + return;
  244. +
  245. + boolean ss = false;
  246. + boolean bss = false;
  247. +
  248. + L2ItemInstance weaponInst = activeChar.getActiveWeaponInstance();
  249. +
  250. + if (weaponInst != null)
  251. + {
  252. + if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
  253. + {
  254. + bss = true;
  255. + weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
  256. + } else if (weaponInst.getChargedSpiritshot() == L2ItemInstance.CHARGED_SPIRITSHOT)
  257. + {
  258. + ss = true;
  259. + weaponInst.setChargedSpiritshot(L2ItemInstance.CHARGED_NONE);
  260. + }
  261. + }
  262. + // If there is no weapon equipped, check for an active summon.
  263. + else if (activeChar instanceof L2Summon)
  264. + {
  265. + L2Summon activeSummon = (L2Summon) activeChar;
  266. +
  267. + if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_BLESSED_SPIRITSHOT)
  268. + {
  269. + bss = true;
  270. + activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  271. + }
  272. + else if (activeSummon.getChargedSpiritShot() == L2ItemInstance.CHARGED_SPIRITSHOT)
  273. + {
  274. + ss = true;
  275. + activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  276. + }
  277. + }
  278. + else if (activeChar instanceof L2NpcInstance)
  279. + {
  280. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  281. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  282. + }
  283. + for (int index = 0; index < targets.length; index++)
  284. + {
  285. + target = (L2Character) targets[index];
  286. +
  287. + if (target.reflectSkill(skill))
  288. + target = activeChar;
  289. +
  290. + boolean acted = Formulas.getInstance().calcMagicAffected(activeChar, target, skill);
  291. + if (target.isInvul() || !acted)
  292. + {
  293. + activeChar.sendPacket(new SystemMessage(SystemMessageId.MISSED_TARGET));
  294. + } else
  295. + {
  296. + double damage = Formulas.getInstance().calcManaDam(activeChar, target, skill, ss, bss);
  297. +
  298. + double mp = (damage > target.getCurrentMp() ? target.getCurrentMp() : damage);
  299. + target.reduceCurrentMp(mp);
  300. + if (damage > 0)
  301. + {
  302. + if (target.isSleeping())
  303. + {
  304. + target.stopSleeping(null);
  305. + }
  306. + else if (target.isImmobileUntilAttacked())
  307. + {
  308. + target.stopImmobileUntilAttacked(null);
  309. + }
  310. + }
  311. +
  312. + StatusUpdate sump = new StatusUpdate(target.getObjectId());
  313. + sump.addAttribute(StatusUpdate.CUR_MP, (int) target.getCurrentMp());
  314. + // [L2J_JP EDIT START - TSL]
  315. + target.sendPacket(sump);
  316. + SystemMessage sm = new SystemMessage(SystemMessageId.S2_MP_HAS_BEEN_DRAINED_BY_S1);
  317. + if (activeChar instanceof L2NpcInstance)
  318. + {
  319. + int mobId = ((L2NpcInstance) activeChar).getNpcId();
  320. + sm.addNpcName(mobId);
  321. + } else if (activeChar instanceof L2Summon)
  322. + {
  323. + int mobId = ((L2Summon) activeChar).getNpcId();
  324. + sm.addNpcName(mobId);
  325. + } else
  326. + {
  327. + sm.addString(activeChar.getName());
  328. + }
  329. + sm.addNumber((int) mp);
  330. + target.sendPacket(sm);
  331. + if (activeChar instanceof L2PcInstance)
  332. + {
  333. + SystemMessage sm2 = new SystemMessage(SystemMessageId.YOUR_OPPONENTS_MP_WAS_REDUCED_BY_S1);
  334. + sm2.addNumber((int) mp);
  335. + activeChar.sendPacket(sm2);
  336. + }
  337. + // [L2J_JP EDIT END - TSL]
  338. + }
  339. + }
  340. +}
  341. +
  342. +public SkillType[] getSkillIds()
  343. +{
  344. + return SKILL_IDS;
  345. +}
  346. +}
  347. Index: java/config/altsettings.properties
  348. ===================================================================
  349. --- java/config/altsettings.properties (revision 1770)
  350. +++ java/config/altsettings.properties (revision 1771)
  351. @@ -44,9 +44,6 @@
  352. # Alternative Rate Value for Perfect Shield Block Rate.
  353. AltPerfectShieldBlockRate = 5
  354.  
  355. -# Alternative AltGameMobAttackAI, like C1
  356. -AltGameMobAttackAI = False
  357. -
  358. # Alternative mob behavior in peace zones
  359. # Default = True; Set to False to prevent mobs from auto-agro against players in peace zones
  360. AltMobAgroInPeaceZone = True
  361. Index: java/net/sf/l2j/Config.java
  362. ===================================================================
  363. --- java/net/sf/l2j/Config.java (revision 1770)
  364. +++ java/net/sf/l2j/Config.java (revision 1771)
  365. @@ -1683,7 +1683,6 @@
  366. ALT_PERFECT_SHLD_BLOCK = Integer.parseInt(altSettings.getProperty("AltPerfectShieldBlockRate", "10"));
  367. ALT_GAME_DELEVEL = Boolean.parseBoolean(altSettings.getProperty("Delevel", "true"));
  368. ALT_GAME_MAGICFAILURES = Boolean.parseBoolean(altSettings.getProperty("MagicFailures", "false"));
  369. - ALT_GAME_MOB_ATTACK_AI = Boolean.parseBoolean(altSettings.getProperty("AltGameMobAttackAI", "false"));
  370. ALT_MOB_AGRO_IN_PEACEZONE = Boolean.parseBoolean(altSettings.getProperty("AltMobAgroInPeaceZone", "true"));
  371. ALT_GAME_EXPONENT_XP = Float.parseFloat(altSettings.getProperty("AltGameExponentXp", "0."));
  372. ALT_GAME_EXPONENT_SP = Float.parseFloat(altSettings.getProperty("AltGameExponentSp", "0."));
  373. @@ -2376,7 +2375,6 @@
  374. else if (pName.equalsIgnoreCase("AltPerfectShieldBlockRate")) ALT_PERFECT_SHLD_BLOCK = Integer.parseInt(pValue);
  375. else if (pName.equalsIgnoreCase("Delevel")) ALT_GAME_DELEVEL = Boolean.valueOf(pValue);
  376. else if (pName.equalsIgnoreCase("MagicFailures")) ALT_GAME_MAGICFAILURES = Boolean.valueOf(pValue);
  377. - else if (pName.equalsIgnoreCase("AltGameMobAttackAI")) ALT_GAME_MOB_ATTACK_AI = Boolean.valueOf(pValue);
  378. else if (pName.equalsIgnoreCase("AltMobAgroInPeaceZone")) ALT_MOB_AGRO_IN_PEACEZONE = Boolean.valueOf(pValue);
  379.  
  380. else if (pName.equalsIgnoreCase("AltGameExponentXp")) ALT_GAME_EXPONENT_XP = Float.parseFloat(pValue);
  381. Index: java/net/sf/l2j/gameserver/model/L2Skill.java
  382. ===================================================================
  383. --- java/net/sf/l2j/gameserver/model/L2Skill.java (revision 1770)
  384. +++ java/net/sf/l2j/gameserver/model/L2Skill.java (revision 1771)
  385. @@ -2228,6 +2228,28 @@
  386. }
  387. }
  388. }
  389. + else if (activeChar instanceof L2NpcInstance)
  390. + {
  391. + // for buff purposes, returns one unbuffed friendly mob nearby or mob itself?
  392. + L2NpcInstance npc = (L2NpcInstance) activeChar;
  393. + for (L2Object newTarget : activeChar.getKnownList().getKnownObjects().values())
  394. + {
  395. + if (newTarget instanceof L2NpcInstance && ((L2NpcInstance)newTarget).getFactionId() == npc.getFactionId())
  396. + {
  397. + if (!Util.checkIfInRange(getCastRange(), activeChar, newTarget, true))
  398. + continue;
  399. + if (((L2NpcInstance)newTarget).getFirstEffect(this) != null)
  400. + {
  401. + targetList.add((L2NpcInstance)newTarget);
  402. + break;
  403. + }
  404. + }
  405. + }
  406. + if (targetList.isEmpty())
  407. + {
  408. + targetList.add(activeChar);
  409. + }
  410. + }
  411.  
  412. return targetList.toArray(new L2Character[targetList.size()]);
  413. }
  414. Index: java/net/sf/l2j/gameserver/model/L2ItemInstance.java
  415. ===================================================================
  416. --- java/net/sf/l2j/gameserver/model/L2ItemInstance.java (revision 1770)
  417. +++ java/net/sf/l2j/gameserver/model/L2ItemInstance.java (revision 1771)
  418. @@ -63,7 +63,8 @@
  419. PET,
  420. PET_EQUIP,
  421. LEASE,
  422. - FREIGHT
  423. + FREIGHT,
  424. + NPC
  425. }
  426.  
  427. /** ID of the owner */
  428. @@ -939,7 +940,7 @@
  429. {
  430. return;
  431. }
  432. - if (_loc == ItemLocation.VOID || _ownerId == 0)
  433. + if (_loc == ItemLocation.VOID || _loc == ItemLocation.NPC || _ownerId == 0)
  434. {
  435. return;
  436. }
  437. Index: java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java
  438. ===================================================================
  439. --- java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java (revision 1770)
  440. +++ java/net/sf/l2j/gameserver/model/actor/instance/L2NpcInstance.java (revision 1771)
  441. @@ -53,6 +53,7 @@
  442. import net.sf.l2j.gameserver.model.L2World;
  443. import net.sf.l2j.gameserver.model.L2WorldRegion;
  444. import net.sf.l2j.gameserver.model.MobGroupTable;
  445. +import net.sf.l2j.gameserver.model.NpcInventory;
  446. import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  447. import net.sf.l2j.gameserver.model.actor.knownlist.NpcKnownList;
  448. import net.sf.l2j.gameserver.model.actor.stat.NpcStat;
  449. @@ -69,6 +70,7 @@
  450. import net.sf.l2j.gameserver.serverpackets.ExShowVariationCancelWindow;
  451. import net.sf.l2j.gameserver.serverpackets.ExShowVariationMakeWindow;
  452. import net.sf.l2j.gameserver.serverpackets.InventoryUpdate;
  453. +import net.sf.l2j.gameserver.serverpackets.MagicSkillUse;
  454. import net.sf.l2j.gameserver.serverpackets.MyTargetSelected;
  455. import net.sf.l2j.gameserver.serverpackets.NpcHtmlMessage;
  456. import net.sf.l2j.gameserver.serverpackets.NpcInfo;
  457. @@ -104,6 +106,8 @@
  458.  
  459. /** The L2Spawn object that manage this L2NpcInstance */
  460. private L2Spawn _spawn;
  461. +
  462. + private NpcInventory _inventory = null;
  463.  
  464. /** The flag to specify if this L2NpcInstance is busy */
  465. private boolean _isBusy = false;
  466. @@ -276,6 +280,8 @@
  467.  
  468. // Set the name of the L2Character
  469. setName(template.name);
  470. + if ((template.ss > 0 || template.bss > 0) && template.ssRate > 0)
  471. + _inventory = new NpcInventory(this);
  472.  
  473. }
  474.  
  475. @@ -2170,7 +2176,9 @@
  476. @Override
  477. public void onSpawn()
  478. {
  479. - super.onSpawn();
  480. + if (_inventory != null) _inventory.Reset();
  481. +
  482. + super.onSpawn();
  483.  
  484. if (getTemplate().getEventQuests(Quest.QuestEventType.NPC_SPAWNED) != null)
  485. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.NPC_SPAWNED))
  486. @@ -2297,4 +2305,61 @@
  487. {
  488. return _currentCollisionRadius;
  489. }
  490. +
  491. + public boolean rechargeAutoSoulShot(boolean physical, boolean magic)
  492. + {
  493. + if (this.getTemplate().ssRate == 0) return false;
  494. +
  495. + L2Weapon weaponItem = getActiveWeaponItem();
  496. + if (weaponItem == null)
  497. + {
  498. + //_log.warning("NpcId "+getNpcId()+" missing weaponItem definition in DP - or wrong use of shots.");
  499. + return false;
  500. + }
  501. + if (magic)
  502. + {
  503. + if (this.getTemplate().ssRate < Rnd.get(100))
  504. + {
  505. + _inventory.bshotInUse = false;
  506. + return false;
  507. + }
  508. +
  509. + if (null != _inventory.destroyItemByItemId("Consume", 3947, weaponItem.getSpiritShotCount(), null, null))
  510. + {
  511. + _inventory.bshotInUse = true;
  512. + broadcastPacket(new MagicSkillUse(this, this, 2061, 1, 0, 0), 360000); // no grade
  513. + return true;
  514. + }
  515. + else
  516. + _inventory.bshotInUse = false;
  517. +
  518. + }
  519. + if (physical)
  520. + {
  521. + if (this.getTemplate().ssRate < Rnd.get(100))
  522. + {
  523. + _inventory.sshotInUse = false;
  524. + return false;
  525. + }
  526. +
  527. + if (null != _inventory.destroyItemByItemId("Consume", 1835, weaponItem.getSoulShotCount(), null, null))
  528. + {
  529. + _inventory.sshotInUse = true;
  530. + broadcastPacket(new MagicSkillUse(this, this, 2039, 1, 0, 0), 360000); // no grade
  531. + return true;
  532. + }
  533. + else
  534. + _inventory.sshotInUse = false;
  535. + }
  536. + return false;
  537. + }
  538. +
  539. + public boolean isUsingShot(boolean physical)
  540. + {
  541. + if (_inventory == null) return false;
  542. + if (physical && _inventory.sshotInUse) return true;
  543. + if (!physical && _inventory.bshotInUse) return true;
  544. + return false;
  545. + }
  546. +
  547. }
  548. Index: java/net/sf/l2j/gameserver/model/L2Character.java
  549. ===================================================================
  550. --- java/net/sf/l2j/gameserver/model/L2Character.java (revision 1770)
  551. +++ java/net/sf/l2j/gameserver/model/L2Character.java (revision 1771)
  552. @@ -789,7 +789,9 @@
  553. // Verify if soulshots are charged.
  554. boolean wasSSCharged;
  555.  
  556. - if (this instanceof L2Summon && !(this instanceof L2PetInstance))
  557. + if (this instanceof L2NpcInstance)
  558. + wasSSCharged = ((L2NpcInstance)this).rechargeAutoSoulShot(true, false);
  559. + else if (this instanceof L2Summon && !(this instanceof L2PetInstance))
  560. wasSSCharged = (((L2Summon)this).getChargedSoulShot() != L2ItemInstance.CHARGED_NONE);
  561. else
  562. wasSSCharged = (weaponInst != null && weaponInst.getChargedSoulshot() != L2ItemInstance.CHARGED_NONE);
  563. @@ -1351,7 +1353,9 @@
  564. //Recharge AutoSoulShot
  565. if (skill.useSoulShot())
  566. {
  567. - if (this instanceof L2PcInstance)
  568. + if (this instanceof L2NpcInstance)
  569. + ((L2NpcInstance)this).rechargeAutoSoulShot(true, false);
  570. + else if (this instanceof L2PcInstance)
  571. ((L2PcInstance)this).rechargeAutoSoulShot(true, false, false);
  572. else if (this instanceof L2Summon)
  573. ((L2Summon)this).getOwner().rechargeAutoSoulShot(true, false, true);
  574. @@ -1358,7 +1362,7 @@
  575. }
  576. else if (skill.useSpiritShot())
  577. {
  578. - if (this instanceof L2PcInstance)
  579. + if (this instanceof L2PcInstance)
  580. ((L2PcInstance)this).rechargeAutoSoulShot(false, true, false);
  581. else if (this instanceof L2Summon)
  582. ((L2Summon)this).getOwner().rechargeAutoSoulShot(false, true, true);
  583. @@ -1485,6 +1489,14 @@
  584. }
  585. }
  586. }
  587. + else if (this instanceof L2NpcInstance && skill.useSpiritShot() && !forceBuff)
  588. + {
  589. + if(((L2NpcInstance)this).rechargeAutoSoulShot(false, true))
  590. + {
  591. + hitTime = (int)(0.70 * hitTime);
  592. + coolTime = (int)(0.70 * coolTime);
  593. + }
  594. + }
  595.  
  596. // Set the _castEndTime and _castInterruptTim. +10 ticks for lag situations, will be reseted in onMagicFinalizer
  597. _castEndTime = 10 + GameTimeController.getGameTicks() + (coolTime + hitTime) / GameTimeController.MILLIS_IN_TICK;
  598. Index: java/net/sf/l2j/gameserver/model/L2Attackable.java
  599. ===================================================================
  600. --- java/net/sf/l2j/gameserver/model/L2Attackable.java (revision 1770)
  601. +++ java/net/sf/l2j/gameserver/model/L2Attackable.java (revision 1771)
  602. @@ -948,7 +948,43 @@
  603. }
  604. return mostHated;
  605. }
  606. +
  607. + /**
  608. + * Return the 2 most hated L2Character of the L2Attackable _aggroList.<BR><BR>
  609. + */
  610. + public List<L2Character> get2MostHated()
  611. + {
  612. + if (getAggroListRP().isEmpty() || isAlikeDead()) return null;
  613.  
  614. + L2Character mostHated = null;
  615. + L2Character secondMostHated = null;
  616. + int maxHate = 0;
  617. + List<L2Character> result = new FastList<L2Character>();
  618. +
  619. + // While Interating over This Map Removing Object is Not Allowed
  620. + synchronized (getAggroList())
  621. + {
  622. + // Go through the aggroList of the L2Attackable
  623. + for (AggroInfo ai : getAggroListRP().values())
  624. + {
  625. + if (ai == null) continue;
  626. + if (ai._attacker.isAlikeDead() || !getKnownList().knowsObject(ai._attacker) ||!ai._attacker.isVisible())
  627. + ai._hate = 0;
  628. + if (ai._hate > maxHate)
  629. + {
  630. + secondMostHated = mostHated;
  631. + mostHated = ai._attacker;
  632. + maxHate = ai._hate;
  633. + }
  634. + }
  635. + }
  636. + result.add(mostHated);
  637. + if (getAttackByList().contains(secondMostHated))
  638. + result.add(secondMostHated);
  639. + else result.add(null);
  640. + return result;
  641. + }
  642. +
  643. /**
  644. * Return the hate level of the L2Attackable against this L2Character contained in _aggroList.<BR><BR>
  645. *
  646. Index: java/net/sf/l2j/gameserver/model/NpcInventory.java
  647. ===================================================================
  648. --- java/net/sf/l2j/gameserver/model/NpcInventory.java (revision 0)
  649. +++ java/net/sf/l2j/gameserver/model/NpcInventory.java (revision 1771)
  650. @@ -0,0 +1,89 @@
  651. +/* This program is free software; you can redistribute it and/or modify
  652. + * it under the terms of the GNU General Public License as published by
  653. + * the Free Software Foundation; either version 2, or (at your option)
  654. + * any later version.
  655. + *
  656. + * This program is distributed in the hope that it will be useful,
  657. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  658. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  659. + * GNU General Public License for more details.
  660. + *
  661. + * You should have received a copy of the GNU General Public License
  662. + * along with this program; if not, write to the Free Software
  663. + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  664. + * 02111-1307, USA.
  665. + *
  666. + * http://www.gnu.org/copyleft/gpl.html
  667. + */
  668. +package net.sf.l2j.gameserver.model;
  669. +
  670. +import java.util.List;
  671. +
  672. +import javolution.util.FastList;
  673. +import net.sf.l2j.gameserver.model.L2ItemInstance.ItemLocation;
  674. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  675. +
  676. +public class NpcInventory extends Inventory
  677. +{
  678. + public static final int ADENA_ID = 57;
  679. + public static final int ANCIENT_ADENA_ID = 5575;
  680. +
  681. + private final L2NpcInstance _owner;
  682. +
  683. + public boolean sshotInUse = false;
  684. + public boolean bshotInUse = false;
  685. +
  686. + public NpcInventory(L2NpcInstance owner)
  687. + {
  688. + _owner = owner;
  689. + }
  690. +
  691. + public void Reset()
  692. + {
  693. + this.destroyAllItems("Reset", null, null);
  694. + if (_owner.getTemplate().ss > 0) this.addItem("Reset", 1835, _owner.getTemplate().ss, null, null);
  695. + if (_owner.getTemplate().bss > 0) this.addItem("Reset", 3947, _owner.getTemplate().bss, null, null);
  696. + }
  697. +
  698. + @Override
  699. + public L2NpcInstance getOwner() { return _owner; }
  700. + @Override
  701. + protected ItemLocation getBaseLocation() { return ItemLocation.NPC; }
  702. + @Override
  703. + protected ItemLocation getEquipLocation() { return ItemLocation.NPC; }
  704. +
  705. + /**
  706. + * Returns the list of all items in inventory that have a given item id.
  707. + * @return L2ItemInstance[] : matching items from inventory
  708. + */
  709. + public L2ItemInstance[] getAllItemsByItemId(int itemId)
  710. + {
  711. + List<L2ItemInstance> list = new FastList<L2ItemInstance>();
  712. + for (L2ItemInstance item : _items)
  713. + {
  714. + if (item.getItemId() == itemId)
  715. + list.add(item);
  716. + }
  717. +
  718. + return list.toArray(new L2ItemInstance[list.size()]);
  719. + }
  720. +
  721. + /**
  722. + * Refresh the weight of equipment loaded
  723. + */
  724. + @Override
  725. + public void refreshWeight()
  726. + {
  727. + // not needed
  728. + }
  729. +
  730. + /**
  731. + * Get back items in inventory from database
  732. + */
  733. + @Override
  734. + public void restore()
  735. + {
  736. + // not needed
  737. + }
  738. +
  739. +}
  740. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/Continuous.java
  741. ===================================================================
  742. --- java/net/sf/l2j/gameserver/handler/skillhandlers/Continuous.java (revision 1770)
  743. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/Continuous.java (revision 1771)
  744. @@ -28,6 +28,7 @@
  745. import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  746. import net.sf.l2j.gameserver.model.actor.instance.L2ClanHallManagerInstance;
  747. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  748. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  749. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  750. import net.sf.l2j.gameserver.model.actor.instance.L2PlayableInstance;
  751. import net.sf.l2j.gameserver.network.SystemMessageId;
  752. @@ -162,6 +163,11 @@
  753. activeSummon.setChargedSoulShot(L2ItemInstance.CHARGED_NONE);
  754. }
  755. }
  756. + else if (activeChar instanceof L2NpcInstance)
  757. + {
  758. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  759. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  760. + }
  761.  
  762. acted = Formulas.getInstance().calcSkillSuccess(activeChar, target, skill, ss, sps, bss);
  763. }
  764. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/Mdam.java
  765. ===================================================================
  766. --- java/net/sf/l2j/gameserver/handler/skillhandlers/Mdam.java (revision 1770)
  767. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/Mdam.java (revision 1771)
  768. @@ -97,6 +97,11 @@
  769. activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  770. }
  771. }
  772. + else if (activeChar instanceof L2NpcInstance)
  773. + {
  774. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  775. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  776. + }
  777.  
  778. for (int index = 0; index < targets.length; index++)
  779. {
  780. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/Disablers.java
  781. ===================================================================
  782. --- java/net/sf/l2j/gameserver/handler/skillhandlers/Disablers.java (revision 1770)
  783. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/Disablers.java (revision 1771)
  784. @@ -31,6 +31,7 @@
  785. import net.sf.l2j.gameserver.model.L2Skill;
  786. import net.sf.l2j.gameserver.model.L2Summon;
  787. import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  788. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  789. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  790. import net.sf.l2j.gameserver.model.actor.instance.L2SiegeSummonInstance;
  791. import net.sf.l2j.gameserver.model.base.Experience;
  792. @@ -152,6 +153,11 @@
  793. }
  794. }
  795. }
  796. + else if (activeChar instanceof L2NpcInstance)
  797. + {
  798. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  799. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  800. + }
  801.  
  802. for (int index = 0; index < targets.length; index++)
  803. {
  804. Index: java/net/sf/l2j/gameserver/handler/skillhandlers/CpDam.java
  805. ===================================================================
  806. --- java/net/sf/l2j/gameserver/handler/skillhandlers/CpDam.java (revision 1770)
  807. +++ java/net/sf/l2j/gameserver/handler/skillhandlers/CpDam.java (revision 1771)
  808. @@ -21,6 +21,7 @@
  809. import net.sf.l2j.gameserver.model.L2Skill;
  810. import net.sf.l2j.gameserver.model.L2Summon;
  811. import net.sf.l2j.gameserver.model.L2Skill.SkillType;
  812. +import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  813. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  814. import net.sf.l2j.gameserver.skills.Formulas;
  815.  
  816. @@ -85,6 +86,11 @@
  817. activeSummon.setChargedSpiritShot(L2ItemInstance.CHARGED_NONE);
  818. }
  819. }
  820. + else if (activeChar instanceof L2NpcInstance)
  821. + {
  822. + bss = ((L2NpcInstance)activeChar).isUsingShot(false);
  823. + ss = ((L2NpcInstance)activeChar).isUsingShot(true);
  824. + }
  825.  
  826. for (int index = 0; index < targets.length; index++)
  827. {
  828. Index: java/net/sf/l2j/gameserver/ai/L2AttackableAI.java
  829. ===================================================================
  830. --- java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (revision 1770)
  831. +++ java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (revision 1771)
  832. @@ -18,8 +18,11 @@
  833. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
  834. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
  835.  
  836. +import java.util.List;
  837. import java.util.concurrent.Future;
  838.  
  839. +import javolution.util.FastList;
  840. +
  841. import net.sf.l2j.Config;
  842. import net.sf.l2j.gameserver.GameTimeController;
  843. import net.sf.l2j.gameserver.GeoData;
  844. @@ -29,7 +32,6 @@
  845. import net.sf.l2j.gameserver.model.L2Attackable;
  846. import net.sf.l2j.gameserver.model.L2CharPosition;
  847. import net.sf.l2j.gameserver.model.L2Character;
  848. -import net.sf.l2j.gameserver.model.L2Effect;
  849. import net.sf.l2j.gameserver.model.L2Object;
  850. import net.sf.l2j.gameserver.model.L2Skill;
  851. import net.sf.l2j.gameserver.model.L2Summon;
  852. @@ -37,17 +39,17 @@
  853. import net.sf.l2j.gameserver.model.actor.instance.L2FestivalMonsterInstance;
  854. import net.sf.l2j.gameserver.model.actor.instance.L2FolkInstance;
  855. import net.sf.l2j.gameserver.model.actor.instance.L2FriendlyMobInstance;
  856. +import net.sf.l2j.gameserver.model.actor.instance.L2GrandBossInstance;
  857. import net.sf.l2j.gameserver.model.actor.instance.L2GuardInstance;
  858. import net.sf.l2j.gameserver.model.actor.instance.L2MinionInstance;
  859. import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  860. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  861. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  862. -import net.sf.l2j.gameserver.model.actor.instance.L2PenaltyMonsterInstance;
  863. import net.sf.l2j.gameserver.model.actor.instance.L2RaidBossInstance;
  864. import net.sf.l2j.gameserver.model.actor.instance.L2RiftInvaderInstance;
  865. -import net.sf.l2j.gameserver.templates.L2Weapon;
  866. -import net.sf.l2j.gameserver.templates.L2WeaponType;
  867. +import net.sf.l2j.gameserver.taskmanager.DecayTaskManager;
  868. import net.sf.l2j.util.Rnd;
  869. +import net.sf.l2j.gameserver.util.Util;
  870.  
  871. /**
  872. * This class manages AI of L2Attackable.<BR><BR>
  873. @@ -73,7 +75,12 @@
  874.  
  875. /** The flag used to indicate that a thinking action is in progress */
  876. private boolean _thinking; // to prevent recursive thinking
  877. -
  878. +
  879. + /** For attack AI, analysis of mob and its targets */
  880. + private SelfAnalysis _selfAnalysis = new SelfAnalysis();
  881. + private TargetAnalysis _mostHatedAnalysis = new TargetAnalysis();
  882. + private TargetAnalysis _secondMostHatedAnalysis = new TargetAnalysis();
  883. +
  884. /**
  885. * Constructor of L2AttackableAI.<BR><BR>
  886. *
  887. @@ -83,7 +90,7 @@
  888. public L2AttackableAI(L2Character.AIAccessor accessor)
  889. {
  890. super(accessor);
  891. -
  892. + _selfAnalysis.Init();
  893. _attackTimeout = Integer.MAX_VALUE;
  894. _globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
  895. }
  896. @@ -161,8 +168,7 @@
  897. if (!(me instanceof L2RaidBossInstance) && ((L2PcInstance)target).isSilentMoving())
  898. return false;
  899.  
  900. - // Check if player is an ally //TODO! [Nemesiss] it should be rather boolean or smth like that
  901. - // Comparing String isnt good idea!
  902. + // Check if player is an ally (comparing mem addr)
  903. if (me.getFactionId() == "varka" && ((L2PcInstance)target).isAlliedWithVarka())
  904. return false;
  905. if (me.getFactionId() == "ketra" && ((L2PcInstance)target).isAlliedWithKetra())
  906. @@ -180,6 +186,9 @@
  907. && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(me.getX(), me.getY(), me.getZ()))
  908. return false;
  909. }
  910. +
  911. + if (_selfAnalysis.cannotMoveOnLand && !target.isInsideZone(L2Character.ZONE_WATER))
  912. + return false;
  913. }
  914.  
  915. // Check if the actor is a L2GuardInstance
  916. @@ -318,6 +327,30 @@
  917. // Calculate the attack timeout
  918. _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  919.  
  920. + // self and buffs
  921. + if (_selfAnalysis.lastBuffTick+100 < GameTimeController.getGameTicks())
  922. + {
  923. + for (L2Skill sk : _selfAnalysis.buffSkills)
  924. + {
  925. + if (_actor.getFirstEffect(sk.getId()) == null)
  926. + {
  927. + if (_actor.getCurrentMp() < sk.getMpConsume())
  928. + continue;
  929. + if (_actor.isSkillDisabled(sk.getId()))
  930. + continue;
  931. + // no clan buffs here?
  932. + if (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_CLAN)
  933. + continue;
  934. + L2Object OldTarget = _actor.getTarget();
  935. + _actor.setTarget(_actor);
  936. + clientStopMoving(null);
  937. + _accessor.doCast(sk);
  938. + // forcing long reuse delay so if cast get interrupted or there would be several buffs, doesn't cast again
  939. + _selfAnalysis.lastBuffTick = GameTimeController.getGameTicks();
  940. + _actor.setTarget(OldTarget);
  941. + }
  942. + }
  943. + }
  944. // Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
  945. super.onIntentionAttack(target);
  946. }
  947. @@ -380,7 +413,7 @@
  948.  
  949. // Chose a target from its aggroList
  950. L2Character hated;
  951. - if (_actor.isConfused()) hated = getAttackTarget(); // Force mobs to attak anybody if confused
  952. + if (_actor.isConfused()) hated = getAttackTarget(); // effect handles selection
  953. else hated = npc.getMostHated();
  954.  
  955. // Order to the L2Attackable to attack the target
  956. @@ -437,18 +470,54 @@
  957. moveTo(x1, y1, z1);
  958. return;
  959. }
  960. + else if (Rnd.nextInt(RANDOM_WALK_RATE) == 0)
  961. + {
  962. + // self and clan buffs
  963. + for (L2Skill sk : _selfAnalysis.buffSkills)
  964. + {
  965. + if (_actor.getFirstEffect(sk.getId()) == null)
  966. + {
  967. + if (_actor.getCurrentMp() < sk.getMpConsume())
  968. + continue;
  969. + if (_actor.isSkillDisabled(sk.getId()))
  970. + continue;
  971. + L2Object OldTarget = _actor.getTarget();
  972. + _actor.setTarget(_actor);
  973. + clientStopMoving(null);
  974. + _accessor.doCast(sk);
  975. + _actor.setTarget(OldTarget);
  976. + return;
  977. + }
  978. + }
  979. + }
  980. }
  981. // Order to the L2MonsterInstance to random walk (1/100)
  982. else if (npc.getSpawn() != null && Rnd.nextInt(RANDOM_WALK_RATE) == 0)
  983. {
  984. int x1, y1, z1;
  985. -
  986. + int range = Config.MAX_DRIFT_RANGE;
  987. +
  988. + // self and clan buffs
  989. + for (L2Skill sk : _selfAnalysis.buffSkills)
  990. + {
  991. + if (_actor.getFirstEffect(sk.getId()) == null)
  992. + {
  993. + if (_actor.getCurrentMp() < sk.getMpConsume())
  994. + continue;
  995. + if (_actor.isSkillDisabled(sk.getId()))
  996. + continue;
  997. + L2Object OldTarget = _actor.getTarget();
  998. + _actor.setTarget(_actor);
  999. + clientStopMoving(null);
  1000. + _accessor.doCast(sk);
  1001. + _actor.setTarget(OldTarget);
  1002. + return;
  1003. + }
  1004. + }
  1005. +
  1006. // If NPC with random coord in territory
  1007. if (npc.getSpawn().getLocx() == 0 && npc.getSpawn().getLocy() == 0)
  1008. {
  1009. - // If NPC with random fixed coord, don't move
  1010. - if (Territory.getInstance().getProcMax(npc.getSpawn().getLocation()) > 0) return;
  1011. -
  1012. // Calculate a destination point in the spawn area
  1013. int p[] = Territory.getInstance().getRandomPoint(npc.getSpawn().getLocation());
  1014. x1 = p[0];
  1015. @@ -458,21 +527,23 @@
  1016. // Calculate the distance between the current position of the L2Character and the target (x,y)
  1017. double distance2 = _actor.getPlanDistanceSq(x1, y1);
  1018.  
  1019. - if (distance2 > Config.MAX_DRIFT_RANGE * Config.MAX_DRIFT_RANGE)
  1020. + if (distance2 > range * range)
  1021. {
  1022. npc.setisReturningToSpawnPoint(true);
  1023. - float delay = (float) Math.sqrt(distance2) / Config.MAX_DRIFT_RANGE;
  1024. + float delay = (float) Math.sqrt(distance2) / range;
  1025. x1 = _actor.getX() + (int) ((x1 - _actor.getX()) / delay);
  1026. y1 = _actor.getY() + (int) ((y1 - _actor.getY()) / delay);
  1027. }
  1028. +
  1029. + // If NPC with random fixed coord, don't move (unless needs to return to spawnpoint)
  1030. + if (Territory.getInstance().getProcMax(npc.getSpawn().getLocation()) > 0 && !npc.isReturningToSpawnPoint())
  1031. + return;
  1032. }
  1033. else
  1034. {
  1035. // If NPC with fixed coord
  1036. - x1 = npc.getSpawn().getLocx() + Rnd.nextInt(Config.MAX_DRIFT_RANGE * 2)
  1037. - - Config.MAX_DRIFT_RANGE;
  1038. - y1 = npc.getSpawn().getLocy() + Rnd.nextInt(Config.MAX_DRIFT_RANGE * 2)
  1039. - - Config.MAX_DRIFT_RANGE;
  1040. + x1 = npc.getSpawn().getLocx() + Rnd.nextInt(range * 2) - range;
  1041. + y1 = npc.getSpawn().getLocy() + Rnd.nextInt(range * 2) - range;
  1042. z1 = npc.getZ();
  1043. }
  1044.  
  1045. @@ -480,9 +551,6 @@
  1046. // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
  1047. moveTo(x1, y1, z1);
  1048. }
  1049. -
  1050. - return;
  1051. -
  1052. }
  1053.  
  1054. /**
  1055. @@ -527,234 +595,726 @@
  1056. setIntention(AI_INTENTION_ACTIVE);
  1057.  
  1058. _actor.setWalking();
  1059. + return;
  1060. }
  1061. - else
  1062. +
  1063. + // Handle all L2Object of its Faction inside the Faction Range
  1064. + if (((L2NpcInstance) _actor).getFactionId() != null)
  1065. {
  1066. - // Call all L2Object of its Faction inside the Faction Range
  1067. - if (((L2NpcInstance) _actor).getFactionId() != null)
  1068. - {
  1069. - String faction_id = ((L2NpcInstance) _actor).getFactionId();
  1070. + String faction_id = ((L2NpcInstance) _actor).getFactionId();
  1071.  
  1072. - // Go through all L2Object that belong to its faction
  1073. - for (L2Object obj : _actor.getKnownList().getKnownObjects().values())
  1074. - {
  1075. - if (obj instanceof L2NpcInstance)
  1076. - {
  1077. - L2NpcInstance npc = (L2NpcInstance) obj;
  1078. + // Go through all L2Object that belong to its faction
  1079. + for (L2Object obj : _actor.getKnownList().getKnownObjects().values())
  1080. + {
  1081. + if (obj instanceof L2NpcInstance)
  1082. + {
  1083. + L2NpcInstance npc = (L2NpcInstance) obj;
  1084.  
  1085. - if (npc == null || getAttackTarget() == null || faction_id != npc.getFactionId())
  1086. - continue;
  1087. + if (npc == null || getAttackTarget() == null || faction_id != npc.getFactionId())
  1088. + continue;
  1089.  
  1090. - // Check if the L2Object is inside the Faction Range of the actor
  1091. - if (_actor.isInsideRadius(npc, npc.getFactionRange(), true, false)
  1092. - && GeoData.getInstance().canSeeTarget(_actor, npc)
  1093. - && Math.abs(getAttackTarget().getZ() - npc.getZ()) < 600
  1094. - && npc.getAI() != null
  1095. - && _actor.getAttackByList().contains(getAttackTarget())
  1096. - && (npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE
  1097. - || npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
  1098. - {
  1099. - if (getAttackTarget() instanceof L2PcInstance
  1100. - && getAttackTarget().isInParty()
  1101. - && getAttackTarget().getParty().isInDimensionalRift())
  1102. - {
  1103. - byte riftType = getAttackTarget().getParty().getDimensionalRift().getType();
  1104. - byte riftRoom = getAttackTarget().getParty().getDimensionalRift().getCurrentRoom();
  1105. + // Check if the L2Object is inside the Faction Range of the actor
  1106. + if (_actor.isInsideRadius(npc, npc.getFactionRange()+npc.getTemplate().collisionRadius, true, false)
  1107. + && npc.getAI() != null
  1108. + )
  1109. + {
  1110. + if (Math.abs(getAttackTarget().getZ() - npc.getZ()) < 600
  1111. + && _actor.getAttackByList().contains(getAttackTarget())
  1112. + && (npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE
  1113. + || npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)
  1114. + && GeoData.getInstance().canSeeTarget(_actor, npc))
  1115. + {
  1116. + if (getAttackTarget() instanceof L2PcInstance
  1117. + && getAttackTarget().isInParty()
  1118. + && getAttackTarget().getParty().isInDimensionalRift())
  1119. + {
  1120. + byte riftType = getAttackTarget().getParty().getDimensionalRift().getType();
  1121. + byte riftRoom = getAttackTarget().getParty().getDimensionalRift().getCurrentRoom();
  1122.  
  1123. - if (_actor instanceof L2RiftInvaderInstance
  1124. - && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(npc.getX(), npc.getY(), npc.getZ()))
  1125. - continue;
  1126. - }
  1127. + if (_actor instanceof L2RiftInvaderInstance
  1128. + && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(npc.getX(), npc.getY(), npc.getZ()))
  1129. + continue;
  1130. + }
  1131.  
  1132. - // Notify the L2Object AI with EVT_AGGRESSION
  1133. - npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
  1134. - }
  1135. - }
  1136. - }
  1137. + // Notify the L2Object AI with EVT_AGGRESSION
  1138. + npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
  1139. + }
  1140. + // heal or resurrect friends
  1141. + if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled()
  1142. + && npc.getCurrentHp() < npc.getMaxHp()*0.6
  1143. + && _actor.getCurrentHp() > _actor.getMaxHp()/2
  1144. + && _actor.getCurrentMp() > _actor.getMaxMp()/2
  1145. +
  1146. + )
  1147. + {
  1148. + if (npc.isDead() && _actor instanceof L2MinionInstance)
  1149. + {
  1150. + if (((L2MinionInstance)_actor).getLeader() == npc)
  1151. + {
  1152. + for (L2Skill sk : _selfAnalysis.resurrectSkills)
  1153. + {
  1154. + if (_actor.getCurrentMp() < sk.getMpConsume())
  1155. + continue;
  1156. + if (_actor.isSkillDisabled(sk.getId()))
  1157. + continue;
  1158. + if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
  1159. + continue;
  1160. +
  1161. + if (10 >= Rnd.get(100)) // chance
  1162. + continue;
  1163. + if (!GeoData.getInstance().canSeeTarget(_actor, npc))
  1164. + break;
  1165. +
  1166. + L2Object OldTarget = _actor.getTarget();
  1167. + _actor.setTarget(npc);
  1168. + // would this ever be fast enough for the decay not to run?
  1169. + // giving some extra seconds
  1170. + DecayTaskManager.getInstance().cancelDecayTask(npc);
  1171. + DecayTaskManager.getInstance().addDecayTask(npc);
  1172. + clientStopMoving(null);
  1173. + _accessor.doCast(sk);
  1174. + _actor.setTarget(OldTarget);
  1175. + return;
  1176. + }
  1177. + }
  1178. + }
  1179. + else if (npc.isInCombat())
  1180. + {
  1181. + for (L2Skill sk : _selfAnalysis.healSkills)
  1182. + {
  1183. + if (_actor.getCurrentMp() < sk.getMpConsume())
  1184. + continue;
  1185. + if (_actor.isSkillDisabled(sk.getId()))
  1186. + continue;
  1187. + if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
  1188. + continue;
  1189. +
  1190. + int chance = 4;
  1191. + if (_actor instanceof L2MinionInstance)
  1192. + {
  1193. + // minions support boss
  1194. + if (((L2MinionInstance)_actor).getLeader() == npc)
  1195. + chance = 6;
  1196. + else chance = 3;
  1197. + }
  1198. + if (npc instanceof L2GrandBossInstance)
  1199. + chance = 6;
  1200. + if (chance >= Rnd.get(100)) // chance
  1201. + continue;
  1202. + if (!GeoData.getInstance().canSeeTarget(_actor, npc))
  1203. + break;
  1204. +
  1205. + L2Object OldTarget = _actor.getTarget();
  1206. + _actor.setTarget(npc);
  1207. + clientStopMoving(null);
  1208. + _accessor.doCast(sk);
  1209. + _actor.setTarget(OldTarget);
  1210. + return;
  1211. + }
  1212. + }
  1213. + }
  1214. + }
  1215. + }
  1216. }
  1217. + }
  1218.  
  1219. - if(_actor.isAttackingDisabled()) return;
  1220. + if(_actor.isAttackingDisabled()) return;
  1221.  
  1222. - // Get all information needed to chose between physical or magical attack
  1223. - L2Skill[] skills = null;
  1224. - double dist2 = 0;
  1225. - int range = 0;
  1226. + // Get 2 most hated chars
  1227. + List<L2Character> hated = ((L2Attackable) _actor).get2MostHated();
  1228. + if (_actor.isConfused())
  1229. + {
  1230. + if (hated != null)
  1231. + hated.set(0, getAttackTarget()); // effect handles selection
  1232. + else
  1233. + {
  1234. + hated = new FastList<L2Character>();
  1235. + hated.add(getAttackTarget());
  1236. + hated.add(null);
  1237. + }
  1238. + }
  1239.  
  1240. - try
  1241. + if (hated == null || hated.get(0) == null)
  1242. + {
  1243. + setIntention(AI_INTENTION_ACTIVE);
  1244. + return;
  1245. + }
  1246. + // Reconsider target if _actor hasn't got hits in for last 14 sec
  1247. + if (!_actor.isMuted()
  1248. + && _attackTimeout - 160 < GameTimeController.getGameTicks()
  1249. + && hated.get(1) != null)
  1250. + {
  1251. + if (Util.checkIfInRange(900, _actor, hated.get(1), true))
  1252. + {
  1253. + // take off 2* the amount the aggro is larger than second most
  1254. + ((L2Attackable) _actor).reduceHate(hated.get(0), 2 * (((L2Attackable) _actor).getHating(hated.get(0)) - ((L2Attackable) _actor).getHating(hated.get(1))));
  1255. + // Calculate a new attack timeout
  1256. + _attackTimeout = MAX_ATTACK_TIMEOUT
  1257. + + GameTimeController.getGameTicks();
  1258. + }
  1259. + }
  1260. + if (hated.get(0) != getAttackTarget())
  1261. + {
  1262. + setAttackTarget(hated.get(0));
  1263. + }
  1264. + _mostHatedAnalysis.Update(hated.get(0));
  1265. + _secondMostHatedAnalysis.Update(hated.get(1));
  1266. +
  1267. + // Get all information needed to choose between physical or magical attack
  1268. + _actor.setTarget(_mostHatedAnalysis.character);
  1269. + double dist2 = _actor.getPlanDistanceSq(_mostHatedAnalysis.character.getX(), _mostHatedAnalysis.character.getY());
  1270. + int combinedCollision = _actor.getTemplate().collisionRadius + _mostHatedAnalysis.character.getTemplate().collisionRadius;
  1271. + int range = _actor.getPhysicalAttackRange() + combinedCollision;
  1272. +
  1273. + // Considering, if bigger range will be attempted
  1274. + if ( (dist2 < 10000 + combinedCollision*combinedCollision)
  1275. + && !_selfAnalysis.isFighter && !_selfAnalysis.isBalanced
  1276. + && (_selfAnalysis.hasLongRangeSkills || _selfAnalysis.isArcher)
  1277. + && (_mostHatedAnalysis.isBalanced || _mostHatedAnalysis.isFighter)
  1278. + && (_mostHatedAnalysis.character.isRooted() || _mostHatedAnalysis.isSlower)
  1279. + && (Config.GEODATA == 2 ? 20 : 12) >= Rnd.get(100) // chance
  1280. + )
  1281. + {
  1282. + int posX = _actor.getX();
  1283. + int posY = _actor.getY();
  1284. + int posZ = _actor.getZ();
  1285. + double distance = Math.sqrt(dist2); // This way, we only do the sqrt if we need it
  1286. +
  1287. + int signx=-1;
  1288. + int signy=-1;
  1289. + if (_actor.getX()>_mostHatedAnalysis.character.getX())
  1290. + signx=1;
  1291. + if (_actor.getY()>_mostHatedAnalysis.character.getY())
  1292. + signy=1;
  1293. + posX += Math.round((float)((signx * ((range / 2) + (Rnd.get(range)))) - distance));
  1294. + posY += Math.round((float)((signy * ((range / 2) + (Rnd.get(range)))) - distance));
  1295. + setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(posX, posY, posZ, 0));
  1296. + return;
  1297. + }
  1298. +
  1299. + // Cannot see target, needs to go closer, currently just goes to range 300 if mage
  1300. + if ((dist2 > 310*310 + combinedCollision*combinedCollision)
  1301. + && this._selfAnalysis.hasLongRangeSkills
  1302. + && !GeoData.getInstance().canSeeTarget(_actor, _mostHatedAnalysis.character)
  1303. + )
  1304. + {
  1305. + if (!(_selfAnalysis.isMage && _actor.isMuted()))
  1306. + {
  1307. + moveToPawn(_mostHatedAnalysis.character, 300);
  1308. + return;
  1309. + }
  1310. + }
  1311. +
  1312. + if (_mostHatedAnalysis.character.isMoving()) range += 50;
  1313. + // Check if the actor is far from target
  1314. + if (dist2 > range*range)
  1315. + {
  1316. + if (!_actor.isMuted() && (_selfAnalysis.hasLongRangeSkills || !_selfAnalysis.healSkills.isEmpty()))
  1317. + {
  1318. + // check for long ranged skills and heal/buff skills
  1319. + if (!_mostHatedAnalysis.isCanceled)
  1320. + {
  1321. + for (L2Skill sk : _selfAnalysis.cancelSkills)
  1322. + {
  1323. + int castRange = sk.getCastRange() + combinedCollision;
  1324. + if (_actor.isSkillDisabled(sk.getId())
  1325. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1326. + || (dist2 > castRange * castRange)
  1327. + )
  1328. + continue;
  1329. + if (Rnd.nextInt(100) <= 8)
  1330. + {
  1331. + clientStopMoving(null);
  1332. + _accessor.doCast(sk);
  1333. + _mostHatedAnalysis.isCanceled = true;
  1334. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1335. + return;
  1336. + }
  1337. + }
  1338. + }
  1339. + if (this._selfAnalysis.lastDebuffTick+60 < GameTimeController.getGameTicks())
  1340. + {
  1341. + for (L2Skill sk : _selfAnalysis.debuffSkills)
  1342. + {
  1343. + int castRange = sk.getCastRange() + combinedCollision;
  1344. + if (_actor.isSkillDisabled(sk.getId())
  1345. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1346. + || (dist2 > castRange * castRange)
  1347. + )
  1348. + continue;
  1349. + int chance = 8;
  1350. + if (_selfAnalysis.isFighter && _mostHatedAnalysis.isMage)
  1351. + chance = 3;
  1352. + if (_selfAnalysis.isFighter && _mostHatedAnalysis.isArcher)
  1353. + chance = 12;
  1354. + if (_selfAnalysis.isMage && !_mostHatedAnalysis.isMage)
  1355. + chance = 10;
  1356. + if (_mostHatedAnalysis.isMagicResistant) chance /= 2;
  1357. +
  1358. + if (Rnd.nextInt(100) <= chance)
  1359. + {
  1360. + clientStopMoving(null);
  1361. + _accessor.doCast(sk);
  1362. + _selfAnalysis.lastDebuffTick = GameTimeController.getGameTicks();
  1363. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1364. + return;
  1365. + }
  1366. + }
  1367. + }
  1368. + if (!_mostHatedAnalysis.character.isMuted())
  1369. + {
  1370. + int chance = 8;
  1371. + if (!(_mostHatedAnalysis.isMage || _mostHatedAnalysis.isBalanced))
  1372. + chance = 3;
  1373. + for (L2Skill sk : _selfAnalysis.muteSkills)
  1374. + {
  1375. + int castRange = sk.getCastRange() + combinedCollision;
  1376. + if (_actor.isSkillDisabled(sk.getId())
  1377. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1378. + || (dist2 > castRange * castRange)
  1379. + )
  1380. + continue;
  1381. + if (Rnd.nextInt(100) <= chance)
  1382. + {
  1383. + clientStopMoving(null);
  1384. + _accessor.doCast(sk);
  1385. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1386. + return;
  1387. + }
  1388. + }
  1389. + }
  1390. + if (_secondMostHatedAnalysis.character != null && !_secondMostHatedAnalysis.character.isMuted() && (_secondMostHatedAnalysis.isMage || _secondMostHatedAnalysis.isBalanced))
  1391. + {
  1392. + double secondHatedDist2 = _actor.getPlanDistanceSq(_secondMostHatedAnalysis.character.getX(), _secondMostHatedAnalysis.character.getY());
  1393. + for (L2Skill sk : _selfAnalysis.muteSkills)
  1394. + {
  1395. + int castRange = sk.getCastRange() + combinedCollision;
  1396. + if (_actor.isSkillDisabled(sk.getId())
  1397. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1398. + || (secondHatedDist2 > castRange * castRange)
  1399. + )
  1400. + continue;
  1401. + if (Rnd.nextInt(100) <= 2)
  1402. + {
  1403. + _actor.setTarget(_secondMostHatedAnalysis.character);
  1404. + clientStopMoving(null);
  1405. + _accessor.doCast(sk);
  1406. + _actor.setTarget(_mostHatedAnalysis.character);
  1407. + return;
  1408. + }
  1409. + }
  1410. + }
  1411. + if (!_mostHatedAnalysis.character.isSleeping())
  1412. + {
  1413. + for (L2Skill sk : _selfAnalysis.sleepSkills)
  1414. + {
  1415. + int castRange = sk.getCastRange() + combinedCollision;
  1416. + if (_actor.isSkillDisabled(sk.getId())
  1417. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1418. + || (dist2 > castRange * castRange)
  1419. + )
  1420. + continue;
  1421. + if (Rnd.nextInt(100) <= 1)
  1422. + {
  1423. + clientStopMoving(null);
  1424. + _accessor.doCast(sk);
  1425. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1426. + return;
  1427. + }
  1428. + }
  1429. + }
  1430. + if (_secondMostHatedAnalysis.character != null && !_secondMostHatedAnalysis.character.isSleeping())
  1431. + {
  1432. + double secondHatedDist2 = _actor.getPlanDistanceSq(_secondMostHatedAnalysis.character.getX(), _secondMostHatedAnalysis.character.getY());
  1433. + for (L2Skill sk : _selfAnalysis.sleepSkills)
  1434. + {
  1435. + int castRange = sk.getCastRange() + combinedCollision;
  1436. + if (_actor.isSkillDisabled(sk.getId())
  1437. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1438. + || (secondHatedDist2 > castRange * castRange)
  1439. + )
  1440. + continue;
  1441. + if (Rnd.nextInt(100) <= 3)
  1442. + {
  1443. + _actor.setTarget(_secondMostHatedAnalysis.character);
  1444. + clientStopMoving(null);
  1445. + _accessor.doCast(sk);
  1446. + _actor.setTarget(_mostHatedAnalysis.character);
  1447. + return;
  1448. + }
  1449. + }
  1450. + }
  1451. + if (!_mostHatedAnalysis.character.isRooted())
  1452. + {
  1453. + for (L2Skill sk : _selfAnalysis.rootSkills)
  1454. + {
  1455. + int castRange = sk.getCastRange() + combinedCollision;
  1456. + if (_actor.isSkillDisabled(sk.getId())
  1457. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1458. + || (dist2 > castRange * castRange)
  1459. + )
  1460. + continue;
  1461. + if (Rnd.nextInt(100) <= (_mostHatedAnalysis.isSlower ? 3 : 8));
  1462. + {
  1463. + clientStopMoving(null);
  1464. + _accessor.doCast(sk);
  1465. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1466. + return;
  1467. + }
  1468. + }
  1469. + }
  1470. + if (!_mostHatedAnalysis.character.isAttackingDisabled())
  1471. + {
  1472. + for (L2Skill sk : _selfAnalysis.generalDisablers)
  1473. + {
  1474. + int castRange = sk.getCastRange() + combinedCollision;
  1475. + if (_actor.isSkillDisabled(sk.getId())
  1476. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1477. + || (dist2 > castRange * castRange)
  1478. + )
  1479. + continue;
  1480. + if (Rnd.nextInt(100) <= ((_selfAnalysis.isFighter && _actor.isRooted()) ? 15 : 7))
  1481. + {
  1482. + clientStopMoving(null);
  1483. + _accessor.doCast(sk);
  1484. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1485. + return;
  1486. + }
  1487. + }
  1488. + }
  1489. + if (_actor.getCurrentHp() < _actor.getMaxHp()*0.4)
  1490. + {
  1491. + for (L2Skill sk : _selfAnalysis.healSkills)
  1492. + {
  1493. + if (_actor.isSkillDisabled(sk.getId())
  1494. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1495. + )
  1496. + continue;
  1497. + int chance = 7;
  1498. + if (_mostHatedAnalysis.character.isAttackingDisabled()) chance += 10;
  1499. + if (_secondMostHatedAnalysis.character == null || _secondMostHatedAnalysis.character.isAttackingDisabled()) chance += 10;
  1500. + if (Rnd.nextInt(100) <= chance)
  1501. + {
  1502. + _actor.setTarget(_actor);
  1503. + clientStopMoving(null);
  1504. + _accessor.doCast(sk);
  1505. + _actor.setTarget(_mostHatedAnalysis.character);
  1506. + return;
  1507. + }
  1508. + }
  1509. + }
  1510. +
  1511. + // chance decision for launching long range skills
  1512. + int castingChance = 5;
  1513. + if (_selfAnalysis.isMage) castingChance = 50; // mages
  1514. + if (_selfAnalysis.isBalanced)
  1515. + {
  1516. + if (!_mostHatedAnalysis.isFighter) // advance to mages
  1517. + castingChance = 15;
  1518. + else
  1519. + castingChance = 25; // stay away from fighters
  1520. + }
  1521. + if (_selfAnalysis.isFighter)
  1522. + {
  1523. + if(_mostHatedAnalysis.isMage)
  1524. + castingChance = 3;
  1525. + else
  1526. + castingChance = 7;
  1527. + if (_actor.isRooted())
  1528. + castingChance = 20; // doesn't matter if no success first round
  1529. + }
  1530. + for (L2Skill sk : _selfAnalysis.generalSkills)
  1531. + {
  1532. +
  1533. + int castRange = sk.getCastRange() + combinedCollision;
  1534. + if (_actor.isSkillDisabled(sk.getId())
  1535. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1536. + || (dist2 > castRange * castRange)
  1537. + )
  1538. + continue;
  1539. +
  1540. + if (Rnd.nextInt(100) <= castingChance)
  1541. + {
  1542. + clientStopMoving(null);
  1543. + _accessor.doCast(sk);
  1544. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1545. + return;
  1546. + }
  1547. + }
  1548. + }
  1549. +
  1550. + // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
  1551. + if (_selfAnalysis.isMage)
  1552. + {
  1553. + if (_actor.isMuted()) return;
  1554. + range = _selfAnalysis.maxCastRange;
  1555. + }
  1556. + if (_mostHatedAnalysis.character.isMoving()) range -= 100; if (range < 5) range = 5;
  1557. + moveToPawn(getAttackTarget(), range);
  1558. + return;
  1559. + }
  1560. + // **************************************************
  1561. + // Else, if this is close enough for physical attacks
  1562. + else
  1563. + {
  1564. + // In case many mobs are trying to hit from same place, move a bit,
  1565. + // circling around the target
  1566. + if (Rnd.nextInt(100) <= 33) // check it once per 3 seconds
  1567. + {
  1568. + for (L2Object nearby : _actor.getKnownList().getKnownCharactersInRadius(20))
  1569. + {
  1570. + if (nearby instanceof L2Attackable
  1571. + && nearby != getAttackTarget())
  1572. + {
  1573. + int diffx = Rnd.get(combinedCollision, combinedCollision+40);
  1574. + if (Rnd.get(10)<5) diffx = -diffx;
  1575. + int diffy = Rnd.get(combinedCollision, combinedCollision+40);
  1576. + if (Rnd.get(10)<5) diffy = -diffy;
  1577. + moveTo(getAttackTarget().getX() + diffx, getAttackTarget().getY()
  1578. + + diffy, getAttackTarget().getZ());
  1579. + return;
  1580. + }
  1581. + }
  1582. + }
  1583. +
  1584. + // Calculate a new attack timeout.
  1585. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1586. +
  1587. + // check for close combat skills && heal/buff skills
  1588. +
  1589. + if (!_mostHatedAnalysis.isCanceled)
  1590. {
  1591. - _actor.setTarget(getAttackTarget());
  1592. - skills = _actor.getAllSkills();
  1593. - dist2 = _actor.getPlanDistanceSq(getAttackTarget().getX(), getAttackTarget().getY());
  1594. - range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getAttackTarget().getTemplate().collisionRadius;
  1595. + for (L2Skill sk : _selfAnalysis.cancelSkills)
  1596. + {
  1597. + if ((_actor.isMuted() && sk.isMagic())
  1598. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1599. + continue;
  1600. + int castRange = sk.getCastRange() + combinedCollision;
  1601. + if (_actor.isSkillDisabled(sk.getId())
  1602. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1603. + || (dist2 > castRange * castRange))
  1604. + continue;
  1605. + if (Rnd.nextInt(100) <= 8)
  1606. + {
  1607. + clientStopMoving(null);
  1608. + _accessor.doCast(sk);
  1609. + _mostHatedAnalysis.isCanceled = true;
  1610. + return;
  1611. + }
  1612. + }
  1613. + }
  1614. + if (this._selfAnalysis.lastDebuffTick+60 < GameTimeController.getGameTicks())
  1615. + {
  1616. + for (L2Skill sk : _selfAnalysis.debuffSkills)
  1617. + {
  1618. + if ((_actor.isMuted() && sk.isMagic())
  1619. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1620. + continue;
  1621. + int castRange = sk.getCastRange() + combinedCollision;
  1622. + if (_actor.isSkillDisabled(sk.getId())
  1623. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1624. + || (dist2 > castRange * castRange))
  1625. + continue;
  1626. + int chance = 5;
  1627. + if (_selfAnalysis.isFighter && _mostHatedAnalysis.isMage)
  1628. + chance = 3;
  1629. + if (_selfAnalysis.isFighter && _mostHatedAnalysis.isArcher)
  1630. + chance = 3;
  1631. + if (_selfAnalysis.isMage && !_mostHatedAnalysis.isMage)
  1632. + chance = 4;
  1633. + if (_mostHatedAnalysis.isMagicResistant) chance /= 2;
  1634. + if (sk.getCastRange() < 200) chance += 3;
  1635. + if (Rnd.nextInt(100) <= chance)
  1636. + {
  1637. + clientStopMoving(null);
  1638. + _accessor.doCast(sk);
  1639. + _selfAnalysis.lastDebuffTick = GameTimeController.getGameTicks();
  1640. + return;
  1641. + }
  1642. + }
  1643. }
  1644. - catch (NullPointerException e)
  1645. + if (!_mostHatedAnalysis.character.isMuted() && (_mostHatedAnalysis.isMage || _mostHatedAnalysis.isBalanced))
  1646. {
  1647. - //_log.warning("AttackableAI: Attack target is NULL.");
  1648. - setIntention(AI_INTENTION_ACTIVE);
  1649. - return;
  1650. + for (L2Skill sk : _selfAnalysis.muteSkills)
  1651. + {
  1652. + if ((_actor.isMuted() && sk.isMagic())
  1653. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1654. + continue;
  1655. + int castRange = sk.getCastRange() + combinedCollision;
  1656. + if (_actor.isSkillDisabled(sk.getId())
  1657. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1658. + || (dist2 > castRange * castRange))
  1659. + continue;
  1660. + if (Rnd.nextInt(100) <= 7)
  1661. + {
  1662. + clientStopMoving(null);
  1663. + _accessor.doCast(sk);
  1664. + return;
  1665. + }
  1666. + }
  1667. + }
  1668. + if (_secondMostHatedAnalysis.character != null && !_secondMostHatedAnalysis.character.isMuted() && (_secondMostHatedAnalysis.isMage || _secondMostHatedAnalysis.isBalanced))
  1669. + {
  1670. + double secondHatedDist2 = _actor.getPlanDistanceSq(_secondMostHatedAnalysis.character.getX(), _secondMostHatedAnalysis.character.getY());
  1671. + for (L2Skill sk : _selfAnalysis.muteSkills)
  1672. + {
  1673. + if ((_actor.isMuted() && sk.isMagic())
  1674. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1675. + continue;
  1676. + int castRange = sk.getCastRange() + combinedCollision;
  1677. + if (_actor.isSkillDisabled(sk.getId())
  1678. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1679. + || (secondHatedDist2 > castRange * castRange))
  1680. + continue;
  1681. + if (Rnd.nextInt(100) <= 3)
  1682. + {
  1683. + _actor.setTarget(_secondMostHatedAnalysis.character);
  1684. + clientStopMoving(null);
  1685. + _accessor.doCast(sk);
  1686. + _actor.setTarget(_mostHatedAnalysis.character);
  1687. + return;
  1688. + }
  1689. + }
  1690. }
  1691. -
  1692. - L2Weapon weapon = _actor.getActiveWeaponItem();
  1693. - if (weapon != null && weapon.getItemType() == L2WeaponType.BOW)
  1694. + if (_secondMostHatedAnalysis.character != null && !_secondMostHatedAnalysis.character.isSleeping())
  1695. {
  1696. - // Micht: kepping this one otherwise we should do 2 sqrt
  1697. - double distance2 = _actor.getPlanDistanceSq(getAttackTarget().getX(), getAttackTarget().getY());
  1698. - if (distance2 <= 10000)
  1699. - {
  1700. - int chance = 5;
  1701. - if (chance >= Rnd.get(100))
  1702. - {
  1703. - int posX = _actor.getX();
  1704. - int posY = _actor.getY();
  1705. - int posZ = _actor.getZ();
  1706. - double distance = Math.sqrt(distance2); // This way, we only do the sqrt if we need it
  1707. -
  1708. - int signx=-1;
  1709. - int signy=-1;
  1710. - if (_actor.getX()>getAttackTarget().getX())
  1711. - signx=1;
  1712. - if (_actor.getY()>getAttackTarget().getY())
  1713. - signy=1;
  1714. - posX += Math.round((float)((signx * ((range / 2) + (Rnd.get(range)))) - distance));
  1715. - posY += Math.round((float)((signy * ((range / 2) + (Rnd.get(range)))) - distance));
  1716. - setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(posX, posY, posZ, 0));
  1717. - return;
  1718. - }
  1719. - }
  1720. + double secondHatedDist2 = _actor.getPlanDistanceSq(_secondMostHatedAnalysis.character.getX(), _secondMostHatedAnalysis.character.getY());
  1721. + for (L2Skill sk : _selfAnalysis.sleepSkills)
  1722. + {
  1723. + if ((_actor.isMuted() && sk.isMagic())
  1724. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1725. + continue;
  1726. + int castRange = sk.getCastRange() + combinedCollision;
  1727. + if (_actor.isSkillDisabled(sk.getId())
  1728. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1729. + || (secondHatedDist2 > castRange * castRange))
  1730. + continue;
  1731. + if (Rnd.nextInt(100) <= 4)
  1732. + {
  1733. + _actor.setTarget(_secondMostHatedAnalysis.character);
  1734. + clientStopMoving(null);
  1735. + _accessor.doCast(sk);
  1736. + _actor.setTarget(_mostHatedAnalysis.character);
  1737. + return;
  1738. + }
  1739. + }
  1740. }
  1741. -
  1742. - // Force mobs to attack anybody if confused
  1743. - L2Character hated;
  1744. - if (_actor.isConfused()) hated = getAttackTarget();
  1745. - else hated = ((L2Attackable) _actor).getMostHated();
  1746. -
  1747. - if (hated == null)
  1748. + if (!_mostHatedAnalysis.character.isRooted() && _mostHatedAnalysis.isFighter && !_selfAnalysis.isFighter)
  1749. {
  1750. - setIntention(AI_INTENTION_ACTIVE);
  1751. - return;
  1752. + for (L2Skill sk : _selfAnalysis.rootSkills)
  1753. + {
  1754. + if ((_actor.isMuted() && sk.isMagic())
  1755. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1756. + continue;
  1757. + int castRange = sk.getCastRange() + combinedCollision;
  1758. + if (_actor.isSkillDisabled(sk.getId())
  1759. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1760. + || (dist2 > castRange * castRange))
  1761. + continue;
  1762. + if (Rnd.nextInt(100) <= 4)
  1763. + {
  1764. + clientStopMoving(null);
  1765. + _accessor.doCast(sk);
  1766. + return;
  1767. + }
  1768. + }
  1769. }
  1770. - if (hated != getAttackTarget())
  1771. + if (!_mostHatedAnalysis.character.isAttackingDisabled())
  1772. {
  1773. - setAttackTarget(hated);
  1774. + for (L2Skill sk : _selfAnalysis.generalDisablers)
  1775. + {
  1776. + if ((_actor.isMuted() && sk.isMagic())
  1777. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1778. + continue;
  1779. + int castRange = sk.getCastRange() + combinedCollision;
  1780. + if (_actor.isSkillDisabled(sk.getId())
  1781. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1782. + || (dist2 > castRange * castRange))
  1783. + continue;
  1784. + if (Rnd.nextInt(100) <= ((sk.getCastRange() < 200) ? 10 : 7))
  1785. + {
  1786. + clientStopMoving(null);
  1787. + _accessor.doCast(sk);
  1788. + return;
  1789. + }
  1790. + }
  1791. }
  1792. - // We should calculate new distance cuz mob can have changed the target
  1793. - dist2 = _actor.getPlanDistanceSq(hated.getX(), hated.getY());
  1794. -
  1795. - if (hated.isMoving()) range += 50;
  1796. - // Check if the actor isn't far from target
  1797. - if (dist2 > range*range)
  1798. + if (_actor.getCurrentHp() < _actor.getMaxHp()*0.4)
  1799. {
  1800. - // check for long ranged skills and heal/buff skills
  1801. - if (!_actor.isMuted() &&
  1802. - (!Config.ALT_GAME_MOB_ATTACK_AI || (_actor instanceof L2MonsterInstance && Rnd.nextInt(100) <= 5))
  1803. - )
  1804. - for (L2Skill sk : skills)
  1805. - {
  1806. - int castRange = sk.getCastRange();
  1807. -
  1808. - if (((sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) || (dist2 >= castRange * castRange / 9.0)
  1809. - && (dist2 <= castRange * castRange) && (castRange > 70))
  1810. - && !_actor.isSkillDisabled(sk.getId())
  1811. - && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)
  1812. - && !sk.isPassive()
  1813. - && Rnd.nextInt(100) <= 5)
  1814. - {
  1815. - L2Object OldTarget = _actor.getTarget();
  1816. - if (sk.getSkillType() == L2Skill.SkillType.BUFF
  1817. - || sk.getSkillType() == L2Skill.SkillType.HEAL)
  1818. - {
  1819. - boolean useSkillSelf = true;
  1820. - if (sk.getSkillType() == L2Skill.SkillType.HEAL
  1821. - && _actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5))
  1822. - {
  1823. - useSkillSelf = false;
  1824. - break;
  1825. - }
  1826. - if (sk.getSkillType() == L2Skill.SkillType.BUFF)
  1827. - {
  1828. - L2Effect[] effects = _actor.getAllEffects();
  1829. - for (int i = 0; effects != null && i < effects.length; i++)
  1830. - {
  1831. - L2Effect effect = effects[i];
  1832. - if (effect.getSkill() == sk)
  1833. - {
  1834. - useSkillSelf = false;
  1835. - break;
  1836. - }
  1837. - }
  1838. - }
  1839. - if (useSkillSelf) _actor.setTarget(_actor);
  1840. - }
  1841. -
  1842. - clientStopMoving(null);
  1843. - _accessor.doCast(sk);
  1844. - _actor.setTarget(OldTarget);
  1845. - return;
  1846. - }
  1847. - }
  1848. -
  1849. - // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
  1850. - if (hated.isMoving()) range -= 100; if (range < 5) range = 5;
  1851. - moveToPawn(getAttackTarget(), range);
  1852. - return;
  1853. + for (L2Skill sk : _selfAnalysis.healSkills)
  1854. + {
  1855. + if ((_actor.isMuted() && sk.isMagic())
  1856. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1857. + continue;
  1858. + if (_actor.isSkillDisabled(sk.getId())
  1859. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk))
  1860. + continue;
  1861. + int chance = 7;
  1862. + if (_mostHatedAnalysis.character.isAttackingDisabled()) chance += 10;
  1863. + if (_secondMostHatedAnalysis.character == null || _secondMostHatedAnalysis.character.isAttackingDisabled()) chance += 10;
  1864. + if (Rnd.nextInt(100) <= chance)
  1865. + {
  1866. + _actor.setTarget(_actor);
  1867. + clientStopMoving(null);
  1868. + _accessor.doCast(sk);
  1869. + _actor.setTarget(_mostHatedAnalysis.character);
  1870. + return;
  1871. + }
  1872. + }
  1873. }
  1874. - // Else, if this is close enough to attack
  1875. - else
  1876. + for (L2Skill sk : _selfAnalysis.generalSkills)
  1877. {
  1878. - _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  1879. -
  1880. - // check for close combat skills && heal/buff skills
  1881. - if (!_actor.isMuted() /*&& _rnd.nextInt(100) <= 5*/)
  1882. + if ((_actor.isMuted() && sk.isMagic())
  1883. + || (_actor.isPsychicalMuted() && !sk.isMagic()))
  1884. + continue;
  1885. + int castRange = sk.getCastRange() + combinedCollision;
  1886. + if (_actor.isSkillDisabled(sk.getId())
  1887. + || _actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)
  1888. + || (dist2 > castRange * castRange))
  1889. + continue;
  1890. +
  1891. + // chance decision for launching general skills in melee fight
  1892. + // close range skills should be higher, long range lower
  1893. + int castingChance = 5;
  1894. + if (_selfAnalysis.isMage)
  1895. {
  1896. - boolean useSkillSelf = true;;
  1897. - for (L2Skill sk : skills)
  1898. - {
  1899. - if (/*sk.getCastRange() >= dist && sk.getCastRange() <= 70 && */!sk.isPassive()
  1900. - && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)
  1901. - && !_actor.isSkillDisabled(sk.getId()) && (Rnd.nextInt(100) <= 8
  1902. - || (_actor instanceof L2PenaltyMonsterInstance && Rnd.nextInt(100) <= 20)))
  1903. - {
  1904. - L2Object OldTarget = _actor.getTarget();
  1905. - if (sk.getSkillType() == L2Skill.SkillType.BUFF
  1906. - || sk.getSkillType() == L2Skill.SkillType.HEAL)
  1907. - {
  1908. - useSkillSelf = true;
  1909. - if (sk.getSkillType() == L2Skill.SkillType.HEAL
  1910. - && _actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5))
  1911. - {
  1912. - useSkillSelf = false;
  1913. - break;
  1914. - }
  1915. - if (sk.getSkillType() == L2Skill.SkillType.BUFF)
  1916. - {
  1917. - L2Effect[] effects = _actor.getAllEffects();
  1918. - for (int i = 0; effects != null && i < effects.length; i++)
  1919. - {
  1920. - L2Effect effect = effects[i];
  1921. - if (effect.getSkill() == sk)
  1922. - {
  1923. - useSkillSelf = false;
  1924. - break;
  1925. - }
  1926. - }
  1927. - }
  1928. - if (useSkillSelf) _actor.setTarget(_actor);
  1929. - }
  1930. - // GeoData Los Check here
  1931. - if (!useSkillSelf && !GeoData.getInstance().canSeeTarget(_actor, _actor.getTarget()))
  1932. - return;
  1933. - clientStopMoving(null);
  1934. - _accessor.doCast(sk);
  1935. - _actor.setTarget(OldTarget);
  1936. - return;
  1937. - }
  1938. - }
  1939. + if (sk.getCastRange() < 200) castingChance = 35;
  1940. + else castingChance = 25; // mages
  1941. }
  1942. -
  1943. - // Finally, physical attacks
  1944. - clientStopMoving(null);
  1945. - _accessor.doAttack(hated);
  1946. + if (_selfAnalysis.isBalanced)
  1947. + {
  1948. + if (sk.getCastRange() < 200) castingChance = 12;
  1949. + else
  1950. + {
  1951. + if (_mostHatedAnalysis.isMage) // hit mages
  1952. + castingChance = 2;
  1953. + else
  1954. + castingChance = 5;
  1955. + }
  1956. +
  1957. + }
  1958. + if (_selfAnalysis.isFighter)
  1959. + {
  1960. + if (sk.getCastRange() < 200) castingChance = 12;
  1961. + else
  1962. + {
  1963. + if(_mostHatedAnalysis.isMage)
  1964. + castingChance = 1;
  1965. + else
  1966. + castingChance = 3;
  1967. + }
  1968. + }
  1969. + if (Rnd.nextInt(100) <= castingChance)
  1970. + {
  1971. + clientStopMoving(null);
  1972. + _accessor.doCast(sk);
  1973. + return;
  1974. + }
  1975. }
  1976. +
  1977. + // Finally, physical attacks
  1978. + clientStopMoving(null);
  1979. + _accessor.doAttack(getAttackTarget());
  1980. }
  1981. }
  1982.  
  1983. @@ -873,4 +1433,5 @@
  1984. {
  1985. _globalAggro = value;
  1986. }
  1987. +
  1988. }
  1989. Index: java/net/sf/l2j/gameserver/ai/L2CharacterAI.java
  1990. ===================================================================
  1991. --- java/net/sf/l2j/gameserver/ai/L2CharacterAI.java (revision 1770)
  1992. +++ java/net/sf/l2j/gameserver/ai/L2CharacterAI.java (revision 1771)
  1993. @@ -14,6 +14,8 @@
  1994. */
  1995. package net.sf.l2j.gameserver.ai;
  1996.  
  1997. +import java.util.List;
  1998. +import javolution.util.FastList;
  1999. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
  2000. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
  2001. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
  2002. @@ -32,10 +34,17 @@
  2003. import net.sf.l2j.gameserver.model.L2Skill;
  2004. import net.sf.l2j.gameserver.model.actor.instance.L2BoatInstance;
  2005. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  2006. +import net.sf.l2j.gameserver.model.actor.instance.L2GrandBossInstance;
  2007. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  2008. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  2009. +import net.sf.l2j.gameserver.model.actor.instance.L2RaidBossInstance;
  2010. +import net.sf.l2j.gameserver.model.actor.instance.L2SiegeGuardInstance;
  2011. import net.sf.l2j.gameserver.serverpackets.AutoAttackStop;
  2012. import net.sf.l2j.gameserver.taskmanager.AttackStanceTaskManager;
  2013. +import net.sf.l2j.gameserver.templates.L2NpcTemplate;
  2014. +import net.sf.l2j.gameserver.templates.L2Weapon;
  2015. +import net.sf.l2j.gameserver.templates.L2WeaponType;
  2016. +import net.sf.l2j.util.Rnd;
  2017.  
  2018. /**
  2019. * This class manages AI of L2Character.<BR><BR>
  2020. @@ -1030,4 +1039,202 @@
  2021. }
  2022. return false;
  2023. }
  2024. +
  2025. + protected class SelfAnalysis
  2026. + {
  2027. + public boolean isMage = false;
  2028. + public boolean isBalanced;
  2029. + public boolean isArcher = false;
  2030. + public boolean isFighter = false;
  2031. + public boolean cannotMoveOnLand = false;
  2032. + public List<L2Skill> generalSkills = new FastList<L2Skill>();
  2033. + public List<L2Skill> buffSkills = new FastList<L2Skill>();
  2034. + public int lastBuffTick = 0;
  2035. + public List<L2Skill> debuffSkills = new FastList<L2Skill>();
  2036. + public int lastDebuffTick = 0;
  2037. + public List<L2Skill> cancelSkills = new FastList<L2Skill>();
  2038. + public List<L2Skill> healSkills = new FastList<L2Skill>();
  2039. + //public List<L2Skill> trickSkills = new FastList<L2Skill>();
  2040. + public List<L2Skill> generalDisablers = new FastList<L2Skill>();
  2041. + public List<L2Skill> sleepSkills = new FastList<L2Skill>();
  2042. + public List<L2Skill> rootSkills = new FastList<L2Skill>();
  2043. + public List<L2Skill> muteSkills = new FastList<L2Skill>();
  2044. + public List<L2Skill> resurrectSkills = new FastList<L2Skill>();
  2045. + public boolean hasHealOrResurrect = false;
  2046. + public boolean hasLongRangeSkills = false;
  2047. + public boolean hasLongRangeDamageSkills = false;
  2048. + public int maxCastRange = 0;
  2049. +
  2050. + public SelfAnalysis()
  2051. + {
  2052. + }
  2053. +
  2054. + public void Init()
  2055. + {
  2056. + switch (((L2NpcTemplate)_actor.getTemplate()).AI)
  2057. + {
  2058. + case FIGHTER:
  2059. + isFighter = true;
  2060. + break;
  2061. + case MAGE:
  2062. + isMage = true;
  2063. + break;
  2064. + case BALANCED:
  2065. + isBalanced = true;
  2066. + break;
  2067. + case ARCHER:
  2068. + isArcher = true;
  2069. + break;
  2070. + default:
  2071. + isFighter = true;
  2072. + break;
  2073. + }
  2074. + // water movement analysis
  2075. + if (_actor instanceof L2NpcInstance)
  2076. + {
  2077. + // well, lol..
  2078. + if (((L2NpcInstance)_actor).getNpcId() == 20314) // great white shark
  2079. + cannotMoveOnLand = true;
  2080. + }
  2081. + // skill analysis
  2082. + for (L2Skill sk : _actor.getAllSkills())
  2083. + {
  2084. + int castRange = sk.getCastRange();
  2085. + boolean isLongRangeDamageSkill = false;
  2086. + switch(sk.getSkillType())
  2087. + {
  2088. + case HEAL:
  2089. + case HEAL_PERCENT:
  2090. + case HEAL_STATIC:
  2091. + case BALANCE_LIFE:
  2092. + case HOT:
  2093. + healSkills.add(sk);
  2094. + hasHealOrResurrect = true;
  2095. + continue; // won't be considered something for fighting
  2096. + case BUFF:
  2097. + buffSkills.add(sk);
  2098. + continue; // won't be considered something for fighting
  2099. + case PARALYZE:
  2100. + case STUN:
  2101. + generalDisablers.add(sk);
  2102. + break;
  2103. + case MUTE:
  2104. + muteSkills.add(sk);
  2105. + break;
  2106. + case SLEEP:
  2107. + sleepSkills.add(sk);
  2108. + break;
  2109. + case ROOT:
  2110. + rootSkills.add(sk);
  2111. + break;
  2112. + case FEAR: // could be used as an alternative for healing?
  2113. + case CONFUSION:
  2114. + // trickSkills.add(sk);
  2115. + case DEBUFF:
  2116. + debuffSkills.add(sk);
  2117. + break;
  2118. + case CANCEL:
  2119. + case MAGE_BANE:
  2120. + case WARRIOR_BANE:
  2121. + case NEGATE:
  2122. + cancelSkills.add(sk);
  2123. + break;
  2124. + case RESURRECT:
  2125. + resurrectSkills.add(sk);
  2126. + hasHealOrResurrect = true;
  2127. + break;
  2128. + case NOTDONE:
  2129. + continue; // won't be considered something for fighting
  2130. + default:
  2131. + if (!sk.isPassive()) {
  2132. + generalSkills.add(sk);
  2133. + isLongRangeDamageSkill = true;
  2134. + }
  2135. + break;
  2136. + }
  2137. + if (castRange > 70) {
  2138. + hasLongRangeSkills = true;
  2139. + if (isLongRangeDamageSkill)
  2140. + hasLongRangeDamageSkills = true;
  2141. + }
  2142. + if (castRange > maxCastRange) maxCastRange = castRange;
  2143. +
  2144. + }
  2145. + // Because of missing skills, some mages/balanced cannot play like mages
  2146. + if (!hasLongRangeDamageSkills && isMage)
  2147. + {
  2148. + isBalanced = true;
  2149. + isMage = false;
  2150. + isFighter = false;
  2151. + }
  2152. + if (!hasLongRangeSkills && (isMage || isBalanced))
  2153. + {
  2154. + isBalanced = false;
  2155. + isMage = false;
  2156. + isFighter = true;
  2157. + }
  2158. + if (generalSkills.isEmpty() && isMage)
  2159. + {
  2160. + isBalanced = true;
  2161. + isMage = false;
  2162. + }
  2163. + }
  2164. + }
  2165. +
  2166. + protected class TargetAnalysis
  2167. + {
  2168. + public L2Character character;
  2169. + public boolean isMage;
  2170. + public boolean isBalanced;
  2171. + public boolean isArcher;
  2172. + public boolean isFighter;
  2173. + public boolean isCanceled;
  2174. + public boolean isSlower;
  2175. + public boolean isMagicResistant;
  2176. +
  2177. + public TargetAnalysis()
  2178. + {
  2179. + }
  2180. +
  2181. + public void Update(L2Character target)
  2182. + {
  2183. + // update status once in 4 seconds
  2184. + if (target == character && Rnd.nextInt(100) > 25)
  2185. + return;
  2186. + character = target;
  2187. + if (target == null)
  2188. + return;
  2189. + isMage = false;
  2190. + isBalanced = false;
  2191. + isArcher = false;
  2192. + isFighter = false;
  2193. + isCanceled = false;
  2194. +
  2195. + if (target.getMAtk(null, null) > 1.5*target.getPAtk(null))
  2196. + isMage = true;
  2197. + else if (target.getPAtk(null)*0.8 < target.getMAtk(null, null)
  2198. + || target.getMAtk(null, null)*0.8 > target.getPAtk(null))
  2199. + {
  2200. + isBalanced = true;
  2201. + }
  2202. + else
  2203. + {
  2204. + L2Weapon weapon = target.getActiveWeaponItem();
  2205. + if (weapon != null && (weapon.getItemType() == L2WeaponType.BOW || weapon.getItemType() == L2WeaponType.CROSSBOW))
  2206. + isArcher = true;
  2207. + else
  2208. + isFighter = true;
  2209. + }
  2210. + if (target.getRunSpeed() < _actor.getRunSpeed()-3)
  2211. + isSlower = true;
  2212. + else
  2213. + isSlower = false;
  2214. + if (target.getMDef(null, null)*1.2 > _actor.getMAtk(null, null))
  2215. + isMagicResistant = true;
  2216. + else
  2217. + isMagicResistant = false;
  2218. + if (target.getBuffCount() < 4)
  2219. + isCanceled = true;
  2220. + }
  2221. + }
  2222. }
  2223. Index: java/net/sf/l2j/gameserver/ai/L2SiegeGuardAI.java
  2224. ===================================================================
  2225. --- java/net/sf/l2j/gameserver/ai/L2SiegeGuardAI.java (revision 1770)
  2226. +++ java/net/sf/l2j/gameserver/ai/L2SiegeGuardAI.java (revision 1771)
  2227. @@ -32,10 +32,10 @@
  2228. import net.sf.l2j.gameserver.model.L2Summon;
  2229. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  2230. import net.sf.l2j.gameserver.model.actor.instance.L2FolkInstance;
  2231. -import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  2232. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  2233. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  2234. import net.sf.l2j.gameserver.model.actor.instance.L2SiegeGuardInstance;
  2235. +import net.sf.l2j.gameserver.util.Util;
  2236. import net.sf.l2j.util.Rnd;
  2237.  
  2238. /**
  2239. @@ -52,7 +52,11 @@
  2240. /** The L2Attackable AI task executed every 1s (call onEvtThink method)*/
  2241. private Future<?> _aiTask;
  2242.  
  2243. - /** The delay after wich the attacked is stopped */
  2244. + /** For attack AI, analysis of mob and its targets */
  2245. + private SelfAnalysis _selfAnalysis = new SelfAnalysis();
  2246. + //private TargetAnalysis _mostHatedAnalysis = new TargetAnalysis();
  2247. +
  2248. + /** The delay after which the attacked is stopped */
  2249. private int _attackTimeout;
  2250.  
  2251. /** The L2Attackable aggro counter */
  2252. @@ -72,10 +76,9 @@
  2253. public L2SiegeGuardAI(L2Character.AIAccessor accessor)
  2254. {
  2255. super(accessor);
  2256. -
  2257. + _selfAnalysis.Init();
  2258. _attackTimeout = Integer.MAX_VALUE;
  2259. _globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
  2260. -
  2261. _attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
  2262. }
  2263.  
  2264. @@ -125,9 +128,18 @@
  2265. target instanceof L2SiegeGuardInstance ||
  2266. target instanceof L2FolkInstance ||
  2267. target instanceof L2DoorInstance ||
  2268. - target.isAlikeDead() ||
  2269. - target.isInvul()) return false;
  2270. + target.isAlikeDead()) return false;
  2271.  
  2272. + // Check if the target isn't invulnerable
  2273. + if (target.isInvul())
  2274. + {
  2275. + // However EffectInvincible requires to check GMs specially
  2276. + if (target instanceof L2PcInstance && ((L2PcInstance)target).isGM())
  2277. + return false;
  2278. + if (target instanceof L2Summon && ((L2Summon)target).getOwner().isGM())
  2279. + return false;
  2280. + }
  2281. +
  2282. // Get the owner if the target is a summon
  2283. if (target instanceof L2Summon)
  2284. {
  2285. @@ -143,7 +155,7 @@
  2286. if (((L2PcInstance) target).isSilentMoving()
  2287. && !_actor.isInsideRadius(target, 250, false, false)) return false;
  2288. }
  2289. - // Los Check Here
  2290. + // Los Check Here
  2291. return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
  2292.  
  2293. }
  2294. @@ -263,7 +275,8 @@
  2295. L2Character hated;
  2296. if (_actor.isConfused()) hated = _attackTarget; // Force mobs to attak anybody if confused
  2297. else hated = npc.getMostHated();
  2298. -
  2299. + //_mostHatedAnalysis.Update(hated);
  2300. +
  2301. // Order to the L2Attackable to attack the target
  2302. if (hated != null)
  2303. {
  2304. @@ -286,12 +299,174 @@
  2305. // Order to the L2SiegeGuardInstance to return to its home location because there's no target to attack
  2306. ((L2SiegeGuardInstance) _actor).returnHome();
  2307. return;
  2308. + }
  2309.  
  2310. + /**
  2311. + * Manage AI attack thinks of a L2Attackable (called by onEvtThink).<BR><BR>
  2312. + *
  2313. + * <B><U> Actions</U> :</B><BR><BR>
  2314. + * <li>Update the attack timeout if actor is running</li>
  2315. + * <li>If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE</li>
  2316. + * <li>Call all L2Object of its Faction inside the Faction Range</li>
  2317. + * <li>Chose a target and order to attack it with magic skill or physical attack</li><BR><BR>
  2318. + *
  2319. + * TODO: Manage casting rules to healer mobs (like Ant Nurses)
  2320. + *
  2321. + */
  2322. + private void thinkAttack()
  2323. + {
  2324. + if (Config.DEBUG)
  2325. + _log.info("L2SiegeGuardAI.thinkAttack(); timeout="
  2326. + + (_attackTimeout - GameTimeController.getGameTicks()));
  2327. +
  2328. + if (_attackTimeout < GameTimeController.getGameTicks())
  2329. + {
  2330. + // Check if the actor is running
  2331. + if (_actor.isRunning())
  2332. + {
  2333. + // Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
  2334. + _actor.setWalking();
  2335. +
  2336. + // Calculate a new attack timeout
  2337. + _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  2338. + }
  2339. + }
  2340. +
  2341. + // Check if target is dead or if timeout is expired to stop this attack
  2342. + if (_attackTarget == null || _attackTarget.isAlikeDead()
  2343. + || _attackTimeout < GameTimeController.getGameTicks())
  2344. + {
  2345. + // Stop hating this target after the attack timeout or if target is dead
  2346. + if (_attackTarget != null)
  2347. + {
  2348. + L2Attackable npc = (L2Attackable) _actor;
  2349. + npc.stopHating(_attackTarget);
  2350. + }
  2351. +
  2352. + // Cancel target and timeout
  2353. + _attackTimeout = Integer.MAX_VALUE;
  2354. + _attackTarget = null;
  2355. +
  2356. + // Set the AI Intention to AI_INTENTION_ACTIVE
  2357. + setIntention(AI_INTENTION_ACTIVE, null, null);
  2358. +
  2359. + _actor.setWalking();
  2360. + return;
  2361. + }
  2362. +
  2363. + factionNotifyAndSupport();
  2364. + attackPrepare();
  2365. }
  2366.  
  2367. + private final void factionNotifyAndSupport()
  2368. + {
  2369. + L2Character target = getAttackTarget();
  2370. + // Call all L2Object of its Faction inside the Faction Range
  2371. + if (((L2NpcInstance) _actor).getFactionId() == null || target == null || _actor == null)
  2372. + return;
  2373. +
  2374. + if (target.isInvul()) return; // speeding it up for siege guards
  2375. +
  2376. + String faction_id = ((L2NpcInstance) _actor).getFactionId();
  2377. +
  2378. + // Go through all L2Character that belong to its faction
  2379. + //for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(((L2NpcInstance) _actor).getFactionRange()+_actor.getTemplate().collisionRadius))
  2380. + for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
  2381. + {
  2382. + if (cha == null) continue;
  2383. +
  2384. + if (!(cha instanceof L2NpcInstance))
  2385. + {
  2386. + if(_selfAnalysis.hasHealOrResurrect && cha instanceof L2PcInstance && ((L2NpcInstance) _actor).getCastle().getSiege().checkIsDefender(((L2PcInstance)cha).getClan()))
  2387. + {
  2388. + // heal friends
  2389. + if (!_actor.isAttackingDisabled()
  2390. + && cha.getCurrentHp() < cha.getMaxHp()*0.6
  2391. + && _actor.getCurrentHp() > _actor.getMaxHp()/2
  2392. + && _actor.getCurrentMp() > _actor.getMaxMp()/2
  2393. + && cha.isInCombat())
  2394. + {
  2395. + for (L2Skill sk : _selfAnalysis.healSkills)
  2396. + {
  2397. + if (_actor.getCurrentMp() < sk.getMpConsume())
  2398. + continue;
  2399. + if (_actor.isSkillDisabled(sk.getId()))
  2400. + continue;
  2401. + if (!Util.checkIfInRange(sk.getCastRange(), _actor, cha, true))
  2402. + continue;
  2403. +
  2404. + int chance = 5;
  2405. + if (chance >= Rnd.get(100)) // chance
  2406. + continue;
  2407. + if (!GeoData.getInstance().canSeeTarget(_actor, cha))
  2408. + break;
  2409. +
  2410. + L2Object OldTarget = _actor.getTarget();
  2411. + _actor.setTarget(cha);
  2412. + clientStopMoving(null);
  2413. + _accessor.doCast(sk);
  2414. + _actor.setTarget(OldTarget);
  2415. + return;
  2416. + }
  2417. + }
  2418. + }
  2419. + continue;
  2420. + }
  2421. +
  2422. + L2NpcInstance npc = (L2NpcInstance) cha;
  2423. +
  2424. + if (faction_id != npc.getFactionId()) continue;
  2425. +
  2426. + if (npc.getAI() != null) // TODO: possibly check not needed
  2427. + {
  2428. + if (Math.abs(target.getZ() - npc.getZ()) < 600
  2429. + //&& _actor.getAttackByList().contains(getAttackTarget())
  2430. + && (npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE
  2431. + || npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE)
  2432. + //limiting aggro for siege guards
  2433. + && target.isInsideRadius(npc, 1500, true, false)
  2434. + && GeoData.getInstance().canSeeTarget(npc, target))
  2435. + {
  2436. + // Notify the L2Object AI with EVT_AGGRESSION
  2437. + npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
  2438. + }
  2439. + // heal friends
  2440. + if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled()
  2441. + && npc.getCurrentHp() < npc.getMaxHp()*0.6
  2442. + && _actor.getCurrentHp() > _actor.getMaxHp()/2
  2443. + && _actor.getCurrentMp() > _actor.getMaxMp()/2
  2444. + && npc.isInCombat())
  2445. + {
  2446. + for (L2Skill sk : _selfAnalysis.healSkills)
  2447. + {
  2448. + if (_actor.getCurrentMp() < sk.getMpConsume())
  2449. + continue;
  2450. + if (_actor.isSkillDisabled(sk.getId()))
  2451. + continue;
  2452. + if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
  2453. + continue;
  2454. +
  2455. + int chance = 4;
  2456. + if (chance >= Rnd.get(100)) // chance
  2457. + continue;
  2458. + if (!GeoData.getInstance().canSeeTarget(_actor, npc))
  2459. + break;
  2460. +
  2461. + L2Object OldTarget = _actor.getTarget();
  2462. + _actor.setTarget(npc);
  2463. + clientStopMoving(null);
  2464. + _accessor.doCast(sk);
  2465. + _actor.setTarget(OldTarget);
  2466. + return;
  2467. + }
  2468. + }
  2469. + }
  2470. + }
  2471. + }
  2472. +
  2473. private void attackPrepare()
  2474. {
  2475. - // Get all information needed to chose between physical or magical attack
  2476. + // Get all information needed to choose between physical or magical attack
  2477. L2Skill[] skills = null;
  2478. double dist_2 = 0;
  2479. int range = 0;
  2480. @@ -303,89 +478,90 @@
  2481. skills = _actor.getAllSkills();
  2482. dist_2 = _actor.getPlanDistanceSq(_attackTarget.getX(), _attackTarget.getY());
  2483. range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + _attackTarget.getTemplate().collisionRadius;
  2484. + if (_attackTarget.isMoving()) range += 50;
  2485. }
  2486. catch (NullPointerException e)
  2487. {
  2488. - //_log.warning("AttackableAI: Attack target is NULL.");
  2489. - _actor.setTarget(null);
  2490. - setIntention(AI_INTENTION_IDLE, null, null);
  2491. - return;
  2492. + //_log.warning("AttackableAI: Attack target is NULL.");
  2493. + _actor.setTarget(null);
  2494. + setIntention(AI_INTENTION_IDLE, null, null);
  2495. + return;
  2496. }
  2497. -
  2498. +
  2499. // never attack defenders
  2500. if(_attackTarget instanceof L2PcInstance && sGuard.getCastle().getSiege().checkIsDefender(((L2PcInstance)_attackTarget).getClan()))
  2501. {
  2502. - // Cancel the target
  2503. - sGuard.stopHating(_attackTarget);
  2504. - _actor.setTarget(null);
  2505. - setIntention(AI_INTENTION_IDLE, null, null);
  2506. - return;
  2507. + // Cancel the target
  2508. + sGuard.stopHating(_attackTarget);
  2509. + _actor.setTarget(null);
  2510. + setIntention(AI_INTENTION_IDLE, null, null);
  2511. + return;
  2512. }
  2513.  
  2514. if (!GeoData.getInstance().canSeeTarget(_actor, _attackTarget))
  2515. - {
  2516. - // Siege guards differ from normal mobs currently:
  2517. - // If target cannot seen, don't attack any more
  2518. - sGuard.stopHating(_attackTarget);
  2519. - _actor.setTarget(null);
  2520. - setIntention(AI_INTENTION_IDLE, null, null);
  2521. - return;
  2522. - }
  2523. + {
  2524. + // Siege guards differ from normal mobs currently:
  2525. + // If target cannot seen, don't attack any more
  2526. + sGuard.stopHating(_attackTarget);
  2527. + _actor.setTarget(null);
  2528. + setIntention(AI_INTENTION_IDLE, null, null);
  2529. + return;
  2530. + }
  2531.  
  2532. // Check if the actor isn't muted and if it is far from target
  2533. - if (!_actor.isMuted() && dist_2 > (range + 20) * (range + 20))
  2534. + if (!_actor.isMuted() && dist_2 > range * range)
  2535. {
  2536. // check for long ranged skills and heal/buff skills
  2537. - if (!Config.ALT_GAME_MOB_ATTACK_AI
  2538. - || (_actor instanceof L2MonsterInstance && Rnd.nextInt(100) <= 5))
  2539. - for (L2Skill sk : skills)
  2540. + for (L2Skill sk : skills)
  2541. + {
  2542. + int castRange = sk.getCastRange();
  2543. +
  2544. + if ((dist_2 <= castRange * castRange)
  2545. + && castRange > 70
  2546. + && !_actor.isSkillDisabled(sk.getId())
  2547. + && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)
  2548. + && !sk.isPassive())
  2549. {
  2550. - int castRange = sk.getCastRange();
  2551. -
  2552. - if (((sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) || (dist_2 >= castRange * castRange / 9)
  2553. - && (dist_2 <= castRange * castRange) && (castRange > 70))
  2554. - && !_actor.isSkillDisabled(sk.getId())
  2555. - && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk) && !sk.isPassive())
  2556. +
  2557. + L2Object OldTarget = _actor.getTarget();
  2558. + if (sk.getSkillType() == L2Skill.SkillType.BUFF
  2559. + || sk.getSkillType() == L2Skill.SkillType.HEAL)
  2560. {
  2561. - L2Object OldTarget = _actor.getTarget();
  2562. - if (sk.getSkillType() == L2Skill.SkillType.BUFF
  2563. - || sk.getSkillType() == L2Skill.SkillType.HEAL)
  2564. + boolean useSkillSelf = true;
  2565. + if (sk.getSkillType() == L2Skill.SkillType.HEAL
  2566. + && _actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5))
  2567. {
  2568. - boolean useSkillSelf = true;
  2569. - if (sk.getSkillType() == L2Skill.SkillType.HEAL
  2570. - && _actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5))
  2571. + useSkillSelf = false;
  2572. + break;
  2573. + }
  2574. + if (sk.getSkillType() == L2Skill.SkillType.BUFF)
  2575. + {
  2576. + L2Effect[] effects = _actor.getAllEffects();
  2577. + for (int i = 0; effects != null && i < effects.length; i++)
  2578. {
  2579. - useSkillSelf = false;
  2580. - break;
  2581. - }
  2582. - if (sk.getSkillType() == L2Skill.SkillType.BUFF)
  2583. - {
  2584. - L2Effect[] effects = _actor.getAllEffects();
  2585. - for (int i = 0; effects != null && i < effects.length; i++)
  2586. + L2Effect effect = effects[i];
  2587. + if (effect.getSkill() == sk)
  2588. {
  2589. - L2Effect effect = effects[i];
  2590. - if (effect.getSkill() == sk)
  2591. - {
  2592. - useSkillSelf = false;
  2593. - break;
  2594. - }
  2595. + useSkillSelf = false;
  2596. + break;
  2597. }
  2598. }
  2599. - if (useSkillSelf) _actor.setTarget(_actor);
  2600. }
  2601. + if (useSkillSelf) _actor.setTarget(_actor);
  2602. + }
  2603.  
  2604. - clientStopMoving(null);
  2605. - _accessor.doCast(sk);
  2606. - _actor.setTarget(OldTarget);
  2607. - return;
  2608. - }
  2609. + clientStopMoving(null);
  2610. + _accessor.doCast(sk);
  2611. + _actor.setTarget(OldTarget);
  2612. + return;
  2613. }
  2614. + }
  2615.  
  2616. // Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
  2617. if (!(_actor.isAttackingNow()) && (_actor.getRunSpeed() == 0)
  2618. && (_actor.getKnownList().knowsObject(_attackTarget)))
  2619. {
  2620. - // Cancel the target
  2621. + // Cancel the target
  2622. _actor.getKnownList().removeKnownObject(_attackTarget);
  2623. _actor.setTarget(null);
  2624. setIntention(AI_INTENTION_IDLE, null, null);
  2625. @@ -409,10 +585,16 @@
  2626. }
  2627. else // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
  2628. {
  2629. - // Temporary hack for preventing guards jumping off towers,
  2630. - // before replacing this with effective geodata checks and AI modification
  2631. - if(dz*dz < 170*170) // normally 130 if guard z coordinates correct
  2632. - moveToPawn(_attackTarget, range);
  2633. + // Temporary hack for preventing guards jumping off towers,
  2634. + // before replacing this with effective geodata checks and AI modification
  2635. + if(dz*dz < 170*170) // normally 130 if guard z coordinates correct
  2636. + {
  2637. + if (_selfAnalysis.isMage) range = _selfAnalysis.maxCastRange-50;
  2638. + if (_attackTarget.isMoving())
  2639. + moveToPawn(_attackTarget, range-70);
  2640. + else
  2641. + moveToPawn(_attackTarget, range);
  2642. + }
  2643. }
  2644. }
  2645.  
  2646. @@ -420,19 +602,25 @@
  2647.  
  2648. }
  2649. // Else, if the actor is muted and far from target, just "move to pawn"
  2650. - else if (_actor.isMuted() && dist_2 > (range + 20) * (range + 20))
  2651. + else if (_actor.isMuted() && dist_2 > range * range)
  2652. {
  2653. - // Temporary hack for preventing guards jumping off towers,
  2654. - // before replacing this with effective geodata checks and AI modification
  2655. - double dz = _actor.getZ() - _attackTarget.getZ();
  2656. - if(dz*dz < 170*170) // normally 130 if guard z coordinates correct
  2657. - moveToPawn(_attackTarget, range);
  2658. + // Temporary hack for preventing guards jumping off towers,
  2659. + // before replacing this with effective geodata checks and AI modification
  2660. + double dz = _actor.getZ() - _attackTarget.getZ();
  2661. + if(dz*dz < 170*170) // normally 130 if guard z coordinates correct
  2662. + {
  2663. + if (_selfAnalysis.isMage) range = _selfAnalysis.maxCastRange-50;
  2664. + if (_attackTarget.isMoving())
  2665. + moveToPawn(_attackTarget, range-70);
  2666. + else
  2667. + moveToPawn(_attackTarget, range);
  2668. + }
  2669. return;
  2670. }
  2671. // Else, if this is close enough to attack
  2672. - else if (dist_2 <= (range + 20) * (range + 20))
  2673. + else if (dist_2 <= range * range)
  2674. {
  2675. - // Force mobs to attak anybody if confused
  2676. + // Force mobs to attack anybody if confused
  2677. L2Character hated = null;
  2678. if (_actor.isConfused()) hated = _attackTarget;
  2679. else hated = ((L2Attackable) _actor).getMostHated();
  2680. @@ -453,7 +641,7 @@
  2681. {
  2682. int castRange = sk.getCastRange();
  2683.  
  2684. - if (castRange * castRange >= dist_2 && castRange <= 70 && !sk.isPassive()
  2685. + if (castRange * castRange >= dist_2 && !sk.isPassive()
  2686. && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)
  2687. && !_actor.isSkillDisabled(sk.getId()))
  2688. {
  2689. @@ -495,109 +683,8 @@
  2690. _accessor.doAttack(_attackTarget);
  2691. }
  2692. }
  2693. -
  2694. +
  2695. /**
  2696. - * Manage AI attack thinks of a L2Attackable (called by onEvtThink).<BR><BR>
  2697. - *
  2698. - * <B><U> Actions</U> :</B><BR><BR>
  2699. - * <li>Update the attack timeout if actor is running</li>
  2700. - * <li>If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE</li>
  2701. - * <li>Call all L2Object of its Faction inside the Faction Range</li>
  2702. - * <li>Chose a target and order to attack it with magic skill or physical attack</li><BR><BR>
  2703. - *
  2704. - * TODO: Manage casting rules to healer mobs (like Ant Nurses)
  2705. - *
  2706. - */
  2707. - private void thinkAttack()
  2708. - {
  2709. - if (Config.DEBUG)
  2710. - _log.info("L2SiegeGuardAI.thinkAttack(); timeout="
  2711. - + (_attackTimeout - GameTimeController.getGameTicks()));
  2712. -
  2713. - if (_attackTimeout < GameTimeController.getGameTicks())
  2714. - {
  2715. - // Check if the actor is running
  2716. - if (_actor.isRunning())
  2717. - {
  2718. - // Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
  2719. - _actor.setWalking();
  2720. -
  2721. - // Calculate a new attack timeout
  2722. - _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
  2723. - }
  2724. - }
  2725. -
  2726. - // Check if target is dead or if timeout is expired to stop this attack
  2727. - if (_attackTarget == null || _attackTarget.isAlikeDead()
  2728. - || _attackTimeout < GameTimeController.getGameTicks())
  2729. - {
  2730. - // Stop hating this target after the attack timeout or if target is dead
  2731. - if (_attackTarget != null)
  2732. - {
  2733. - L2Attackable npc = (L2Attackable) _actor;
  2734. - npc.stopHating(_attackTarget);
  2735. - }
  2736. -
  2737. - // Cancel target and timeout
  2738. - _attackTimeout = Integer.MAX_VALUE;
  2739. - _attackTarget = null;
  2740. -
  2741. - // Set the AI Intention to AI_INTENTION_ACTIVE
  2742. - setIntention(AI_INTENTION_ACTIVE, null, null);
  2743. -
  2744. - _actor.setWalking();
  2745. - return;
  2746. - }
  2747. -
  2748. - attackPrepare();
  2749. - factionNotify();
  2750. - }
  2751. -
  2752. - private final void factionNotify()
  2753. - {
  2754. - // Call all L2Object of its Faction inside the Faction Range
  2755. - if (((L2NpcInstance) _actor).getFactionId() == null || _attackTarget == null || _actor == null)
  2756. - return;
  2757. -
  2758. - if (_attackTarget.isInvul()) return;
  2759. -
  2760. - String faction_id = ((L2NpcInstance) _actor).getFactionId();
  2761. -
  2762. - // Go through all L2Object that belong to its faction
  2763. - for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
  2764. - {
  2765. - if (cha == null) continue;
  2766. -
  2767. - if (!(cha instanceof L2NpcInstance)) continue;
  2768. -
  2769. - L2NpcInstance npc = (L2NpcInstance) cha;
  2770. -
  2771. - if (faction_id != npc.getFactionId()) continue;
  2772. -
  2773. - // Check if the L2Object is inside the Faction Range of the actor
  2774. - if ((npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE || npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE)
  2775. - && _actor.isInsideRadius(npc, npc.getFactionRange(), false, true)
  2776. - && npc.getTarget() == null
  2777. - && _attackTarget.isInsideRadius(npc, npc.getFactionRange(), false, true)
  2778. - )
  2779. - {
  2780. - if (Config.GEODATA > 0)
  2781. - {
  2782. - if (GeoData.getInstance().canSeeTarget(npc, _attackTarget))
  2783. - // Notify the L2Object AI with EVT_AGGRESSION
  2784. - npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attackTarget, 1);
  2785. - }
  2786. - else
  2787. - {
  2788. - if (Math.abs(_attackTarget.getZ() - npc.getZ()) < 600)
  2789. - // Notify the L2Object AI with EVT_AGGRESSION
  2790. - npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attackTarget, 1);
  2791. - }
  2792. - }
  2793. - }
  2794. - }
  2795. -
  2796. - /**
  2797. * Manage AI thinking actions of a L2Attackable.<BR><BR>
  2798. */
  2799. @Override
  2800. Index: java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java
  2801. ===================================================================
  2802. --- java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java (revision 1770)
  2803. +++ java/net/sf/l2j/gameserver/templates/L2NpcTemplate.java (revision 1771)
  2804. @@ -68,8 +68,12 @@
  2805. public final int factionRange;
  2806. public final int absorbLevel;
  2807. public final AbsorbCrystalType absorbType;
  2808. + public final short ss;
  2809. + public final short bss;
  2810. + public final short ssRate;
  2811. public Race race;
  2812. - public final String jClass;
  2813. + public final String jClass;
  2814. + public final AIType AI;
  2815.  
  2816. public static enum AbsorbCrystalType
  2817. {
  2818. @@ -78,6 +82,14 @@
  2819. PARTY_ONE_RANDOM
  2820. }
  2821.  
  2822. + public static enum AIType
  2823. + {
  2824. + FIGHTER,
  2825. + ARCHER,
  2826. + BALANCED,
  2827. + MAGE
  2828. + }
  2829. +
  2830. public static enum Race
  2831. {
  2832. UNDEAD,
  2833. @@ -125,7 +137,7 @@
  2834. /**
  2835. * Constructor of L2Character.<BR><BR>
  2836. *
  2837. - * @param set The StatsSet object to transfert data to the method
  2838. + * @param set The StatsSet object to transfer data to the method
  2839. *
  2840. */
  2841. public L2NpcTemplate(StatsSet set)
  2842. @@ -154,10 +166,18 @@
  2843. factionRange = set.getInteger("factionRange");
  2844. absorbLevel = set.getInteger("absorb_level", 0);
  2845. absorbType = AbsorbCrystalType.valueOf(set.getString("absorb_type"));
  2846. + ss = (short)set.getInteger("ss", 0);
  2847. + bss = (short)set.getInteger("bss", 0);
  2848. + ssRate = (short)set.getInteger("ssRate", 0);
  2849. race = null;
  2850. //_npcStatsSet = set;
  2851. _teachInfo = null;
  2852. jClass = set.getString("jClass");
  2853. + String ai = set.getString("AI", "fighter");
  2854. + if (ai.equalsIgnoreCase("archer")) AI = AIType.ARCHER;
  2855. + else if (ai.equalsIgnoreCase("balanced")) AI = AIType.BALANCED;
  2856. + else if (ai.equalsIgnoreCase("mage")) AI = AIType.MAGE;
  2857. + else AI = AIType.FIGHTER;
  2858. }
  2859.  
  2860. public void addTeachInfo(ClassId classId)
  2861. Index: java/net/sf/l2j/gameserver/datatables/NpcTable.java
  2862. ===================================================================
  2863. --- java/net/sf/l2j/gameserver/datatables/NpcTable.java (revision 1770)
  2864. +++ java/net/sf/l2j/gameserver/datatables/NpcTable.java (revision 1771)
  2865. @@ -73,7 +73,7 @@
  2866. {
  2867. con = L2DatabaseFactory.getInstance().getConnection();
  2868. PreparedStatement statement;
  2869. - statement = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"id", "idTemplate", "name", "serverSideName", "title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type", "attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk", "pdef", "matk", "mdef", "atkspd", "aggro", "matkspd", "rhand", "lhand", "armor", "walkspd", "runspd", "faction_id", "faction_range", "isUndead", "absorb_level", "absorb_type"}) + " FROM npc");
  2870. + statement = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"id", "idTemplate", "name", "serverSideName", "title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type", "attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk", "pdef", "matk", "mdef", "atkspd", "aggro", "matkspd", "rhand", "lhand", "armor", "walkspd", "runspd", "faction_id", "faction_range", "isUndead", "absorb_level", "absorb_type", "ss", "bss", "ss_rate", "AI"}) + " FROM npc");
  2871. ResultSet npcdata = statement.executeQuery();
  2872.  
  2873. fillNpcTable(npcdata);
  2874. @@ -288,6 +288,12 @@
  2875.  
  2876. npcDat.set("absorb_level", NpcData.getString("absorb_level"));
  2877. npcDat.set("absorb_type", NpcData.getString("absorb_type"));
  2878. +
  2879. + npcDat.set("ss", NpcData.getInt("ss"));
  2880. + npcDat.set("bss", NpcData.getInt("bss"));
  2881. + npcDat.set("ssRate", NpcData.getInt("ss_rate"));
  2882. +
  2883. + npcDat.set("AI", NpcData.getString("AI"));
  2884.  
  2885. L2NpcTemplate template = new L2NpcTemplate(npcDat);
  2886. template.addVulnerability(Stats.BOW_WPN_VULN,1);
  2887. @@ -331,7 +337,7 @@
  2888.  
  2889. // reload the NPC base data
  2890. con = L2DatabaseFactory.getInstance().getConnection();
  2891. - PreparedStatement st = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"id", "idTemplate", "name", "serverSideName", "title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type", "attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk", "pdef", "matk", "mdef", "atkspd", "aggro", "matkspd", "rhand", "lhand", "armor", "walkspd", "runspd", "faction_id", "faction_range", "isUndead", "absorb_level", "absorb_type"}) + " FROM npc WHERE id=?");
  2892. + PreparedStatement st = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[] {"id", "idTemplate", "name", "serverSideName", "title", "serverSideTitle", "class", "collision_radius", "collision_height", "level", "sex", "type", "attackrange", "hp", "mp", "hpreg", "mpreg", "str", "con", "dex", "int", "wit", "men", "exp", "sp", "patk", "pdef", "matk", "mdef", "atkspd", "aggro", "matkspd", "rhand", "lhand", "armor", "walkspd", "runspd", "faction_id", "faction_range", "isUndead", "absorb_level", "absorb_type", "ss", "bss", "ss_rate", "AI"}) + " FROM npc WHERE id=?");
  2893. st.setInt(1, id);
  2894. ResultSet rs = st.executeQuery();
  2895. fillNpcTable(rs);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement