L2Attackable.java 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2, or (at your option)
  5. * any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. * 02111-1307, USA.
  16. *
  17. * http://www.gnu.org/copyleft/gpl.html
  18. */
  19. package net.sf.l2j.gameserver.model;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.logging.Level;
  23. import javolution.util.FastList;
  24. import javolution.util.FastMap;
  25. import net.sf.l2j.Config;
  26. import net.sf.l2j.gameserver.ItemsAutoDestroy;
  27. import net.sf.l2j.gameserver.ThreadPoolManager;
  28. import net.sf.l2j.gameserver.ai.CtrlEvent;
  29. import net.sf.l2j.gameserver.ai.CtrlIntention;
  30. import net.sf.l2j.gameserver.ai.L2AttackableAI;
  31. import net.sf.l2j.gameserver.ai.L2CharacterAI;
  32. import net.sf.l2j.gameserver.ai.L2SiegeGuardAI;
  33. import net.sf.l2j.gameserver.clientpackets.Say2;
  34. import net.sf.l2j.gameserver.datatables.EventDroplist;
  35. import net.sf.l2j.gameserver.datatables.ItemTable;
  36. import net.sf.l2j.gameserver.datatables.EventDroplist.DateDrop;
  37. import net.sf.l2j.gameserver.instancemanager.CursedWeaponsManager;
  38. import net.sf.l2j.gameserver.model.actor.instance.L2BossInstance;
  39. import net.sf.l2j.gameserver.model.actor.instance.L2DoorInstance;
  40. import net.sf.l2j.gameserver.model.actor.instance.L2FolkInstance;
  41. import net.sf.l2j.gameserver.model.actor.instance.L2MinionInstance;
  42. import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  43. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  44. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  45. import net.sf.l2j.gameserver.model.actor.instance.L2PetInstance;
  46. import net.sf.l2j.gameserver.model.actor.instance.L2PlayableInstance;
  47. import net.sf.l2j.gameserver.model.actor.instance.L2RaidBossInstance;
  48. import net.sf.l2j.gameserver.model.actor.instance.L2SiegeGuardInstance;
  49. import net.sf.l2j.gameserver.model.actor.instance.L2SummonInstance;
  50. import net.sf.l2j.gameserver.model.actor.knownlist.AttackableKnownList;
  51. import net.sf.l2j.gameserver.model.base.SoulCrystal;
  52. import net.sf.l2j.gameserver.model.quest.Quest;
  53. import net.sf.l2j.gameserver.network.SystemMessageId;
  54. import net.sf.l2j.gameserver.serverpackets.CreatureSay;
  55. import net.sf.l2j.gameserver.serverpackets.InventoryUpdate;
  56. import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  57. import net.sf.l2j.gameserver.skills.Stats;
  58. import net.sf.l2j.gameserver.templates.L2EtcItemType;
  59. import net.sf.l2j.gameserver.templates.L2NpcTemplate;
  60. import net.sf.l2j.gameserver.util.Util;
  61. import net.sf.l2j.util.Rnd;
  62. /**
  63. * This class manages all NPC that can be attacked.<BR><BR>
  64. *
  65. * L2Attackable :<BR><BR>
  66. * <li>L2ArtefactInstance</li>
  67. * <li>L2FriendlyMobInstance</li>
  68. * <li>L2MonsterInstance</li>
  69. * <li>L2SiegeGuardInstance </li>
  70. *
  71. * @version $Revision: 1.24.2.3.2.16 $ $Date: 2005/04/11 19:11:21 $
  72. */
  73. public class L2Attackable extends L2NpcInstance
  74. {
  75. //protected static Logger _log = Logger.getLogger(L2Attackable.class.getName());
  76. /**
  77. * This class contains all AggroInfo of the L2Attackable against the attacker L2Character.<BR><BR>
  78. *
  79. * <B><U> Data</U> :</B><BR><BR>
  80. * <li>attacker : The attaker L2Character concerned by this AggroInfo of this L2Attackable </li>
  81. * <li>hate : Hate level of this L2Attackable against the attaker L2Character (hate = damage) </li>
  82. * <li>damage : Number of damages that the attaker L2Character gave to this L2Attackable </li><BR><BR>
  83. *
  84. */
  85. public final class AggroInfo
  86. {
  87. /** The attaker L2Character concerned by this AggroInfo of this L2Attackable */
  88. protected L2Character _attacker;
  89. /** Hate level of this L2Attackable against the attaker L2Character (hate = damage) */
  90. protected int _hate;
  91. /** Number of damages that the attaker L2Character gave to this L2Attackable */
  92. protected int _damage;
  93. /**
  94. * Constructor of AggroInfo.<BR><BR>
  95. */
  96. AggroInfo(L2Character pAttacker)
  97. {
  98. _attacker = pAttacker;
  99. }
  100. /**
  101. * Verify is object is equal to this AggroInfo.<BR><BR>
  102. */
  103. @Override
  104. public boolean equals(Object obj)
  105. {
  106. if (this == obj) return true;
  107. if (obj instanceof AggroInfo) return (((AggroInfo)obj)._attacker == _attacker);
  108. return false;
  109. }
  110. /**
  111. * Return the Identifier of the attaker L2Character.<BR><BR>
  112. */
  113. @Override
  114. public int hashCode()
  115. {
  116. return _attacker.getObjectId();
  117. }
  118. }
  119. /**
  120. * This class contains all RewardInfo of the L2Attackable against the any attacker L2Character, based on amount of damage done.<BR><BR>
  121. *
  122. * <B><U> Data</U> :</B><BR><BR>
  123. * <li>attacker : The attaker L2Character concerned by this RewardInfo of this L2Attackable </li>
  124. * <li>dmg : Total amount of damage done by the attacker to this L2Attackable (summon + own) </li>
  125. *
  126. */
  127. protected final class RewardInfo
  128. {
  129. protected L2Character _attacker;
  130. protected int _dmg = 0;
  131. public RewardInfo(L2Character pAttacker, int pDmg)
  132. {
  133. _attacker = pAttacker;
  134. _dmg = pDmg;
  135. }
  136. public void addDamage(int pDmg)
  137. {
  138. _dmg += pDmg;
  139. }
  140. @Override
  141. public boolean equals(Object obj)
  142. {
  143. if (this == obj) return true;
  144. if (obj instanceof RewardInfo) return (((RewardInfo)obj)._attacker == _attacker);
  145. return false;
  146. }
  147. @Override
  148. public int hashCode()
  149. {
  150. return _attacker.getObjectId();
  151. }
  152. }
  153. /**
  154. * This class contains all AbsorberInfo of the L2Attackable against the absorber L2Character.<BR><BR>
  155. *
  156. * <B><U> Data</U> :</B><BR><BR>
  157. * <li>absorber : The attaker L2Character concerned by this AbsorberInfo of this L2Attackable </li>
  158. *
  159. */
  160. public final class AbsorberInfo
  161. {
  162. /** The attaker L2Character concerned by this AbsorberInfo of this L2Attackable */
  163. protected L2PcInstance _absorber;
  164. protected int _crystalId;
  165. protected double _absorbedHP;
  166. /**
  167. * Constructor of AbsorberInfo.<BR><BR>
  168. */
  169. AbsorberInfo(L2PcInstance attacker, int pCrystalId, double pAbsorbedHP)
  170. {
  171. _absorber = attacker;
  172. _crystalId = pCrystalId;
  173. _absorbedHP = pAbsorbedHP;
  174. }
  175. /**
  176. * Verify is object is equal to this AbsorberInfo.<BR><BR>
  177. */
  178. @Override
  179. public boolean equals(Object obj)
  180. {
  181. if (this == obj) return true;
  182. if (obj instanceof AbsorberInfo) return (((AbsorberInfo)obj)._absorber == _absorber);
  183. return false;
  184. }
  185. /**
  186. * Return the Identifier of the absorber L2Character.<BR><BR>
  187. */
  188. @Override
  189. public int hashCode()
  190. {
  191. return _absorber.getObjectId();
  192. }
  193. }
  194. /**
  195. * This class is used to create item reward lists instead of creating item instances.<BR><BR>
  196. */
  197. public final class RewardItem
  198. {
  199. protected int _itemId;
  200. protected int _count;
  201. public RewardItem(int itemId, int count)
  202. {
  203. _itemId = itemId;
  204. _count = count;
  205. }
  206. public int getItemId() { return _itemId;}
  207. public int getCount() { return _count;}
  208. }
  209. /** The table containing all autoAttackable L2Character in its Aggro Range and L2Character that attacked the L2Attackable
  210. * This Map is Thread Safe, but Removing Object While Interating Over It Will Result NPE
  211. * */
  212. private FastMap<L2Character, AggroInfo> _aggroList = new FastMap<L2Character, AggroInfo>().setShared(true);
  213. /** Use this to Read or Put Object to this Map */
  214. public final FastMap<L2Character, AggroInfo> getAggroListRP()
  215. {
  216. return _aggroList;
  217. }
  218. /** Use this to Remove Object from this Map
  219. * This Should be Synchronized While Interating over This Map - ie u cant interating and removing object at once*/
  220. public final FastMap<L2Character, AggroInfo> getAggroList()
  221. {
  222. return _aggroList;
  223. }
  224. private boolean _isReturningToSpawnPoint = false;
  225. public final boolean isReturningToSpawnPoint() { return _isReturningToSpawnPoint; }
  226. public final void setisReturningToSpawnPoint(boolean value) { _isReturningToSpawnPoint = value; }
  227. /** Table containing all Items that a Dwarf can Sweep on this L2Attackable */
  228. private RewardItem[] _sweepItems;
  229. /** crops */
  230. private RewardItem[] _harvestItems;
  231. private boolean _seeded;
  232. private int _seedType = 0;
  233. private L2PcInstance _seeder = null;
  234. /** True if an over-hit enabled skill has successfully landed on the L2Attackable */
  235. private boolean _overhit;
  236. /** Stores the extra (over-hit) damage done to the L2Attackable when the attacker uses an over-hit enabled skill */
  237. private double _overhitDamage;
  238. /** Stores the attacker who used the over-hit enabled skill on the L2Attackable */
  239. private L2Character _overhitAttacker;
  240. /** First CommandChannel who attacked the L2Attackable and meet the requirements **/
  241. private L2CommandChannel _firstCommandChannelAttacked = null;
  242. private CommandChannelTimer _commandChannelTimer = null;
  243. /** True if a Soul Crystal was successfuly used on the L2Attackable */
  244. private boolean _absorbed;
  245. /** The table containing all L2PcInstance that successfuly absorbed the soul of this L2Attackable */
  246. private FastMap<L2PcInstance, AbsorberInfo> _absorbersList = new FastMap<L2PcInstance, AbsorberInfo>().setShared(true);
  247. /** Have this L2Attackable to reward Exp and SP on Die? **/
  248. private boolean _mustGiveExpSp;
  249. /**
  250. * Constructor of L2Attackable (use L2Character and L2NpcInstance constructor).<BR><BR>
  251. *
  252. * <B><U> Actions</U> :</B><BR><BR>
  253. * <li>Call the L2Character constructor to set the _template of the L2Attackable (copy skills from template to object and link _calculators to NPC_STD_CALCULATOR) </li>
  254. * <li>Set the name of the L2Attackable</li>
  255. * <li>Create a RandomAnimation Task that will be launched after the calculated delay if the server allow it </li><BR><BR>
  256. *
  257. * @param objectId Identifier of the object to initialized
  258. * @param L2NpcTemplate Template to apply to the NPC
  259. */
  260. public L2Attackable(int objectId, L2NpcTemplate template)
  261. {
  262. super(objectId, template);
  263. getKnownList(); // init knownlist
  264. _mustGiveExpSp = true;
  265. }
  266. @Override
  267. public AttackableKnownList getKnownList()
  268. {
  269. if(super.getKnownList() == null || !(super.getKnownList() instanceof AttackableKnownList))
  270. setKnownList(new AttackableKnownList(this));
  271. return (AttackableKnownList)super.getKnownList();
  272. }
  273. /**
  274. * Return the L2Character AI of the L2Attackable and if its null create a new one.<BR><BR>
  275. */
  276. @Override
  277. public L2CharacterAI getAI()
  278. {
  279. if (_ai == null)
  280. {
  281. synchronized(this)
  282. {
  283. if (_ai == null)
  284. _ai = new L2AttackableAI(new AIAccessor());
  285. }
  286. }
  287. return _ai;
  288. }
  289. // get condition to hate, actually isAggressive() is checked
  290. // by monster and karma by guards in motheds that overwrite this one.
  291. /**
  292. * Not used.<BR><BR>
  293. *
  294. * @deprecated
  295. *
  296. */
  297. @Deprecated
  298. public boolean getCondition2(L2Character target)
  299. {
  300. if (target instanceof L2FolkInstance || target instanceof L2DoorInstance)
  301. return false;
  302. if (target.isAlikeDead()
  303. || !isInsideRadius(target, getAggroRange(), false, false)
  304. || Math.abs(getZ()-target.getZ()) > 100
  305. )
  306. return false;
  307. return !target.isInvul();
  308. }
  309. /**
  310. * Reduce the current HP of the L2Attackable.<BR><BR>
  311. *
  312. * @param damage The HP decrease value
  313. * @param attacker The L2Character who attacks
  314. *
  315. */
  316. @Override
  317. public void reduceCurrentHp(double damage, L2Character attacker)
  318. {
  319. reduceCurrentHp(damage, attacker, true);
  320. }
  321. /**
  322. * Reduce the current HP of the L2Attackable, update its _aggroList and launch the doDie Task if necessary.<BR><BR>
  323. *
  324. * @param i The HP decrease value
  325. * @param attacker The L2Character who attacks
  326. * @param awake The awake state (If True : stop sleeping)
  327. *
  328. */
  329. @Override
  330. public void reduceCurrentHp(double damage, L2Character attacker, boolean awake)
  331. {
  332. /*
  333. if ((this instanceof L2SiegeGuardInstance) && (attacker instanceof L2SiegeGuardInstance))
  334. //if((this.getEffect(L2Effect.EffectType.CONFUSION)!=null) && (attacker.getEffect(L2Effect.EffectType.CONFUSION)!=null))
  335. return;
  336. if ((this instanceof L2MonsterInstance)&&(attacker instanceof L2MonsterInstance))
  337. if((this.getEffect(L2Effect.EffectType.CONFUSION)!=null) && (attacker.getEffect(L2Effect.EffectType.CONFUSION)!=null))
  338. return;
  339. */
  340. // CommandChannel
  341. if (_commandChannelTimer == null && this.isRaid())
  342. {
  343. if (attacker.isInParty() && attacker.getParty().isInCommandChannel()
  344. && attacker.getParty().getCommandChannel().meetRaidWarCondition(this))
  345. {
  346. _firstCommandChannelAttacked = attacker.getParty().getCommandChannel();
  347. _commandChannelTimer = new CommandChannelTimer(this, attacker.getParty().getCommandChannel());
  348. ThreadPoolManager.getInstance().scheduleGeneral(_commandChannelTimer, 300000); // 5 min
  349. _firstCommandChannelAttacked.broadcastToChannelMembers(new CreatureSay(0, Say2.PARTYROOM_ALL, "", "You have looting rights!"));
  350. }
  351. }
  352. if (isEventMob) return;
  353. // Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList
  354. if (attacker != null) addDamage(attacker, (int)damage);
  355. // If this L2Attackable is a L2MonsterInstance and it has spawned minions, call its minions to battle
  356. if (this instanceof L2MonsterInstance)
  357. {
  358. L2MonsterInstance master = (L2MonsterInstance) this;
  359. if (this instanceof L2MinionInstance)
  360. {
  361. master = ((L2MinionInstance)this).getLeader();
  362. if (!master.isInCombat()&&!master.isDead()) master.addDamage(attacker, 1);
  363. }
  364. if (master.hasMinions())
  365. master.callMinionsToAssist(attacker);
  366. }
  367. // Reduce the current HP of the L2Attackable and launch the doDie Task if necessary
  368. super.reduceCurrentHp(damage, attacker, awake);
  369. }
  370. public synchronized void setMustRewardExpSp(boolean value) {
  371. _mustGiveExpSp = value;
  372. }
  373. public synchronized boolean getMustRewardExpSP() { return _mustGiveExpSp; }
  374. /**
  375. * Kill the L2Attackable (the corpse disappeared after 7 seconds), distribute rewards (EXP, SP, Drops...) and notify Quest Engine.<BR><BR>
  376. *
  377. * <B><U> Actions</U> :</B><BR><BR>
  378. * <li>Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members </li>
  379. * <li>Notify the Quest Engine of the L2Attackable death if necessary</li>
  380. * <li>Kill the L2NpcInstance (the corpse disappeared after 7 seconds) </li><BR><BR>
  381. *
  382. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR><BR>
  383. *
  384. * @param killer The L2Character that has killed the L2Attackable
  385. *
  386. */
  387. @Override
  388. public boolean doDie(L2Character killer)
  389. {
  390. // Kill the L2NpcInstance (the corpse disappeared after 7 seconds)
  391. if (!super.doDie(killer))
  392. return false;
  393. // Enhance soul crystals of the attacker if this L2Attackable had its soul absorbed
  394. try {
  395. if (killer instanceof L2PcInstance)
  396. {
  397. levelSoulCrystals(killer);
  398. }
  399. }
  400. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  401. // Notify the Quest Engine of the L2Attackable death if necessary
  402. try {
  403. if (killer instanceof L2PcInstance || killer instanceof L2Summon)
  404. {
  405. L2PcInstance player = killer instanceof L2PcInstance?(L2PcInstance)killer:((L2Summon)killer).getOwner();
  406. if (getTemplate().getEventQuests(Quest.QuestEventType.MOBKILLED) != null)
  407. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.MOBKILLED))
  408. quest.notifyKill(this, player, killer instanceof L2Summon);
  409. }
  410. }
  411. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  412. setChampion(false);
  413. if (Config.L2JMOD_CHAMPION_ENABLE)
  414. {
  415. //Set champion on next spawn
  416. if (!(this instanceof L2BossInstance) && this instanceof L2MonsterInstance && Config.L2JMOD_CHAMPION_FREQUENCY > 0 && getLevel()>=Config.L2JMOD_CHAMP_MIN_LVL && getLevel()<=Config.L2JMOD_CHAMP_MAX_LVL)
  417. {
  418. int random = Rnd.get(100);
  419. if (random < Config.L2JMOD_CHAMPION_FREQUENCY)
  420. setChampion(true);
  421. }
  422. }
  423. return true;
  424. }
  425. /**
  426. * Distribute Exp and SP rewards to L2PcInstance (including Summon owner) that hit the L2Attackable and to their Party members.<BR><BR>
  427. *
  428. * <B><U> Actions</U> :</B><BR><BR>
  429. * <li>Get the L2PcInstance owner of the L2SummonInstance (if necessary) and L2Party in progress </li>
  430. * <li>Calculate the Experience and SP rewards in function of the level difference</li>
  431. * <li>Add Exp and SP rewards to L2PcInstance (including Summon penalty) and to Party members in the known area of the last attacker </li><BR><BR>
  432. *
  433. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T GIVE rewards to L2PetInstance</B></FONT><BR><BR>
  434. *
  435. * @param lastAttacker The L2Character that has killed the L2Attackable
  436. *
  437. */
  438. @Override
  439. protected void calculateRewards(L2Character lastAttacker)
  440. {
  441. // Creates an empty list of rewards
  442. FastMap<L2Character, RewardInfo> rewards = new FastMap<L2Character, RewardInfo>().setShared(true);
  443. try
  444. {
  445. if (getAggroListRP().isEmpty()) return;
  446. // Manage Base, Quests and Sweep drops of the L2Attackable
  447. doItemDrop(lastAttacker);
  448. // Manage drop of Special Events created by GM for a defined period
  449. doEventDrop(lastAttacker);
  450. if (!getMustRewardExpSP()) return;
  451. int rewardCount = 0;
  452. int damage;
  453. L2Character attacker, ddealer;
  454. RewardInfo reward;
  455. // While Interating over This Map Removing Object is Not Allowed
  456. synchronized (getAggroList())
  457. {
  458. // Go through the _aggroList of the L2Attackable
  459. for (AggroInfo info : getAggroListRP().values())
  460. {
  461. if (info == null) continue;
  462. // Get the L2Character corresponding to this attacker
  463. attacker = info._attacker;
  464. // Get damages done by this attacker
  465. damage = info._damage;
  466. // Prevent unwanted behavior
  467. if (damage > 1)
  468. {
  469. if ( (attacker instanceof L2SummonInstance) ||
  470. ((attacker instanceof L2PetInstance) &&
  471. ((L2PetInstance)attacker).getPetData().getOwnerExpTaken() > 0) )
  472. ddealer = ((L2Summon)attacker).getOwner();
  473. else
  474. ddealer = info._attacker;
  475. // Check if ddealer isn't too far from this (killed monster)
  476. if (!Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, ddealer, true)) continue;
  477. // Calculate real damages (Summoners should get own damage plus summon's damage)
  478. reward = rewards.get(ddealer);
  479. if (reward == null)
  480. {
  481. reward = new RewardInfo(ddealer, damage);
  482. rewardCount++;
  483. }
  484. else
  485. {
  486. reward.addDamage(damage);
  487. }
  488. rewards.put(ddealer, reward);
  489. }
  490. }
  491. }
  492. if (!rewards.isEmpty())
  493. {
  494. L2Party attackerParty;
  495. long exp;
  496. int levelDiff, partyDmg, partyLvl, sp;
  497. float partyMul, penalty;
  498. RewardInfo reward2;
  499. int[] tmp;
  500. for (FastMap.Entry<L2Character, RewardInfo> entry = rewards.head(), end = rewards.tail(); (entry = entry.getNext()) != end;)
  501. {
  502. if (entry == null) continue;
  503. reward = entry.getValue();
  504. if(reward == null) continue;
  505. // Penalty applied to the attacker's XP
  506. penalty = 0;
  507. // Attacker to be rewarded
  508. attacker = reward._attacker;
  509. // Total amount of damage done
  510. damage = reward._dmg;
  511. // If the attacker is a Pet, get the party of the owner
  512. if (attacker instanceof L2PetInstance)
  513. attackerParty = ((L2PetInstance)attacker).getParty();
  514. else if (attacker instanceof L2PcInstance)
  515. attackerParty = ((L2PcInstance)attacker).getParty();
  516. else
  517. return;
  518. // If this attacker is a L2PcInstance with a summoned L2SummonInstance, get Exp Penalty applied for the current summoned L2SummonInstance
  519. if (attacker instanceof L2PcInstance && ((L2PcInstance)attacker).getPet() instanceof L2SummonInstance)
  520. {
  521. penalty = ((L2SummonInstance)((L2PcInstance)attacker).getPet()).getExpPenalty();
  522. }
  523. // We must avoid "over damage", if any
  524. if (damage > getMaxHp()) damage = getMaxHp();
  525. // If there's NO party in progress
  526. if (attackerParty == null)
  527. {
  528. // Calculate Exp and SP rewards
  529. if (attacker.getKnownList().knowsObject(this))
  530. {
  531. // Calculate the difference of level between this attacker (L2PcInstance or L2SummonInstance owner) and the L2Attackable
  532. // mob = 24, atk = 10, diff = -14 (full xp)
  533. // mob = 24, atk = 28, diff = 4 (some xp)
  534. // mob = 24, atk = 50, diff = 26 (no xp)
  535. levelDiff = attacker.getLevel() - getLevel();
  536. tmp = calculateExpAndSp(levelDiff, damage);
  537. exp = tmp[0];
  538. exp *= 1 - penalty;
  539. sp = tmp[1];
  540. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  541. {
  542. exp *= Config.L2JMOD_CHAMPION_REWARDS;
  543. sp *= Config.L2JMOD_CHAMPION_REWARDS;
  544. }
  545. // Check for an over-hit enabled strike
  546. if (attacker instanceof L2PcInstance)
  547. {
  548. L2PcInstance player = (L2PcInstance)attacker;
  549. if (isOverhit() && attacker == getOverhitAttacker())
  550. {
  551. player.sendPacket(new SystemMessage(SystemMessageId.OVER_HIT));
  552. exp += calculateOverhitExp(exp);
  553. }
  554. }
  555. // Distribute the Exp and SP between the L2PcInstance and its L2Summon
  556. if (!attacker.isDead())
  557. attacker.addExpAndSp(Math.round(attacker.calcStat(Stats.EXPSP_RATE, exp, null, null)),
  558. (int)attacker.calcStat(Stats.EXPSP_RATE, sp, null, null));
  559. }
  560. }
  561. else
  562. {
  563. //share with party members
  564. partyDmg = 0;
  565. partyMul = 1.f;
  566. partyLvl = 0;
  567. // Get all L2Character that can be rewarded in the party
  568. List<L2PlayableInstance> rewardedMembers = new FastList<L2PlayableInstance>();
  569. // Go through all L2PcInstance in the party
  570. List<L2PcInstance> groupMembers;
  571. if (attackerParty.isInCommandChannel())
  572. groupMembers = attackerParty.getCommandChannel().getMembers();
  573. else
  574. groupMembers = attackerParty.getPartyMembers();
  575. for (L2PcInstance pl : groupMembers)
  576. {
  577. if (pl == null || pl.isDead()) continue;
  578. // Get the RewardInfo of this L2PcInstance from L2Attackable rewards
  579. reward2 = rewards.get(pl);
  580. // If the L2PcInstance is in the L2Attackable rewards add its damages to party damages
  581. if (reward2 != null)
  582. {
  583. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, pl, true))
  584. {
  585. partyDmg += reward2._dmg; // Add L2PcInstance damages to party damages
  586. rewardedMembers.add(pl);
  587. if (pl.getLevel() > partyLvl)
  588. {
  589. if(attackerParty.isInCommandChannel())
  590. partyLvl = attackerParty.getCommandChannel().getLevel();
  591. else
  592. partyLvl = pl.getLevel();
  593. }
  594. }
  595. rewards.remove(pl); // Remove the L2PcInstance from the L2Attackable rewards
  596. }
  597. else
  598. {
  599. // Add L2PcInstance of the party (that have attacked or not) to members that can be rewarded
  600. // and in range of the monster.
  601. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, pl, true))
  602. {
  603. rewardedMembers.add(pl);
  604. if (pl.getLevel() > partyLvl)
  605. {
  606. if(attackerParty.isInCommandChannel())
  607. partyLvl = attackerParty.getCommandChannel().getLevel();
  608. else
  609. partyLvl = pl.getLevel();
  610. }
  611. }
  612. }
  613. L2PlayableInstance summon = pl.getPet();
  614. if (summon != null && summon instanceof L2PetInstance)
  615. {
  616. reward2 = rewards.get(summon);
  617. if (reward2 != null) // Pets are only added if they have done damage
  618. {
  619. if (Util.checkIfInRange(Config.ALT_PARTY_RANGE, this, summon, true))
  620. {
  621. partyDmg += reward2._dmg; // Add summon damages to party damages
  622. rewardedMembers.add(summon);
  623. if (summon.getLevel() > partyLvl)
  624. partyLvl = summon.getLevel();
  625. }
  626. rewards.remove(summon); // Remove the summon from the L2Attackable rewards
  627. }
  628. }
  629. }
  630. // If the party didn't killed this L2Attackable alone
  631. if (partyDmg < getMaxHp()) partyMul = ((float)partyDmg / (float)getMaxHp());
  632. // Avoid "over damage"
  633. if (partyDmg > getMaxHp()) partyDmg = getMaxHp();
  634. // Calculate the level difference between Party and L2Attackable
  635. levelDiff = partyLvl - getLevel();
  636. // Calculate Exp and SP rewards
  637. tmp = calculateExpAndSp(levelDiff, partyDmg);
  638. exp = tmp[0];
  639. sp = tmp[1];
  640. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  641. {
  642. exp *= Config.L2JMOD_CHAMPION_REWARDS;
  643. sp *= Config.L2JMOD_CHAMPION_REWARDS;
  644. }
  645. exp *= partyMul;
  646. sp *= partyMul;
  647. // Check for an over-hit enabled strike
  648. // (When in party, the over-hit exp bonus is given to the whole party and splitted proportionally through the party members)
  649. if (attacker instanceof L2PcInstance)
  650. {
  651. L2PcInstance player = (L2PcInstance)attacker;
  652. if (isOverhit() && attacker == getOverhitAttacker())
  653. {
  654. player.sendPacket(new SystemMessage(SystemMessageId.OVER_HIT));
  655. exp += calculateOverhitExp(exp);
  656. }
  657. }
  658. // Distribute Experience and SP rewards to L2PcInstance Party members in the known area of the last attacker
  659. if (partyDmg > 0) attackerParty.distributeXpAndSp(exp, sp, rewardedMembers, partyLvl);
  660. }
  661. }
  662. }
  663. rewards = null;
  664. }
  665. catch (Exception e)
  666. {
  667. _log.log(Level.SEVERE, "", e);
  668. }
  669. }
  670. /**
  671. * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR><BR>
  672. *
  673. * @param attacker The L2Character that gave damages to this L2Attackable
  674. * @param damage The number of damages given by the attacker L2Character
  675. *
  676. */
  677. public void addDamage(L2Character attacker, int damage)
  678. {
  679. addDamageHate(attacker, damage, damage);
  680. }
  681. /**
  682. * Add damage and hate to the attacker AggroInfo of the L2Attackable _aggroList.<BR><BR>
  683. *
  684. * @param attacker The L2Character that gave damages to this L2Attackable
  685. * @param damage The number of damages given by the attacker L2Character
  686. * @param aggro The hate (=damage) given by the attacker L2Character
  687. *
  688. */
  689. public void addDamageHate(L2Character attacker, int damage, int aggro)
  690. {
  691. if (attacker == null /*|| _aggroList == null*/) return;
  692. // Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable
  693. AggroInfo ai = getAggroListRP().get(attacker);
  694. if (ai == null)
  695. {
  696. ai = new AggroInfo(attacker);
  697. ai._damage = 0;
  698. ai._hate = 0;
  699. getAggroListRP().put(attacker, ai);
  700. }
  701. // If aggro is negative, its comming from SEE_SPELL, buffs use constant 150
  702. if (aggro < 0) {
  703. ai._hate -= (aggro*150)/(getLevel()+7);
  704. aggro = -aggro;
  705. }
  706. // if damage == 0 -> this is case of adding only to aggro list, dont apply formula on it
  707. else if (damage == 0) ai._hate += aggro;
  708. // else its damage that must be added using constant 100
  709. else ai._hate += (aggro*100)/(getLevel()+7);
  710. // Add new damage and aggro (=damage) to the AggroInfo object
  711. ai._damage += damage;
  712. // Set the intention to the L2Attackable to AI_INTENTION_ACTIVE
  713. if (aggro > 0 && getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE) getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  714. // Notify the L2Attackable AI with EVT_ATTACKED
  715. if (damage > 0)
  716. {
  717. getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, attacker);
  718. try {
  719. if (attacker instanceof L2PcInstance || attacker instanceof L2Summon)
  720. {
  721. L2PcInstance player = attacker instanceof L2PcInstance ? (L2PcInstance)attacker : ((L2Summon)attacker).getOwner();
  722. if (getTemplate().getEventQuests(Quest.QuestEventType.MOBGOTATTACKED) !=null)
  723. for (Quest quest: getTemplate().getEventQuests(Quest.QuestEventType.MOBGOTATTACKED))
  724. quest.notifyAttack(this, player, damage, attacker instanceof L2Summon);
  725. }
  726. }
  727. catch (Exception e) { _log.log(Level.SEVERE, "", e); }
  728. }
  729. }
  730. public void reduceHate(L2Character target, int amount)
  731. {
  732. if (getAI() instanceof L2SiegeGuardAI)
  733. {
  734. // TODO: this just prevents error until siege guards are handled properly
  735. stopHating(target);
  736. setTarget(null);
  737. getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null, null);
  738. return;
  739. }
  740. if (target == null) // whole aggrolist
  741. {
  742. L2Character mostHated = getMostHated();
  743. if (mostHated == null) // makes target passive for a moment more
  744. {
  745. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  746. return;
  747. }
  748. else
  749. {
  750. for(L2Character aggroed : getAggroListRP().keySet())
  751. {
  752. AggroInfo ai = getAggroListRP().get(aggroed);
  753. if (ai == null) return;
  754. ai._hate -= amount;
  755. }
  756. }
  757. amount = getHating(mostHated);
  758. if (amount <= 0)
  759. {
  760. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  761. clearAggroList();
  762. getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  763. setWalking();
  764. }
  765. return;
  766. }
  767. AggroInfo ai = getAggroListRP().get(target);
  768. if (ai == null) return;
  769. ai._hate -= amount;
  770. if (ai._hate <= 0)
  771. {
  772. if (getMostHated() == null)
  773. {
  774. ((L2AttackableAI)getAI()).setGlobalAggro(-25);
  775. clearAggroList();
  776. getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
  777. setWalking();
  778. }
  779. }
  780. }
  781. /**
  782. * Clears _aggroList hate of the L2Character without removing from the list.<BR><BR>
  783. */
  784. public void stopHating(L2Character target)
  785. {
  786. if (target == null) return;
  787. AggroInfo ai = getAggroListRP().get(target);
  788. if (ai == null) return;
  789. ai._hate = 0;
  790. }
  791. /**
  792. * Return the most hated L2Character of the L2Attackable _aggroList.<BR><BR>
  793. */
  794. public L2Character getMostHated()
  795. {
  796. if (getAggroListRP().isEmpty() || isAlikeDead()) return null;
  797. L2Character mostHated = null;
  798. int maxHate = 0;
  799. // While Interating over This Map Removing Object is Not Allowed
  800. synchronized (getAggroList())
  801. {
  802. // Go through the aggroList of the L2Attackable
  803. for (AggroInfo ai : getAggroListRP().values())
  804. {
  805. if (ai == null) continue;
  806. if (ai._attacker.isAlikeDead() || !getKnownList().knowsObject(ai._attacker) ||!ai._attacker.isVisible())
  807. ai._hate = 0;
  808. if (ai._hate > maxHate)
  809. {
  810. mostHated = ai._attacker;
  811. maxHate = ai._hate;
  812. }
  813. }
  814. }
  815. return mostHated;
  816. }
  817. /**
  818. * Return the hate level of the L2Attackable against this L2Character contained in _aggroList.<BR><BR>
  819. *
  820. * @param target The L2Character whose hate level must be returned
  821. *
  822. */
  823. public int getHating(L2Character target)
  824. {
  825. if (getAggroListRP().isEmpty()) return 0;
  826. AggroInfo ai = getAggroListRP().get(target);
  827. if (ai == null) return 0;
  828. if (ai._attacker instanceof L2PcInstance && (((L2PcInstance)ai._attacker).getAppearance().getInvisible() || ai._attacker.isInvul()))
  829. {
  830. //Remove Object Should Use This Method and Can be Blocked While Interating
  831. getAggroList().remove(target);
  832. return 0;
  833. }
  834. if (!ai._attacker.isVisible())
  835. {
  836. getAggroList().remove(target);
  837. return 0;
  838. }
  839. if (ai._attacker.isAlikeDead())
  840. {
  841. ai._hate = 0;
  842. return 0;
  843. }
  844. return ai._hate;
  845. }
  846. /**
  847. * Calculates quantity of items for specific drop acording to current situation <br>
  848. *
  849. * @param drop The L2DropData count is being calculated for
  850. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  851. * @param deepBlueDrop Factor to divide the drop chance
  852. * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  853. */
  854. private RewardItem calculateRewardItem(L2PcInstance lastAttacker, L2DropData drop, int levelModifier, boolean isSweep)
  855. {
  856. // Get default drop chance
  857. float dropChance = drop.getChance();
  858. int deepBlueDrop = 1;
  859. if (Config.DEEPBLUE_DROP_RULES)
  860. {
  861. if (levelModifier > 0)
  862. {
  863. // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  864. // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  865. deepBlueDrop = 3;
  866. if (drop.getItemId() == 57) deepBlueDrop *= (int)Config.RATE_DROP_ITEMS;
  867. }
  868. }
  869. if(deepBlueDrop == 0) //avoid div by 0
  870. deepBlueDrop = 1;
  871. // Check if we should apply our maths so deep blue mobs will not drop that easy
  872. if (Config.DEEPBLUE_DROP_RULES) dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier)/100)) / deepBlueDrop);
  873. // Applies Drop rates
  874. if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA;
  875. else if (isSweep) dropChance *= Config.RATE_DROP_SPOIL;
  876. else dropChance *= Config.RATE_DROP_ITEMS;
  877. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  878. dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  879. // Round drop chance
  880. dropChance = Math.round(dropChance);
  881. // Set our limits for chance of drop
  882. if (dropChance < 1) dropChance = 1;
  883. // if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time
  884. // Get min and max Item quantity that can be dropped in one time
  885. int minCount = drop.getMinDrop();
  886. int maxCount = drop.getMaxDrop();
  887. int itemCount = 0;
  888. // Count and chance adjustment for high rate servers
  889. if (dropChance > L2DropData.MAX_CHANCE && !Config.PRECISE_DROP_CALCULATION)
  890. {
  891. int multiplier = (int)dropChance / L2DropData.MAX_CHANCE;
  892. if (minCount < maxCount) itemCount += Rnd.get(minCount * multiplier, maxCount * multiplier);
  893. else if (minCount == maxCount) itemCount += minCount * multiplier;
  894. else itemCount += multiplier;
  895. dropChance = dropChance % L2DropData.MAX_CHANCE;
  896. }
  897. // Check if the Item must be dropped
  898. int random = Rnd.get(L2DropData.MAX_CHANCE);
  899. while (random < dropChance)
  900. {
  901. // Get the item quantity dropped
  902. if (minCount < maxCount) itemCount += Rnd.get(minCount, maxCount);
  903. else if (minCount == maxCount) itemCount += minCount;
  904. else itemCount++;
  905. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  906. dropChance -= L2DropData.MAX_CHANCE;
  907. }
  908. if (Config.L2JMOD_CHAMPION_ENABLE)
  909. if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion())
  910. itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  911. if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount);
  912. else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop...");
  913. return null;
  914. }
  915. /**
  916. * Calculates quantity of items for specific drop CATEGORY according to current situation <br>
  917. * Only a max of ONE item from a category is allowed to be dropped.
  918. *
  919. * @param drop The L2DropData count is being calculated for
  920. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  921. * @param deepBlueDrop Factor to divide the drop chance
  922. * @param levelModifier level modifier in %'s (will be subtracted from drop chance)
  923. */
  924. private RewardItem calculateCategorizedRewardItem(L2PcInstance lastAttacker, L2DropCategory categoryDrops, int levelModifier)
  925. {
  926. if (categoryDrops == null)
  927. return null;
  928. // Get default drop chance for the category (that's the sum of chances for all items in the category)
  929. // keep track of the base category chance as it'll be used later, if an item is drop from the category.
  930. // for everything else, use the total "categoryDropChance"
  931. int basecategoryDropChance = categoryDrops.getCategoryChance() ;
  932. int categoryDropChance = basecategoryDropChance;
  933. int deepBlueDrop = 1;
  934. if (Config.DEEPBLUE_DROP_RULES)
  935. {
  936. if (levelModifier > 0)
  937. {
  938. // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs.
  939. // NOTE: This is valid only for adena drops! Others drops will still obey server's rate
  940. deepBlueDrop = 3;
  941. }
  942. }
  943. if(deepBlueDrop == 0) //avoid div by 0
  944. deepBlueDrop = 1;
  945. // Check if we should apply our maths so deep blue mobs will not drop that easy
  946. if (Config.DEEPBLUE_DROP_RULES) categoryDropChance = ((categoryDropChance - ((categoryDropChance * levelModifier)/100)) / deepBlueDrop);
  947. // Applies Drop rates
  948. categoryDropChance *= Config.RATE_DROP_ITEMS;
  949. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  950. categoryDropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  951. // Round drop chance
  952. categoryDropChance = Math.round(categoryDropChance);
  953. // Set our limits for chance of drop
  954. if (categoryDropChance < 1) categoryDropChance = 1;
  955. // Check if an Item from this category must be dropped
  956. if (Rnd.get(L2DropData.MAX_CHANCE) < categoryDropChance)
  957. {
  958. L2DropData drop = categoryDrops.dropOne();
  959. if (drop == null)
  960. return null;
  961. // Now decide the quantity to drop based on the rates and penalties. To get this value
  962. // simply divide the modified categoryDropChance by the base category chance. This
  963. // results in a chance that will dictate the drops amounts: for each amount over 100
  964. // that it is, it will give another chance to add to the min/max quantities.
  965. //
  966. // For example, If the final chance is 120%, then the item should drop between
  967. // its min and max one time, and then have 20% chance to drop again. If the final
  968. // chance is 330%, it will similarly give 3 times the min and max, and have a 30%
  969. // chance to give a 4th time.
  970. // At least 1 item will be dropped for sure. So the chance will be adjusted to 100%
  971. // if smaller.
  972. int dropChance = drop.getChance();
  973. if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA;
  974. else dropChance *= Config.RATE_DROP_ITEMS;
  975. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion())
  976. dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  977. dropChance = Math.round(dropChance);
  978. if (dropChance < L2DropData.MAX_CHANCE)
  979. dropChance = L2DropData.MAX_CHANCE;
  980. // Get min and max Item quantity that can be dropped in one time
  981. int min = drop.getMinDrop();
  982. int max = drop.getMaxDrop();
  983. // Get the item quantity dropped
  984. int itemCount = 0;
  985. // Count and chance adjustment for high rate servers
  986. if (dropChance > L2DropData.MAX_CHANCE && !Config.PRECISE_DROP_CALCULATION)
  987. {
  988. int multiplier = dropChance / L2DropData.MAX_CHANCE;
  989. if (min < max) itemCount += Rnd.get(min * multiplier, max * multiplier);
  990. else if (min == max) itemCount += min * multiplier;
  991. else itemCount += multiplier;
  992. dropChance = dropChance % L2DropData.MAX_CHANCE;
  993. }
  994. // Check if the Item must be dropped
  995. int random = Rnd.get(L2DropData.MAX_CHANCE);
  996. while (random < dropChance)
  997. {
  998. // Get the item quantity dropped
  999. if (min < max) itemCount += Rnd.get(min, max);
  1000. else if (min == max) itemCount += min;
  1001. else itemCount++;
  1002. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  1003. dropChance -= L2DropData.MAX_CHANCE;
  1004. }
  1005. if (Config.L2JMOD_CHAMPION_ENABLE)
  1006. if ((drop.getItemId() == 57 || (drop.getItemId() >= 6360 && drop.getItemId() <= 6362)) && isChampion())
  1007. itemCount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  1008. if (itemCount > 0)
  1009. return new RewardItem(drop.getItemId(), itemCount);
  1010. else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop...");
  1011. }
  1012. return null;
  1013. /*
  1014. // Applies Drop rates
  1015. if (drop.getItemId() == 57) dropChance *= Config.RATE_DROP_ADENA;
  1016. else if (isSweep) dropChance *= Config.RATE_DROP_SPOIL;
  1017. else dropChance *= Config.RATE_DROP_ITEMS;
  1018. // Round drop chance
  1019. dropChance = Math.round(dropChance);
  1020. // Set our limits for chance of drop
  1021. if (dropChance < 1) dropChance = 1;
  1022. // if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time
  1023. // Get min and max Item quantity that can be dropped in one time
  1024. int minCount = drop.getMinDrop();
  1025. int maxCount = drop.getMaxDrop();
  1026. int itemCount = 0;
  1027. if (itemCount > 0) return new RewardItem(drop.getItemId(), itemCount);
  1028. else if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop...");
  1029. return null;
  1030. */
  1031. }
  1032. /**
  1033. * Calculates the level modifier for drop<br>
  1034. *
  1035. * @param lastAttacker The L2PcInstance that has killed the L2Attackable
  1036. */
  1037. private int calculateLevelModifierForDrop(L2PcInstance lastAttacker)
  1038. {
  1039. if (Config.DEEPBLUE_DROP_RULES)
  1040. {
  1041. int highestLevel = lastAttacker.getLevel();
  1042. // Check to prevent very high level player to nearly kill mob and let low level player do the last hit.
  1043. if (getAttackByList() != null && !getAttackByList().isEmpty())
  1044. {
  1045. for (L2Character atkChar: getAttackByList())
  1046. if (atkChar != null && atkChar.getLevel() > highestLevel) highestLevel = atkChar.getLevel();
  1047. }
  1048. // According to official data (Prima), deep blue mobs are 9 or more levels below players
  1049. if (highestLevel - 9 >= getLevel()) return ((highestLevel - (getLevel() + 8)) * 9);
  1050. }
  1051. return 0;
  1052. }
  1053. public void doItemDrop(L2Character lastAttacker)
  1054. {
  1055. doItemDrop(getTemplate(),lastAttacker);
  1056. }
  1057. /**
  1058. * Manage Base, Quests and Special Events drops of L2Attackable (called by calculateRewards).<BR><BR>
  1059. *
  1060. * <B><U> Concept</U> :</B><BR><BR>
  1061. * During a Special Event all L2Attackable can drop extra Items.
  1062. * Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist.
  1063. * Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR><BR>
  1064. *
  1065. * <B><U> Actions</U> : </B><BR><BR>
  1066. * <li>Manage drop of Special Events created by GM for a defined period </li>
  1067. * <li>Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops</li>
  1068. * <li>For each possible drops (base + quests), calculate which one must be dropped (random) </li>
  1069. * <li>Get each Item quantity dropped (random) </li>
  1070. * <li>Create this or these L2ItemInstance corresponding to each Item Identifier dropped</li>
  1071. * <li>If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable</li>
  1072. * <li>If the autoLoot mode isn't actif or if the L2Character that has killed the L2Attackable is not a L2PcInstance, add this or these Item(s) in the world as a visible object at the position where mob was last</li><BR><BR>
  1073. *
  1074. * @param lastAttacker The L2Character that has killed the L2Attackable
  1075. */
  1076. public void doItemDrop(L2NpcTemplate npcTemplate, L2Character lastAttacker)
  1077. {
  1078. L2PcInstance player = null;
  1079. if (lastAttacker instanceof L2PcInstance) player = (L2PcInstance)lastAttacker;
  1080. else if (lastAttacker instanceof L2Summon) player = ((L2Summon)lastAttacker).getOwner();
  1081. if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  1082. int levelModifier = calculateLevelModifierForDrop(player); // level modifier in %'s (will be subtracted from drop chance)
  1083. // Check the drop of a cursed weapon
  1084. if (levelModifier == 0 && player.getLevel() > 20) // Not deep blue mob
  1085. CursedWeaponsManager.getInstance().checkDrop(this, player);
  1086. // now throw all categorized drops and handle spoil.
  1087. for(L2DropCategory cat:npcTemplate.getDropData())
  1088. {
  1089. RewardItem item = null;
  1090. if (cat.isSweep())
  1091. {
  1092. // according to sh1ny, seeded mobs CAN be spoiled and swept.
  1093. if ( isSpoil()/* && !isSeeded() */)
  1094. {
  1095. FastList<RewardItem> sweepList = new FastList<RewardItem>();
  1096. for(L2DropData drop: cat.getAllDrops() )
  1097. {
  1098. item = calculateRewardItem(player, drop, levelModifier, true);
  1099. if (item == null) continue;
  1100. if (Config.DEBUG) _log.fine("Item id to spoil: " + item.getItemId() + " amount: " + item.getCount());
  1101. sweepList.add(item);
  1102. }
  1103. // Set the table _sweepItems of this L2Attackable
  1104. if (!sweepList.isEmpty())
  1105. _sweepItems = sweepList.toArray(new RewardItem[sweepList.size()]);
  1106. }
  1107. }
  1108. else
  1109. {
  1110. if (isSeeded())
  1111. {
  1112. L2DropData drop = cat.dropSeedAllowedDropsOnly();
  1113. if(drop == null)
  1114. continue;
  1115. item = calculateRewardItem(player, drop, levelModifier, false);
  1116. }
  1117. else
  1118. {
  1119. item = calculateCategorizedRewardItem(player, cat, levelModifier);
  1120. }
  1121. if (item != null)
  1122. {
  1123. if (Config.DEBUG) _log.fine("Item id to drop: " + item.getItemId() + " amount: " + item.getCount());
  1124. // Check if the autoLoot mode is active
  1125. if (Config.AUTO_LOOT) player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  1126. else DropItem(player, item); // drop the item on the ground
  1127. // Broadcast message if RaidBoss was defeated
  1128. if(this instanceof L2RaidBossInstance)
  1129. {
  1130. SystemMessage sm;
  1131. sm = new SystemMessage(SystemMessageId.S1_DIED_DROPPED_S3_S2);
  1132. sm.addString(getName());
  1133. sm.addItemName(item.getItemId());
  1134. sm.addNumber(item.getCount());
  1135. broadcastPacket(sm);
  1136. }
  1137. }
  1138. }
  1139. }
  1140. // Apply Special Item drop with rnd qty for champions
  1141. if (Config.L2JMOD_CHAMPION_ENABLE && isChampion() && (player.getLevel() <= getLevel()) && Config.L2JMOD_CHAMPION_REWARD > 0 && (Rnd.get(100) < Config.L2JMOD_CHAMPION_REWARD))
  1142. {
  1143. int champqty = Rnd.get(Config.L2JMOD_CHAMPION_REWARD_QTY);
  1144. champqty++; //quantity should actually vary between 1 and whatever admin specified as max, inclusive.
  1145. RewardItem item = new RewardItem(Config.L2JMOD_CHAMPION_REWARD_ID,champqty);
  1146. if (Config.AUTO_LOOT) player.addItem("ChampionLoot", item.getItemId(), item.getCount(), this, true); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  1147. else DropItem(player, item);
  1148. }
  1149. //Instant Item Drop :>
  1150. double rateHp = getStat().calcStat(Stats.MAX_HP , 1, this, null);
  1151. if (rateHp <= 1 && String.valueOf(npcTemplate.type).contentEquals("L2Monster")) //only L2Monster with <= 1x HP can drop herbs
  1152. {
  1153. boolean _hp = false;
  1154. boolean _mp = false;
  1155. boolean _spec = false;
  1156. //ptk - patk type enhance
  1157. int random = Rnd.get(1000); // note *10
  1158. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec) // && !_spec useless yet
  1159. {
  1160. RewardItem item = new RewardItem(8612, 1); // Herb of Warrior
  1161. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1162. else DropItem(player, item);
  1163. _spec = true;
  1164. }
  1165. else for (int i = 0; i < 3; i++)
  1166. {
  1167. random = Rnd.get(100);
  1168. if (random < Config.RATE_DROP_COMMON_HERBS)
  1169. {
  1170. RewardItem item = null;
  1171. if (i == 0) item = new RewardItem(8606, 1); // Herb of Power
  1172. if (i == 1) item = new RewardItem(8608, 1); // Herb of Atk. Spd.
  1173. if (i == 2) item = new RewardItem(8610, 1); // Herb of Critical Attack
  1174. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1175. else DropItem(player, item);
  1176. break;
  1177. }
  1178. }
  1179. //mtk - matk type enhance
  1180. random = Rnd.get(1000); // note *10
  1181. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec)
  1182. {
  1183. RewardItem item = new RewardItem(8613, 1); // Herb of Mystic
  1184. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1185. else DropItem(player, item);
  1186. _spec = true;
  1187. }
  1188. else for (int i = 0; i < 2; i++)
  1189. {
  1190. random = Rnd.get(100);
  1191. if (random < Config.RATE_DROP_COMMON_HERBS)
  1192. {
  1193. RewardItem item = null;
  1194. if (i == 0) item = new RewardItem(8607, 1); // Herb of Magic
  1195. if (i == 1) item = new RewardItem(8609, 1); // Herb of Casting Speed
  1196. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1197. else DropItem(player, item);
  1198. break;
  1199. }
  1200. }
  1201. //hp+mp type
  1202. random = Rnd.get(1000); // note *10
  1203. if ((random < Config.RATE_DROP_SPECIAL_HERBS) && !_spec)
  1204. {
  1205. RewardItem item = new RewardItem(8614, 1); // Herb of Recovery
  1206. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1207. else DropItem(player, item);
  1208. _mp = true;
  1209. _hp = true;
  1210. _spec = true;
  1211. }
  1212. //hp - restore hp type
  1213. if (!_hp)
  1214. {
  1215. random = Rnd.get(100);
  1216. if (random < Config.RATE_DROP_MP_HP_HERBS)
  1217. {
  1218. RewardItem item = new RewardItem(8600, 1); // Herb of Life
  1219. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1220. else DropItem(player, item);
  1221. _hp = true;
  1222. }
  1223. }
  1224. if (!_hp)
  1225. {
  1226. random = Rnd.get(100);
  1227. if (random < Config.RATE_DROP_GREATER_HERBS)
  1228. {
  1229. RewardItem item = new RewardItem(8601, 1); // Greater Herb of Life
  1230. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1231. else DropItem(player, item);
  1232. _hp = true;
  1233. }
  1234. }
  1235. if (!_hp)
  1236. {
  1237. random = Rnd.get(1000); // note *10
  1238. if (random < Config.RATE_DROP_SUPERIOR_HERBS)
  1239. {
  1240. RewardItem item = new RewardItem(8602, 1); // Superior Herb of Life
  1241. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1242. else DropItem(player, item);
  1243. }
  1244. }
  1245. //mp - restore mp type
  1246. if (!_mp)
  1247. {
  1248. random = Rnd.get(100);
  1249. if (random < Config.RATE_DROP_MP_HP_HERBS)
  1250. {
  1251. RewardItem item = new RewardItem(8603, 1); // Herb of Manna
  1252. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1253. else DropItem(player, item);
  1254. _mp = true;
  1255. }
  1256. }
  1257. if (!_mp)
  1258. {
  1259. random = Rnd.get(100);
  1260. if (random < Config.RATE_DROP_GREATER_HERBS)
  1261. {
  1262. RewardItem item = new RewardItem(8604, 1); // Greater Herb of Mana
  1263. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1264. else DropItem(player, item);
  1265. _mp = true;
  1266. }
  1267. }
  1268. if (!_mp)
  1269. {
  1270. random = Rnd.get(1000); // note *10
  1271. if (random < Config.RATE_DROP_SUPERIOR_HERBS)
  1272. {
  1273. RewardItem item = new RewardItem(8605, 1); // Superior Herb of Mana
  1274. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1275. else DropItem(player, item);
  1276. }
  1277. }
  1278. // speed enhance type
  1279. random = Rnd.get(100);
  1280. if (random < Config.RATE_DROP_COMMON_HERBS)
  1281. {
  1282. RewardItem item = new RewardItem(8611, 1); // Herb of Speed
  1283. if (Config.AUTO_LOOT && Config.AUTO_LOOT_HERBS) player.addItem("Loot", item.getItemId(), item.getCount(), this, true);
  1284. else DropItem(player, item);
  1285. }
  1286. }
  1287. }
  1288. /**
  1289. * Manage Special Events drops created by GM for a defined period.<BR><BR>
  1290. *
  1291. * <B><U> Concept</U> :</B><BR><BR>
  1292. * During a Special Event all L2Attackable can drop extra Items.
  1293. * Those extra Items are defined in the table <B>allNpcDateDrops</B> of the EventDroplist.
  1294. * Each Special Event has a start and end date to stop to drop extra Items automaticaly. <BR><BR>
  1295. *
  1296. * <B><U> Actions</U> : <I>If an extra drop must be generated</I></B><BR><BR>
  1297. * <li>Get an Item Identifier (random) from the DateDrop Item table of this Event </li>
  1298. * <li>Get the Item quantity dropped (random) </li>
  1299. * <li>Create this or these L2ItemInstance corresponding to this Item Identifier</li>
  1300. * <li>If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable</li>
  1301. * <li>If the autoLoot mode isn't actif or if the L2Character that has killed the L2Attackable is not a L2PcInstance, add this or these Item(s) in the world as a visible object at the position where mob was last</li><BR><BR>
  1302. *
  1303. * @param lastAttacker The L2Character that has killed the L2Attackable
  1304. */
  1305. public void doEventDrop(L2Character lastAttacker)
  1306. {
  1307. L2PcInstance player = null;
  1308. if (lastAttacker instanceof L2PcInstance)
  1309. player = (L2PcInstance)lastAttacker;
  1310. else if (lastAttacker instanceof L2Summon)
  1311. player = ((L2Summon)lastAttacker).getOwner();
  1312. if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance
  1313. if (player.getLevel() - getLevel() > 9) return;
  1314. // Go through DateDrop of EventDroplist allNpcDateDrops within the date range
  1315. for (DateDrop drop : EventDroplist.getInstance().getAllDrops())
  1316. {
  1317. if (Rnd.get(L2DropData.MAX_CHANCE) < drop.chance)
  1318. {
  1319. RewardItem item = new RewardItem(drop.items[Rnd.get(drop.items.length)], Rnd.get(drop.min, drop.max));
  1320. if (Config.AUTO_LOOT) player.doAutoLoot(this, item); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  1321. else DropItem(player, item); // drop the item on the ground
  1322. }
  1323. }
  1324. }
  1325. /**
  1326. * Drop reward item.<BR><BR>
  1327. */
  1328. public L2ItemInstance DropItem(L2PcInstance lastAttacker, RewardItem item)
  1329. {
  1330. int randDropLim = 70;
  1331. L2ItemInstance ditem = null;
  1332. for (int i = 0; i < item.getCount(); i++)
  1333. {
  1334. // Randomize drop position
  1335. int newX = getX() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1336. int newY = getY() + Rnd.get(randDropLim * 2 + 1) - randDropLim;
  1337. int newZ = Math.max(getZ(), lastAttacker.getZ()) + 20; // TODO: temp hack, do somethign nicer when we have geodatas
  1338. // Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last
  1339. ditem = ItemTable.getInstance().createItem("Loot", item.getItemId(), item.getCount(), lastAttacker, this);
  1340. ditem.dropMe(this, newX, newY, newZ);
  1341. // Add drop to auto destroy item task
  1342. if (!Config.LIST_PROTECTED_ITEMS.contains(item.getItemId())){
  1343. if ((Config.AUTODESTROY_ITEM_AFTER > 0 && ditem.getItemType() != L2EtcItemType.HERB)
  1344. || (Config.HERB_AUTO_DESTROY_TIME > 0 && ditem.getItemType() == L2EtcItemType.HERB))
  1345. ItemsAutoDestroy.getInstance().addItem(ditem);
  1346. }
  1347. ditem.setProtected(false);
  1348. // If stackable, end loop as entire count is included in 1 instance of item
  1349. if (ditem.isStackable() || !Config.MULTIPLE_ITEM_DROP) break;
  1350. }
  1351. return ditem;
  1352. }
  1353. public L2ItemInstance DropItem(L2PcInstance lastAttacker, int itemId, int itemCount)
  1354. {
  1355. return DropItem(lastAttacker, new RewardItem(itemId, itemCount));
  1356. }
  1357. /**
  1358. * Return the active weapon of this L2Attackable (= null).<BR><BR>
  1359. */
  1360. public L2ItemInstance getActiveWeapon()
  1361. {
  1362. return null;
  1363. }
  1364. /**
  1365. * Return True if the _aggroList of this L2Attackable is Empty.<BR><BR>
  1366. */
  1367. public boolean noTarget()
  1368. {
  1369. return getAggroListRP().isEmpty();
  1370. }
  1371. /**
  1372. * Return True if the _aggroList of this L2Attackable contains the L2Character.<BR><BR>
  1373. *
  1374. * @param player The L2Character searched in the _aggroList of the L2Attackable
  1375. *
  1376. */
  1377. public boolean containsTarget(L2Character player)
  1378. {
  1379. return getAggroListRP().containsKey(player);
  1380. }
  1381. /**
  1382. * Clear the _aggroList of the L2Attackable.<BR><BR>
  1383. */
  1384. public void clearAggroList()
  1385. {
  1386. getAggroList().clear();
  1387. }
  1388. /**
  1389. * Return True if a Dwarf use Sweep on the L2Attackable and if item can be spoiled.<BR><BR>
  1390. */
  1391. public boolean isSweepActive()
  1392. {
  1393. return _sweepItems != null;
  1394. }
  1395. /**
  1396. * Return table containing all L2ItemInstance that can be spoiled.<BR><BR>
  1397. */
  1398. public synchronized RewardItem[] takeSweep()
  1399. {
  1400. RewardItem[] sweep = _sweepItems;
  1401. _sweepItems = null;
  1402. return sweep;
  1403. }
  1404. /**
  1405. * Return table containing all L2ItemInstance that can be harvested.<BR><BR>
  1406. */
  1407. public synchronized RewardItem[] takeHarvest()
  1408. {
  1409. RewardItem[] harvest = _harvestItems;
  1410. _harvestItems = null;
  1411. return harvest;
  1412. }
  1413. /**
  1414. * Set the over-hit flag on the L2Attackable.<BR><BR>
  1415. *
  1416. * @param status The status of the over-hit flag
  1417. *
  1418. */
  1419. public void overhitEnabled(boolean status)
  1420. {
  1421. _overhit = status;
  1422. }
  1423. /**
  1424. * Set the over-hit values like the attacker who did the strike and the ammount of damage done by the skill.<BR><BR>
  1425. *
  1426. * @param attacker The L2Character who hit on the L2Attackable using the over-hit enabled skill
  1427. * @param damage The ammount of damage done by the over-hit enabled skill on the L2Attackable
  1428. *
  1429. */
  1430. public void setOverhitValues(L2Character attacker, double damage)
  1431. {
  1432. // Calculate the over-hit damage
  1433. // Ex: mob had 10 HP left, over-hit skill did 50 damage total, over-hit damage is 40
  1434. double overhitDmg = ((getCurrentHp() - damage) * (-1));
  1435. if (overhitDmg < 0)
  1436. {
  1437. // we didn't killed the mob with the over-hit strike. (it wasn't really an over-hit strike)
  1438. // let's just clear all the over-hit related values
  1439. overhitEnabled(false);
  1440. _overhitDamage = 0;
  1441. _overhitAttacker = null;
  1442. return;
  1443. }
  1444. overhitEnabled(true);
  1445. _overhitDamage = overhitDmg;
  1446. _overhitAttacker = attacker;
  1447. }
  1448. /**
  1449. * Return the L2Character who hit on the L2Attackable using an over-hit enabled skill.<BR><BR>
  1450. *
  1451. * @return L2Character attacker
  1452. */
  1453. public L2Character getOverhitAttacker()
  1454. {
  1455. return _overhitAttacker;
  1456. }
  1457. /**
  1458. * Return the ammount of damage done on the L2Attackable using an over-hit enabled skill.<BR><BR>
  1459. *
  1460. * @return double damage
  1461. */
  1462. public double getOverhitDamage()
  1463. {
  1464. return _overhitDamage;
  1465. }
  1466. /**
  1467. * Return True if the L2Attackable was hit by an over-hit enabled skill.<BR><BR>
  1468. */
  1469. public boolean isOverhit()
  1470. {
  1471. return _overhit;
  1472. }
  1473. /**
  1474. * Activate the absorbed soul condition on the L2Attackable.<BR><BR>
  1475. */
  1476. public void absorbSoul()
  1477. {
  1478. _absorbed = true;
  1479. }
  1480. /**
  1481. * Return True if the L2Attackable had his soul absorbed.<BR><BR>
  1482. */
  1483. public boolean isAbsorbed()
  1484. {
  1485. return _absorbed;
  1486. }
  1487. /**
  1488. * Adds an attacker that successfully absorbed the soul of this L2Attackable into the _absorbersList.<BR><BR>
  1489. *
  1490. * params: attacker - a valid L2PcInstance
  1491. * condition - an integer indicating the event when mob dies. This should be:
  1492. * = 0 - "the crystal scatters";
  1493. * = 1 - "the crystal failed to absorb. nothing happens";
  1494. * = 2 - "the crystal resonates because you got more than 1 crystal on you";
  1495. * = 3 - "the crystal cannot absorb the soul because the mob level is too low";
  1496. * = 4 - "the crystal successfuly absorbed the soul";
  1497. */
  1498. public void addAbsorber(L2PcInstance attacker, int crystalId)
  1499. {
  1500. // This just works for targets like L2MonsterInstance
  1501. if (!(this instanceof L2MonsterInstance))
  1502. return;
  1503. // The attacker must not be null
  1504. if (attacker == null)
  1505. return;
  1506. // This L2Attackable must be of one type in the _absorbingMOBS_levelXX tables.
  1507. // OBS: This is done so to avoid triggering the absorbed conditions for mobs that can't be absorbed.
  1508. if (getAbsorbLevel() == 0)
  1509. return;
  1510. // If we have no _absorbersList initiated, do it
  1511. AbsorberInfo ai = _absorbersList.get(attacker);
  1512. // If the L2Character attacker isn't already in the _absorbersList of this L2Attackable, add it
  1513. if (ai == null)
  1514. {
  1515. ai = new AbsorberInfo(attacker, crystalId, getCurrentHp());
  1516. _absorbersList.put(attacker, ai);
  1517. }
  1518. else
  1519. {
  1520. ai._absorber = attacker;
  1521. ai._crystalId = crystalId;
  1522. ai._absorbedHP = getCurrentHp();
  1523. }
  1524. // Set this L2Attackable as absorbed
  1525. absorbSoul();
  1526. }
  1527. /**
  1528. * Calculate the leveling chance of Soul Crystals based on the attacker that killed this L2Attackable
  1529. *
  1530. * @param attacker The player that last killed this L2Attackable
  1531. * $ Rewrite 06.12.06 - Yesod
  1532. */
  1533. private void levelSoulCrystals(L2Character attacker)
  1534. {
  1535. // Only L2PcInstance can absorb a soul
  1536. if (!(attacker instanceof L2PcInstance) && !(attacker instanceof L2Summon))
  1537. {
  1538. resetAbsorbList(); return;
  1539. }
  1540. int maxAbsorbLevel = getAbsorbLevel();
  1541. int minAbsorbLevel = 0;
  1542. // If this is not a valid L2Attackable, clears the _absorbersList and just return
  1543. if (maxAbsorbLevel == 0)
  1544. {
  1545. resetAbsorbList(); return;
  1546. }
  1547. // All boss mobs with maxAbsorbLevel 13 have minAbsorbLevel of 12 else 10
  1548. if (maxAbsorbLevel > 10)
  1549. minAbsorbLevel = maxAbsorbLevel > 12 ? 12 : 10;
  1550. //Init some useful vars
  1551. boolean isSuccess = true;
  1552. boolean doLevelup = true;
  1553. boolean isBossMob = maxAbsorbLevel > 10 ? true : false;
  1554. L2NpcTemplate.AbsorbCrystalType absorbType = getTemplate().absorbType;
  1555. L2PcInstance killer = (attacker instanceof L2Summon)? ((L2Summon)attacker).getOwner() : (L2PcInstance)attacker;
  1556. // If this mob is a boss, then skip some checkings
  1557. if (!isBossMob)
  1558. {
  1559. // Fail if this L2Attackable isn't absorbed or there's no one in its _absorbersList
  1560. if (!isAbsorbed() /*|| _absorbersList == null*/)
  1561. {
  1562. resetAbsorbList();
  1563. return;
  1564. }
  1565. // Fail if the killer isn't in the _absorbersList of this L2Attackable and mob is not boss
  1566. AbsorberInfo ai = _absorbersList.get(killer);
  1567. if (ai == null || ai._absorber.getObjectId() != killer.getObjectId())
  1568. isSuccess = false;
  1569. // Check if the soul crystal was used when HP of this L2Attackable wasn't higher than half of it
  1570. if (ai != null && ai._absorbedHP > (getMaxHp()/2.0))
  1571. isSuccess = false;
  1572. if (!isSuccess) {
  1573. resetAbsorbList();
  1574. return;
  1575. }
  1576. }
  1577. // ********
  1578. String[] crystalNFO = null;
  1579. String crystalNME = "";
  1580. int dice = Rnd.get(100);
  1581. int crystalQTY = 0;
  1582. int crystalLVL = 0;
  1583. int crystalOLD = 0;
  1584. int crystalNEW = 0;
  1585. // ********
  1586. // Now we have four choices:
  1587. // 1- The Monster level is too low for the crystal. Nothing happens.
  1588. // 2- Everything is correct, but it failed. Nothing happens. (57.5%)
  1589. // 3- Everything is correct, but it failed. The crystal scatters. A sound event is played. (10%)
  1590. // 4- Everything is correct, the crystal level up. A sound event is played. (32.5%)
  1591. List<L2PcInstance> players = new FastList<L2PcInstance>();
  1592. if (absorbType == L2NpcTemplate.AbsorbCrystalType.FULL_PARTY && killer.isInParty())
  1593. players = killer.getParty().getPartyMembers();
  1594. else if (absorbType == L2NpcTemplate.AbsorbCrystalType.PARTY_ONE_RANDOM && killer.isInParty())
  1595. {
  1596. // This is a naive method for selecting a random member. It gets any random party member and
  1597. // then checks if the member has a valid crystal. It does not select the random party member
  1598. // among those who have crystals, only. However, this might actually be correct (same as retail).
  1599. players.add(killer.getParty().getPartyMembers().get(Rnd.get(killer.getParty().getMemberCount())));
  1600. }
  1601. else
  1602. players.add(killer);
  1603. for (L2PcInstance player : players)
  1604. {
  1605. if (player == null) continue;
  1606. crystalQTY = 0;
  1607. L2ItemInstance[] inv = player.getInventory().getItems();
  1608. for (L2ItemInstance item : inv)
  1609. {
  1610. int itemId = item.getItemId();
  1611. for (int id : SoulCrystal.SoulCrystalTable)
  1612. {
  1613. // Find any of the 39 possible crystals.
  1614. if (id == itemId)
  1615. {
  1616. crystalQTY++;
  1617. // Keep count but make sure the player has no more than 1 crystal
  1618. if (crystalQTY > 1)
  1619. {
  1620. isSuccess = false; break;
  1621. }
  1622. // Validate if the crystal has already leveled
  1623. if(id != SoulCrystal.RED_NEW_CRYSTAL
  1624. && id != SoulCrystal.GRN_NEW_CYRSTAL
  1625. && id != SoulCrystal.BLU_NEW_CRYSTAL)
  1626. {
  1627. try
  1628. {
  1629. if (item.getItem().getName().contains("Grade"))
  1630. {
  1631. // Split the name of the crystal into 'name' & 'level'
  1632. crystalNFO = item.getItem().getName().trim().replace(" Grade ", "-").split("-");
  1633. // Set Level to 13
  1634. crystalLVL = 13;
  1635. // Get Name
  1636. crystalNME = crystalNFO[0].toLowerCase();
  1637. } else
  1638. {
  1639. // Split the name of the crystal into 'name' & 'level'
  1640. crystalNFO = item.getItem().getName().trim().replace(" Stage ", "").split("-");
  1641. // Get Level
  1642. crystalLVL = Integer.parseInt(crystalNFO[1].trim());
  1643. // Get Name
  1644. crystalNME = crystalNFO[0].toLowerCase();
  1645. }
  1646. // Allocate current and levelup ids' for higher level crystals
  1647. if(crystalLVL > 9)
  1648. {
  1649. for(int i = 0; i < SoulCrystal.HighSoulConvert.length; i++)
  1650. // Get the next stage above 10 using array.
  1651. if(id == SoulCrystal.HighSoulConvert[i][0])
  1652. {
  1653. crystalNEW = SoulCrystal.HighSoulConvert[i][1]; break;
  1654. }
  1655. }
  1656. else
  1657. crystalNEW = id+1;
  1658. }
  1659. catch (NumberFormatException nfe)
  1660. {
  1661. _log.log(Level.WARNING, "An attempt to identify a soul crystal failed, " +
  1662. "verify the names have not changed in etcitem " +
  1663. "table.", nfe);
  1664. player.sendMessage("There has been an error handling your soul crystal." +
  1665. " Please notify your server admin.");
  1666. isSuccess = false;
  1667. break;
  1668. }
  1669. catch (Exception e)
  1670. {
  1671. e.printStackTrace();
  1672. isSuccess = false;
  1673. break;
  1674. }
  1675. }
  1676. else
  1677. {
  1678. crystalNME = item.getItem().getName().toLowerCase().trim();
  1679. crystalNEW = id+1;
  1680. }
  1681. // Done
  1682. crystalOLD = id;
  1683. break;
  1684. }
  1685. }
  1686. if (!isSuccess) break;
  1687. }
  1688. // If the crystal level is way too high for this mob, say that we can't increase it
  1689. if ((crystalLVL < minAbsorbLevel) || (crystalLVL >= maxAbsorbLevel))
  1690. doLevelup = false;
  1691. // The player doesn't have any crystals with him get to the next player.
  1692. if (crystalQTY < 1 || crystalQTY > 1 || !isSuccess || !doLevelup)
  1693. {
  1694. // Too many crystals in inventory.
  1695. if (crystalQTY > 1)
  1696. {
  1697. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_FAILED_RESONATION));
  1698. }
  1699. // The soul crystal stage of the player is way too high
  1700. else if (!doLevelup)
  1701. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_REFUSED));
  1702. crystalQTY = 0;
  1703. continue;
  1704. }
  1705. /* TODO: Confirm boss chance for crystal level up and for crystal breaking.
  1706. * It is known that bosses with FULL_PARTY crystal level ups have 100% success rate, but this is not
  1707. * the case for the other bosses (one-random or last-hit).
  1708. * While not confirmed, it is most reasonable that crystals leveled up at bosses will never break.
  1709. * Also, the chance to level up is guessed as around 70% if not higher.
  1710. */
  1711. int chanceLevelUp = isBossMob? 70:SoulCrystal.LEVEL_CHANCE;
  1712. // If succeeds or it is a full party absorb, level up the crystal.
  1713. if (((absorbType == L2NpcTemplate.AbsorbCrystalType.FULL_PARTY) && doLevelup) || (dice <= chanceLevelUp))
  1714. {
  1715. // Give staged crystal
  1716. exchangeCrystal(player, crystalOLD, crystalNEW, false);
  1717. }
  1718. // If true and not a last-hit mob, break the crystal.
  1719. else if ((!isBossMob) && dice >= (100.0 - SoulCrystal.BREAK_CHANCE))
  1720. {
  1721. // Remove current crystal an give a broken open.
  1722. if (crystalNME.startsWith("red"))
  1723. exchangeCrystal(player, crystalOLD, SoulCrystal.RED_BROKEN_CRYSTAL, true);
  1724. else if (crystalNME.startsWith("gre"))
  1725. exchangeCrystal(player, crystalOLD, SoulCrystal.GRN_BROKEN_CYRSTAL, true);
  1726. else if (crystalNME.startsWith("blu"))
  1727. exchangeCrystal(player, crystalOLD, SoulCrystal.BLU_BROKEN_CRYSTAL, true);
  1728. resetAbsorbList();
  1729. }
  1730. else
  1731. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_FAILED));
  1732. }
  1733. }
  1734. private void exchangeCrystal(L2PcInstance player, int takeid, int giveid, boolean broke)
  1735. {
  1736. L2ItemInstance Item = player.getInventory().destroyItemByItemId("SoulCrystal", takeid, 1, player, this);
  1737. if (Item != null)
  1738. {
  1739. // Prepare inventory update packet
  1740. InventoryUpdate playerIU = new InventoryUpdate();
  1741. playerIU.addRemovedItem(Item);
  1742. // Add new crystal to the killer's inventory
  1743. Item = player.getInventory().addItem("SoulCrystal", giveid, 1, player, this);
  1744. playerIU.addItem(Item);
  1745. // Send a sound event and text message to the player
  1746. if(broke)
  1747. {
  1748. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_BROKE));
  1749. }
  1750. else
  1751. player.sendPacket(new SystemMessage(SystemMessageId.SOUL_CRYSTAL_ABSORBING_SUCCEEDED));
  1752. // Send system message
  1753. SystemMessage sms = new SystemMessage(SystemMessageId.EARNED_ITEM);
  1754. sms.addItemName(giveid);
  1755. player.sendPacket(sms);
  1756. // Send inventory update packet
  1757. player.sendPacket(playerIU);
  1758. }
  1759. }
  1760. private void resetAbsorbList()
  1761. {
  1762. _absorbed = false;
  1763. _absorbersList.clear();
  1764. }
  1765. /**
  1766. * Calculate the Experience and SP to distribute to attacker (L2PcInstance, L2SummonInstance or L2Party) of the L2Attackable.<BR><BR>
  1767. *
  1768. * @param diff The difference of level between attacker (L2PcInstance, L2SummonInstance or L2Party) and the L2Attackable
  1769. * @param damage The damages given by the attacker (L2PcInstance, L2SummonInstance or L2Party)
  1770. *
  1771. */
  1772. private int[] calculateExpAndSp(int diff, int damage)
  1773. {
  1774. double xp;
  1775. double sp;
  1776. if(diff < -5) diff = -5; // makes possible to use ALT_GAME_EXPONENT configuration
  1777. xp = (double)getExpReward() * damage / getMaxHp();
  1778. if (Config.ALT_GAME_EXPONENT_XP != 0) xp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_XP);
  1779. sp = (double)getSpReward() * damage / getMaxHp();
  1780. if (Config.ALT_GAME_EXPONENT_SP != 0) sp *= Math.pow(2., -diff / Config.ALT_GAME_EXPONENT_SP);
  1781. if (Config.ALT_GAME_EXPONENT_XP == 0 && Config.ALT_GAME_EXPONENT_SP == 0)
  1782. {
  1783. if(diff > 5) // formula revised May 07
  1784. {
  1785. double pow = Math.pow((double)5/6, diff-5);
  1786. xp = xp*pow;
  1787. sp = sp*pow;
  1788. }
  1789. if (xp <= 0)
  1790. {
  1791. xp = 0;
  1792. sp = 0;
  1793. }
  1794. else if (sp <= 0)
  1795. {
  1796. sp = 0;
  1797. }
  1798. }
  1799. int[] tmp = { (int)xp, (int)sp };
  1800. return tmp;
  1801. }
  1802. public long calculateOverhitExp(long normalExp)
  1803. {
  1804. // Get the percentage based on the total of extra (over-hit) damage done relative to the total (maximum) ammount of HP on the L2Attackable
  1805. double overhitPercentage = ((getOverhitDamage() * 100) / getMaxHp());
  1806. // Over-hit damage percentages are limited to 25% max
  1807. if (overhitPercentage > 25)
  1808. overhitPercentage = 25;
  1809. // Get the overhit exp bonus according to the above over-hit damage percentage
  1810. // (1/1 basis - 13% of over-hit damage, 13% of extra exp is given, and so on...)
  1811. double overhitExp = ((overhitPercentage / 100) * normalExp);
  1812. // Return the rounded ammount of exp points to be added to the player's normal exp reward
  1813. long bonusOverhit = Math.round(overhitExp);
  1814. return bonusOverhit;
  1815. }
  1816. /**
  1817. * Return True.<BR><BR>
  1818. */
  1819. @Override
  1820. public boolean isAttackable()
  1821. {
  1822. return true;
  1823. }
  1824. @Override
  1825. public void onSpawn()
  1826. {
  1827. super.onSpawn();
  1828. // Clear mob spoil,seed
  1829. setSpoil(false);
  1830. // Clear all aggro char from list
  1831. clearAggroList();
  1832. // Clear Harvester Rewrard List
  1833. _harvestItems = null;
  1834. // Clear mod Seeded stat
  1835. setSeeded(false);
  1836. _sweepItems = null;
  1837. resetAbsorbList();
  1838. setWalking();
  1839. // check the region where this mob is, do not activate the AI if region is inactive.
  1840. if (!isInActiveRegion())
  1841. if (this instanceof L2SiegeGuardInstance)
  1842. ((L2SiegeGuardAI) getAI()).stopAITask();
  1843. else
  1844. ((L2AttackableAI) getAI()).stopAITask();
  1845. }
  1846. /**
  1847. * Sets state of the mob to seeded. Paramets needed to be set before.
  1848. */
  1849. public void setSeeded()
  1850. {
  1851. if (_seedType != 0 && _seeder != null)
  1852. setSeeded(_seedType, _seeder.getLevel());
  1853. }
  1854. /**
  1855. * Sets the seed parametrs, but not the seed state
  1856. * @param id - id of the seed
  1857. * @param seeder - player who is sowind the seed
  1858. */
  1859. public void setSeeded(int id, L2PcInstance seeder)
  1860. {
  1861. if (!_seeded) {
  1862. _seedType = id;
  1863. _seeder = seeder;
  1864. }
  1865. }
  1866. public void setSeeded(int id, int seederLvl)
  1867. {
  1868. _seeded = true;
  1869. _seedType = id;
  1870. int count = 1;
  1871. Map<Integer, L2Skill> skills = getTemplate().getSkills();
  1872. if (skills != null)
  1873. {
  1874. for (int skillId : skills.keySet())
  1875. {
  1876. switch (skillId) {
  1877. case 4303: //Strong type x2
  1878. count *= 2;
  1879. break;
  1880. case 4304: //Strong type x3
  1881. count *= 3;
  1882. break;
  1883. case 4305: //Strong type x4
  1884. count *= 4;
  1885. break;
  1886. case 4306: //Strong type x5
  1887. count *= 5;
  1888. break;
  1889. case 4307: //Strong type x6
  1890. count *= 6;
  1891. break;
  1892. case 4308: //Strong type x7
  1893. count *= 7;
  1894. break;
  1895. case 4309: //Strong type x8
  1896. count *= 8;
  1897. break;
  1898. case 4310: //Strong type x9
  1899. count *= 9;
  1900. break;
  1901. }
  1902. }
  1903. }
  1904. int diff = (getLevel() - (L2Manor.getInstance().getSeedLevel(_seedType) - 5));
  1905. // hi-lvl mobs bonus
  1906. if (diff > 0)
  1907. {
  1908. count += diff;
  1909. }
  1910. FastList<RewardItem> harvested = new FastList<RewardItem>();
  1911. harvested.add(new RewardItem(L2Manor.getInstance().getCropType(_seedType), count* Config.RATE_DROP_MANOR));
  1912. _harvestItems = harvested.toArray(new RewardItem[harvested.size()]);
  1913. }
  1914. public void setSeeded(boolean seeded)
  1915. {
  1916. _seeded = seeded;
  1917. }
  1918. public L2PcInstance getSeeder()
  1919. {
  1920. return _seeder;
  1921. }
  1922. public int getSeedType()
  1923. {
  1924. return _seedType;
  1925. }
  1926. public boolean isSeeded()
  1927. {
  1928. return _seeded;
  1929. }
  1930. private int getAbsorbLevel()
  1931. {
  1932. return getTemplate().absorbLevel;
  1933. }
  1934. /**
  1935. * Check if the server allows Random Animation.<BR><BR>
  1936. */
  1937. // This is located here because L2Monster and L2FriendlyMob both extend this class. The other non-pc instances extend either L2NpcInstance or L2MonsterInstance.
  1938. @Override
  1939. public boolean hasRandomAnimation()
  1940. {
  1941. return ((Config.MAX_MONSTER_ANIMATION > 0) && !(this instanceof L2BossInstance));
  1942. }
  1943. @Override
  1944. public boolean isMob()
  1945. {
  1946. return true; // This means we use MAX_MONSTER_ANIMATION instead of MAX_NPC_ANIMATION
  1947. }
  1948. protected void setCommandChannelTimer(CommandChannelTimer commandChannelTimer)
  1949. {
  1950. _commandChannelTimer = commandChannelTimer;
  1951. }
  1952. public CommandChannelTimer getCommandChannelTimer()
  1953. {
  1954. return _commandChannelTimer;
  1955. }
  1956. public L2CommandChannel getFirstCommandChannelAttacked()
  1957. {
  1958. return _firstCommandChannelAttacked;
  1959. }
  1960. public void setFirstCommandChannelAttacked(
  1961. L2CommandChannel firstCommandChannelAttacked)
  1962. {
  1963. _firstCommandChannelAttacked = firstCommandChannelAttacked;
  1964. }
  1965. private class CommandChannelTimer implements Runnable
  1966. {
  1967. private L2Attackable _monster;
  1968. private L2CommandChannel _channel;
  1969. public CommandChannelTimer(L2Attackable monster, L2CommandChannel channel)
  1970. {
  1971. _monster = monster;
  1972. _channel = channel;
  1973. }
  1974. /**
  1975. * @see java.lang.Runnable#run()
  1976. */
  1977. public void run()
  1978. {
  1979. _monster.setCommandChannelTimer(null);
  1980. _monster.setFirstCommandChannelAttacked(null);
  1981. for (L2Character player : _monster.getAggroListRP().keySet())
  1982. {
  1983. if (player.isInParty() && player.getParty().isInCommandChannel())
  1984. {
  1985. if (player.getParty().getCommandChannel().equals(_channel))
  1986. {
  1987. // if a player which is in first attacked CommandChannel, restart the timer ;)
  1988. _monster.setCommandChannelTimer(this);
  1989. _monster.setFirstCommandChannelAttacked(_channel);
  1990. ThreadPoolManager.getInstance().scheduleGeneral(this, 300000); // 5 min
  1991. break;
  1992. }
  1993. }
  1994. }
  1995. }
  1996. }
  1997. }