L2Attackable.java 78 KB

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