Quest.java 125 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931
  1. /*
  2. * Copyright (C) 2004-2014 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J Server is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.l2jserver.gameserver.model.quest;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.ResultSet;
  23. import java.util.ArrayList;
  24. import java.util.Collection;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.Set;
  30. import java.util.concurrent.locks.ReentrantReadWriteLock;
  31. import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
  32. import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
  33. import java.util.logging.Level;
  34. import java.util.logging.Logger;
  35. import com.l2jserver.Config;
  36. import com.l2jserver.L2DatabaseFactory;
  37. import com.l2jserver.gameserver.GameTimeController;
  38. import com.l2jserver.gameserver.ThreadPoolManager;
  39. import com.l2jserver.gameserver.cache.HtmCache;
  40. import com.l2jserver.gameserver.datatables.DoorTable;
  41. import com.l2jserver.gameserver.datatables.ItemTable;
  42. import com.l2jserver.gameserver.datatables.NpcData;
  43. import com.l2jserver.gameserver.enums.QuestEventType;
  44. import com.l2jserver.gameserver.enums.QuestSound;
  45. import com.l2jserver.gameserver.enums.TrapAction;
  46. import com.l2jserver.gameserver.idfactory.IdFactory;
  47. import com.l2jserver.gameserver.instancemanager.InstanceManager;
  48. import com.l2jserver.gameserver.instancemanager.QuestManager;
  49. import com.l2jserver.gameserver.instancemanager.ZoneManager;
  50. import com.l2jserver.gameserver.model.L2Object;
  51. import com.l2jserver.gameserver.model.L2Party;
  52. import com.l2jserver.gameserver.model.L2Spawn;
  53. import com.l2jserver.gameserver.model.Location;
  54. import com.l2jserver.gameserver.model.actor.L2Attackable;
  55. import com.l2jserver.gameserver.model.actor.L2Character;
  56. import com.l2jserver.gameserver.model.actor.L2Npc;
  57. import com.l2jserver.gameserver.model.actor.L2Playable;
  58. import com.l2jserver.gameserver.model.actor.L2Summon;
  59. import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
  60. import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
  61. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  62. import com.l2jserver.gameserver.model.actor.instance.L2TrapInstance;
  63. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  64. import com.l2jserver.gameserver.model.base.AcquireSkillType;
  65. import com.l2jserver.gameserver.model.entity.Instance;
  66. import com.l2jserver.gameserver.model.holders.ItemHolder;
  67. import com.l2jserver.gameserver.model.interfaces.IIdentifiable;
  68. import com.l2jserver.gameserver.model.interfaces.IPositionable;
  69. import com.l2jserver.gameserver.model.interfaces.IProcedure;
  70. import com.l2jserver.gameserver.model.itemcontainer.Inventory;
  71. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  72. import com.l2jserver.gameserver.model.items.L2Item;
  73. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  74. import com.l2jserver.gameserver.model.olympiad.CompetitionType;
  75. import com.l2jserver.gameserver.model.quest.AITasks.AggroRangeEnter;
  76. import com.l2jserver.gameserver.model.quest.AITasks.SeeCreature;
  77. import com.l2jserver.gameserver.model.quest.AITasks.SkillSee;
  78. import com.l2jserver.gameserver.model.skills.L2Skill;
  79. import com.l2jserver.gameserver.model.stats.Stats;
  80. import com.l2jserver.gameserver.model.zone.L2ZoneType;
  81. import com.l2jserver.gameserver.network.NpcStringId;
  82. import com.l2jserver.gameserver.network.SystemMessageId;
  83. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  84. import com.l2jserver.gameserver.network.serverpackets.ExShowScreenMessage;
  85. import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
  86. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  87. import com.l2jserver.gameserver.network.serverpackets.NpcQuestHtmlMessage;
  88. import com.l2jserver.gameserver.network.serverpackets.SpecialCamera;
  89. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  90. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  91. import com.l2jserver.gameserver.scripting.ManagedScript;
  92. import com.l2jserver.gameserver.scripting.ScriptManager;
  93. import com.l2jserver.gameserver.util.MinionList;
  94. import com.l2jserver.util.L2FastMap;
  95. import com.l2jserver.util.Rnd;
  96. import com.l2jserver.util.Util;
  97. /**
  98. * Quest main class.
  99. * @author Luis Arias
  100. */
  101. public class Quest extends ManagedScript implements IIdentifiable
  102. {
  103. public static final Logger _log = Logger.getLogger(Quest.class.getName());
  104. /** Map containing events from String value of the event. */
  105. private static Map<String, Quest> _allEventsS = new HashMap<>();
  106. /** Map containing lists of timers from the name of the timer. */
  107. private final Map<String, List<QuestTimer>> _allEventTimers = new L2FastMap<>(true);
  108. private final Set<Integer> _questInvolvedNpcs = new HashSet<>();
  109. private final ReentrantReadWriteLock _rwLock = new ReentrantReadWriteLock();
  110. private final WriteLock _writeLock = _rwLock.writeLock();
  111. private final ReadLock _readLock = _rwLock.readLock();
  112. private final int _questId;
  113. private final String _name;
  114. private final String _descr;
  115. private final byte _initialState = State.CREATED;
  116. protected boolean _onEnterWorld = false;
  117. private boolean _isCustom = false;
  118. private boolean _isOlympiadUse = false;
  119. public int[] questItemIds = null;
  120. private static final String DEFAULT_NO_QUEST_MSG = "<html><body>You are either not on a quest that involves this NPC, or you don't meet this NPC's minimum quest requirements.</body></html>";
  121. private static final String DEFAULT_ALREADY_COMPLETED_MSG = "<html><body>This quest has already been completed.</body></html>";
  122. private static final String QUEST_DELETE_FROM_CHAR_QUERY = "DELETE FROM character_quests WHERE charId=? AND name=?";
  123. private static final String QUEST_DELETE_FROM_CHAR_QUERY_NON_REPEATABLE_QUERY = "DELETE FROM character_quests WHERE charId=? AND name=? AND var!=?";
  124. private static final int RESET_HOUR = 6;
  125. private static final int RESET_MINUTES = 30;
  126. /**
  127. * @return the reset hour for a daily quest, could be overridden on a script.
  128. */
  129. public int getResetHour()
  130. {
  131. return RESET_HOUR;
  132. }
  133. /**
  134. * @return the reset minutes for a daily quest, could be overridden on a script.
  135. */
  136. public int getResetMinutes()
  137. {
  138. return RESET_MINUTES;
  139. }
  140. /**
  141. * @return a collection of the values contained in the _allEventsS map.
  142. */
  143. public static Collection<Quest> findAllEvents()
  144. {
  145. return _allEventsS.values();
  146. }
  147. /**
  148. * The Quest object constructor.<br>
  149. * Constructing a quest also calls the {@code init_LoadGlobalData} convenience method.
  150. * @param questId ID of the quest
  151. * @param name String corresponding to the name of the quest
  152. * @param descr String for the description of the quest
  153. */
  154. public Quest(int questId, String name, String descr)
  155. {
  156. _questId = questId;
  157. _name = name;
  158. _descr = descr;
  159. if (questId != 0)
  160. {
  161. QuestManager.getInstance().addQuest(this);
  162. }
  163. else
  164. {
  165. _allEventsS.put(name, this);
  166. }
  167. init_LoadGlobalData();
  168. }
  169. /**
  170. * The function init_LoadGlobalData is, by default, called by the constructor of all quests.<br>
  171. * Children of this class can implement this function in order to define what variables to load and what structures to save them in.<br>
  172. * By default, nothing is loaded.
  173. */
  174. protected void init_LoadGlobalData()
  175. {
  176. }
  177. /**
  178. * The function saveGlobalData is, by default, called at shutdown, for all quests, by the QuestManager.<br>
  179. * Children of this class can implement this function in order to convert their structures<br>
  180. * into <var, value> tuples and make calls to save them to the database, if needed.<br>
  181. * By default, nothing is saved.
  182. */
  183. public void saveGlobalData()
  184. {
  185. }
  186. /**
  187. * Gets the quest ID.
  188. * @return the quest ID
  189. */
  190. @Override
  191. public int getId()
  192. {
  193. return _questId;
  194. }
  195. /**
  196. * Add a new quest state of this quest to the database.
  197. * @param player the owner of the newly created quest state
  198. * @return the newly created {@link QuestState} object
  199. */
  200. public QuestState newQuestState(L2PcInstance player)
  201. {
  202. return new QuestState(this, player, _initialState);
  203. }
  204. /**
  205. * Get the specified player's {@link QuestState} object for this quest.<br>
  206. * If the player does not have it and initIfNode is {@code true},<br>
  207. * create a new QuestState object and return it, otherwise return {@code null}.
  208. * @param player the player whose QuestState to get
  209. * @param initIfNone if true and the player does not have a QuestState for this quest,<br>
  210. * create a new QuestState
  211. * @return the QuestState object for this quest or null if it doesn't exist
  212. */
  213. public QuestState getQuestState(L2PcInstance player, boolean initIfNone)
  214. {
  215. final QuestState qs = player.getQuestState(_name);
  216. if ((qs != null) || !initIfNone)
  217. {
  218. return qs;
  219. }
  220. return newQuestState(player);
  221. }
  222. /**
  223. * @return the initial state of the quest
  224. */
  225. public byte getInitialState()
  226. {
  227. return _initialState;
  228. }
  229. /**
  230. * @return the name of the quest
  231. */
  232. public String getName()
  233. {
  234. return _name;
  235. }
  236. /**
  237. * @return the description of the quest
  238. */
  239. public String getDescr()
  240. {
  241. return _descr;
  242. }
  243. /**
  244. * Add a timer to the quest (if it doesn't exist already) and start it.
  245. * @param name the name of the timer (also passed back as "event" in {@link #onAdvEvent(String, L2Npc, L2PcInstance)})
  246. * @param time time in ms for when to fire the timer
  247. * @param npc the npc associated with this timer (can be null)
  248. * @param player the player associated with this timer (can be null)
  249. * @see #startQuestTimer(String, long, L2Npc, L2PcInstance, boolean)
  250. */
  251. public void startQuestTimer(String name, long time, L2Npc npc, L2PcInstance player)
  252. {
  253. startQuestTimer(name, time, npc, player, false);
  254. }
  255. /**
  256. * Add a timer to the quest (if it doesn't exist already) and start it.
  257. * @param name the name of the timer (also passed back as "event" in {@link #onAdvEvent(String, L2Npc, L2PcInstance)})
  258. * @param time time in ms for when to fire the timer
  259. * @param npc the npc associated with this timer (can be null)
  260. * @param player the player associated with this timer (can be null)
  261. * @param repeating indicates whether the timer is repeatable or one-time.<br>
  262. * If {@code true}, the task is repeated every {@code time} milliseconds until explicitly stopped.
  263. */
  264. public void startQuestTimer(String name, long time, L2Npc npc, L2PcInstance player, boolean repeating)
  265. {
  266. List<QuestTimer> timers = _allEventTimers.get(name);
  267. // Add quest timer if timer doesn't already exist
  268. if (timers == null)
  269. {
  270. timers = new ArrayList<>();
  271. timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  272. _allEventTimers.put(name, timers);
  273. }
  274. // a timer with this name exists, but may not be for the same set of npc and player
  275. else
  276. {
  277. // if there exists a timer with this name, allow the timer only if the [npc, player] set is unique
  278. // nulls act as wildcards
  279. if (getQuestTimer(name, npc, player) == null)
  280. {
  281. _writeLock.lock();
  282. try
  283. {
  284. timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  285. }
  286. finally
  287. {
  288. _writeLock.unlock();
  289. }
  290. }
  291. }
  292. }
  293. /**
  294. * Get a quest timer that matches the provided name and parameters.
  295. * @param name the name of the quest timer to get
  296. * @param npc the NPC associated with the quest timer to get
  297. * @param player the player associated with the quest timer to get
  298. * @return the quest timer that matches the specified parameters or {@code null} if nothing was found
  299. */
  300. public QuestTimer getQuestTimer(String name, L2Npc npc, L2PcInstance player)
  301. {
  302. final List<QuestTimer> timers = _allEventTimers.get(name);
  303. if (timers != null)
  304. {
  305. _readLock.lock();
  306. try
  307. {
  308. for (QuestTimer timer : timers)
  309. {
  310. if (timer != null)
  311. {
  312. if (timer.isMatch(this, name, npc, player))
  313. {
  314. return timer;
  315. }
  316. }
  317. }
  318. }
  319. finally
  320. {
  321. _readLock.unlock();
  322. }
  323. }
  324. return null;
  325. }
  326. /**
  327. * Cancel all quest timers with the specified name.
  328. * @param name the name of the quest timers to cancel
  329. */
  330. public void cancelQuestTimers(String name)
  331. {
  332. final List<QuestTimer> timers = _allEventTimers.get(name);
  333. if (timers != null)
  334. {
  335. _writeLock.lock();
  336. try
  337. {
  338. for (QuestTimer timer : timers)
  339. {
  340. if (timer != null)
  341. {
  342. timer.cancel();
  343. }
  344. }
  345. timers.clear();
  346. }
  347. finally
  348. {
  349. _writeLock.unlock();
  350. }
  351. }
  352. }
  353. /**
  354. * Cancel the quest timer that matches the specified name and parameters.
  355. * @param name the name of the quest timer to cancel
  356. * @param npc the NPC associated with the quest timer to cancel
  357. * @param player the player associated with the quest timer to cancel
  358. */
  359. public void cancelQuestTimer(String name, L2Npc npc, L2PcInstance player)
  360. {
  361. final QuestTimer timer = getQuestTimer(name, npc, player);
  362. if (timer != null)
  363. {
  364. timer.cancelAndRemove();
  365. }
  366. }
  367. /**
  368. * Remove a quest timer from the list of all timers.<br>
  369. * Note: does not stop the timer itself!
  370. * @param timer the {@link QuestState} object to remove
  371. */
  372. public void removeQuestTimer(QuestTimer timer)
  373. {
  374. if (timer != null)
  375. {
  376. final List<QuestTimer> timers = _allEventTimers.get(timer.getName());
  377. if (timers != null)
  378. {
  379. _writeLock.lock();
  380. try
  381. {
  382. timers.remove(timer);
  383. }
  384. finally
  385. {
  386. _writeLock.unlock();
  387. }
  388. }
  389. }
  390. }
  391. public Map<String, List<QuestTimer>> getQuestTimers()
  392. {
  393. return _allEventTimers;
  394. }
  395. // These are methods to call within the core to call the quest events.
  396. /**
  397. * @param npc the NPC that was attacked
  398. * @param attacker the attacking player
  399. * @param damage the damage dealt to the NPC by the player
  400. * @param isSummon if {@code true}, the attack was actually made by the player's summon
  401. * @param skill the skill used to attack the NPC (can be null)
  402. */
  403. public final void notifyAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, L2Skill skill)
  404. {
  405. String res = null;
  406. try
  407. {
  408. res = onAttack(npc, attacker, damage, isSummon, skill);
  409. }
  410. catch (Exception e)
  411. {
  412. showError(attacker, e);
  413. return;
  414. }
  415. showResult(attacker, res);
  416. }
  417. /**
  418. * @param killer the character that killed the {@code victim}
  419. * @param victim the character that was killed by the {@code killer}
  420. * @param qs the quest state object of the player to be notified of this event
  421. */
  422. public final void notifyDeath(L2Character killer, L2Character victim, QuestState qs)
  423. {
  424. String res = null;
  425. try
  426. {
  427. res = onDeath(killer, victim, qs);
  428. }
  429. catch (Exception e)
  430. {
  431. showError(qs.getPlayer(), e);
  432. }
  433. showResult(qs.getPlayer(), res);
  434. }
  435. /**
  436. * @param item
  437. * @param player
  438. */
  439. public final void notifyItemUse(L2Item item, L2PcInstance player)
  440. {
  441. String res = null;
  442. try
  443. {
  444. res = onItemUse(item, player);
  445. }
  446. catch (Exception e)
  447. {
  448. showError(player, e);
  449. }
  450. showResult(player, res);
  451. }
  452. /**
  453. * @param instance
  454. * @param player
  455. * @param skill
  456. */
  457. public final void notifySpellFinished(L2Npc instance, L2PcInstance player, L2Skill skill)
  458. {
  459. String res = null;
  460. try
  461. {
  462. res = onSpellFinished(instance, player, skill);
  463. }
  464. catch (Exception e)
  465. {
  466. showError(player, e);
  467. }
  468. showResult(player, res);
  469. }
  470. /**
  471. * Notify quest script when something happens with a trap.
  472. * @param trap the trap instance which triggers the notification
  473. * @param trigger the character which makes effect on the trap
  474. * @param action 0: trap casting its skill. 1: trigger detects the trap. 2: trigger removes the trap
  475. */
  476. public final void notifyTrapAction(L2TrapInstance trap, L2Character trigger, TrapAction action)
  477. {
  478. String res = null;
  479. try
  480. {
  481. res = onTrapAction(trap, trigger, action);
  482. }
  483. catch (Exception e)
  484. {
  485. if (trigger.getActingPlayer() != null)
  486. {
  487. showError(trigger.getActingPlayer(), e);
  488. }
  489. _log.log(Level.WARNING, "Exception on onTrapAction() in notifyTrapAction(): " + e.getMessage(), e);
  490. return;
  491. }
  492. if (trigger.getActingPlayer() != null)
  493. {
  494. showResult(trigger.getActingPlayer(), res);
  495. }
  496. }
  497. /**
  498. * @param npc the spawned NPC
  499. */
  500. public final void notifySpawn(L2Npc npc)
  501. {
  502. try
  503. {
  504. onSpawn(npc);
  505. }
  506. catch (Exception e)
  507. {
  508. _log.log(Level.WARNING, "Exception on onSpawn() in notifySpawn(): " + e.getMessage(), e);
  509. }
  510. }
  511. /**
  512. * @param event
  513. * @param npc
  514. * @param player
  515. * @return {@code false} if there was an error or the message was sent, {@code true} otherwise
  516. */
  517. public final boolean notifyEvent(String event, L2Npc npc, L2PcInstance player)
  518. {
  519. String res = null;
  520. try
  521. {
  522. res = onAdvEvent(event, npc, player);
  523. }
  524. catch (Exception e)
  525. {
  526. return showError(player, e);
  527. }
  528. return showResult(player, res, npc);
  529. }
  530. /**
  531. * @param player the player entering the world
  532. */
  533. public final void notifyEnterWorld(L2PcInstance player)
  534. {
  535. String res = null;
  536. try
  537. {
  538. res = onEnterWorld(player);
  539. }
  540. catch (Exception e)
  541. {
  542. showError(player, e);
  543. }
  544. showResult(player, res);
  545. }
  546. /**
  547. * @param npc
  548. * @param killer
  549. * @param isSummon
  550. */
  551. public final void notifyKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
  552. {
  553. String res = null;
  554. try
  555. {
  556. res = onKill(npc, killer, isSummon);
  557. }
  558. catch (Exception e)
  559. {
  560. showError(killer, e);
  561. }
  562. showResult(killer, res);
  563. }
  564. /**
  565. * @param npc
  566. * @param qs
  567. * @return {@code false} if there was an error or the message was sent, {@code true} otherwise
  568. */
  569. public final boolean notifyTalk(L2Npc npc, QuestState qs)
  570. {
  571. String res = null;
  572. try
  573. {
  574. res = onTalk(npc, qs.getPlayer());
  575. }
  576. catch (Exception e)
  577. {
  578. return showError(qs.getPlayer(), e);
  579. }
  580. qs.getPlayer().setLastQuestNpcObject(npc.getObjectId());
  581. return showResult(qs.getPlayer(), res, npc);
  582. }
  583. /**
  584. * Override the default NPC dialogs when a quest defines this for the given NPC.<br>
  585. * Note: If the default html for this npc needs to be shown, onFirstTalk should call npc.showChatWindow(player) and then return null.
  586. * @param npc the NPC whose dialogs to override
  587. * @param player the player talking to the NPC
  588. */
  589. public final void notifyFirstTalk(L2Npc npc, L2PcInstance player)
  590. {
  591. String res = null;
  592. try
  593. {
  594. res = onFirstTalk(npc, player);
  595. }
  596. catch (Exception e)
  597. {
  598. showError(player, e);
  599. }
  600. showResult(player, res, npc);
  601. }
  602. /**
  603. * @param npc
  604. * @param player
  605. */
  606. public final void notifyAcquireSkillList(L2Npc npc, L2PcInstance player)
  607. {
  608. String res = null;
  609. try
  610. {
  611. res = onAcquireSkillList(npc, player);
  612. }
  613. catch (Exception e)
  614. {
  615. showError(player, e);
  616. }
  617. showResult(player, res);
  618. }
  619. /**
  620. * Notify the quest engine that an skill info has been acquired.
  621. * @param npc the NPC
  622. * @param player the player
  623. * @param skill the skill
  624. */
  625. public final void notifyAcquireSkillInfo(L2Npc npc, L2PcInstance player, L2Skill skill)
  626. {
  627. String res = null;
  628. try
  629. {
  630. res = onAcquireSkillInfo(npc, player, skill);
  631. }
  632. catch (Exception e)
  633. {
  634. showError(player, e);
  635. }
  636. showResult(player, res);
  637. }
  638. /**
  639. * Notify the quest engine that an skill has been acquired.
  640. * @param npc the NPC
  641. * @param player the player
  642. * @param skill the skill
  643. * @param type the skill learn type
  644. */
  645. public final void notifyAcquireSkill(L2Npc npc, L2PcInstance player, L2Skill skill, AcquireSkillType type)
  646. {
  647. String res = null;
  648. try
  649. {
  650. res = onAcquireSkill(npc, player, skill, type);
  651. }
  652. catch (Exception e)
  653. {
  654. showError(player, e);
  655. }
  656. showResult(player, res);
  657. }
  658. /**
  659. * @param item
  660. * @param player
  661. * @return
  662. */
  663. public final boolean notifyItemTalk(L2ItemInstance item, L2PcInstance player)
  664. {
  665. String res = null;
  666. try
  667. {
  668. res = onItemTalk(item, player);
  669. if (res != null)
  670. {
  671. if (res.equalsIgnoreCase("true"))
  672. {
  673. return true;
  674. }
  675. else if (res.equalsIgnoreCase("false"))
  676. {
  677. return false;
  678. }
  679. }
  680. }
  681. catch (Exception e)
  682. {
  683. return showError(player, e);
  684. }
  685. return showResult(player, res);
  686. }
  687. /**
  688. * @param item
  689. * @param player
  690. * @return
  691. */
  692. public String onItemTalk(L2ItemInstance item, L2PcInstance player)
  693. {
  694. return null;
  695. }
  696. /**
  697. * @param item
  698. * @param player
  699. * @param event
  700. * @return
  701. */
  702. public final boolean notifyItemEvent(L2ItemInstance item, L2PcInstance player, String event)
  703. {
  704. String res = null;
  705. try
  706. {
  707. res = onItemEvent(item, player, event);
  708. if (res != null)
  709. {
  710. if (res.equalsIgnoreCase("true"))
  711. {
  712. return true;
  713. }
  714. else if (res.equalsIgnoreCase("false"))
  715. {
  716. return false;
  717. }
  718. }
  719. }
  720. catch (Exception e)
  721. {
  722. return showError(player, e);
  723. }
  724. return showResult(player, res);
  725. }
  726. /**
  727. * @param npc
  728. * @param caster
  729. * @param skill
  730. * @param targets
  731. * @param isSummon
  732. */
  733. public final void notifySkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isSummon)
  734. {
  735. ThreadPoolManager.getInstance().executeAi(new SkillSee(this, npc, caster, skill, targets, isSummon));
  736. }
  737. /**
  738. * @param npc
  739. * @param caller
  740. * @param attacker
  741. * @param isSummon
  742. */
  743. public final void notifyFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
  744. {
  745. String res = null;
  746. try
  747. {
  748. res = onFactionCall(npc, caller, attacker, isSummon);
  749. }
  750. catch (Exception e)
  751. {
  752. showError(attacker, e);
  753. }
  754. showResult(attacker, res);
  755. }
  756. /**
  757. * @param npc
  758. * @param player
  759. * @param isSummon
  760. */
  761. public final void notifyAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
  762. {
  763. ThreadPoolManager.getInstance().executeAi(new AggroRangeEnter(this, npc, player, isSummon));
  764. }
  765. /**
  766. * @param npc the NPC that sees the creature
  767. * @param creature the creature seen by the NPC
  768. * @param isSummon
  769. */
  770. public final void notifySeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
  771. {
  772. ThreadPoolManager.getInstance().executeAi(new SeeCreature(this, npc, creature, isSummon));
  773. }
  774. /**
  775. * @param eventName - name of event
  776. * @param sender - NPC, who sent event
  777. * @param receiver - NPC, who received event
  778. * @param reference - L2Object to pass, if needed
  779. */
  780. public final void notifyEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
  781. {
  782. try
  783. {
  784. onEventReceived(eventName, sender, receiver, reference);
  785. }
  786. catch (Exception e)
  787. {
  788. _log.log(Level.WARNING, "Exception on onEventReceived() in notifyEventReceived(): " + e.getMessage(), e);
  789. }
  790. }
  791. /**
  792. * @param character
  793. * @param zone
  794. */
  795. public final void notifyEnterZone(L2Character character, L2ZoneType zone)
  796. {
  797. L2PcInstance player = character.getActingPlayer();
  798. String res = null;
  799. try
  800. {
  801. res = onEnterZone(character, zone);
  802. }
  803. catch (Exception e)
  804. {
  805. if (player != null)
  806. {
  807. showError(player, e);
  808. }
  809. }
  810. if (player != null)
  811. {
  812. showResult(player, res);
  813. }
  814. }
  815. /**
  816. * @param character
  817. * @param zone
  818. */
  819. public final void notifyExitZone(L2Character character, L2ZoneType zone)
  820. {
  821. L2PcInstance player = character.getActingPlayer();
  822. String res = null;
  823. try
  824. {
  825. res = onExitZone(character, zone);
  826. }
  827. catch (Exception e)
  828. {
  829. if (player != null)
  830. {
  831. showError(player, e);
  832. }
  833. }
  834. if (player != null)
  835. {
  836. showResult(player, res);
  837. }
  838. }
  839. /**
  840. * @param winner
  841. * @param type {@code false} if there was an error, {@code true} otherwise
  842. */
  843. public final void notifyOlympiadWin(L2PcInstance winner, CompetitionType type)
  844. {
  845. try
  846. {
  847. onOlympiadWin(winner, type);
  848. }
  849. catch (Exception e)
  850. {
  851. showError(winner, e);
  852. }
  853. }
  854. /**
  855. * @param loser
  856. * @param type {@code false} if there was an error, {@code true} otherwise
  857. */
  858. public final void notifyOlympiadLose(L2PcInstance loser, CompetitionType type)
  859. {
  860. try
  861. {
  862. onOlympiadLose(loser, type);
  863. }
  864. catch (Exception e)
  865. {
  866. showError(loser, e);
  867. }
  868. }
  869. /**
  870. * @param npc
  871. */
  872. public final void notifyMoveFinished(L2Npc npc)
  873. {
  874. try
  875. {
  876. onMoveFinished(npc);
  877. }
  878. catch (Exception e)
  879. {
  880. _log.log(Level.WARNING, "Exception on onMoveFinished() in notifyMoveFinished(): " + e.getMessage(), e);
  881. }
  882. }
  883. /**
  884. * @param npc
  885. */
  886. public final void notifyNodeArrived(L2Npc npc)
  887. {
  888. try
  889. {
  890. onNodeArrived(npc);
  891. }
  892. catch (Exception e)
  893. {
  894. _log.log(Level.WARNING, "Exception on onNodeArrived() in notifyNodeArrived(): " + e.getMessage(), e);
  895. }
  896. }
  897. /**
  898. * @param npc
  899. */
  900. public final void notifyRouteFinished(L2Npc npc)
  901. {
  902. try
  903. {
  904. onRouteFinished(npc);
  905. }
  906. catch (Exception e)
  907. {
  908. _log.log(Level.WARNING, "Exception on onRouteFinished() in notifyRouteFinished(): " + e.getMessage(), e);
  909. }
  910. }
  911. // These are methods that java calls to invoke scripts.
  912. /**
  913. * This function is called in place of {@link #onAttack(L2Npc, L2PcInstance, int, boolean, L2Skill)} if the former is not implemented.<br>
  914. * If a script contains both onAttack(..) implementations, then this method will never be called unless the script's {@link #onAttack(L2Npc, L2PcInstance, int, boolean, L2Skill)} explicitly calls this method.
  915. * @param npc this parameter contains a reference to the exact instance of the NPC that got attacked the NPC.
  916. * @param attacker this parameter contains a reference to the exact instance of the player who attacked.
  917. * @param damage this parameter represents the total damage that this attack has inflicted to the NPC.
  918. * @param isSummon this parameter if it's {@code false} it denotes that the attacker was indeed the player, else it specifies that the damage was actually dealt by the player's pet.
  919. * @return
  920. */
  921. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon)
  922. {
  923. return null;
  924. }
  925. /**
  926. * This function is called whenever a player attacks an NPC that is registered for the quest.<br>
  927. * If is not overridden by a subclass, then default to the returned value of the simpler (and older) {@link #onAttack(L2Npc, L2PcInstance, int, boolean)} override.<br>
  928. * @param npc this parameter contains a reference to the exact instance of the NPC that got attacked.
  929. * @param attacker this parameter contains a reference to the exact instance of the player who attacked the NPC.
  930. * @param damage this parameter represents the total damage that this attack has inflicted to the NPC.
  931. * @param isSummon this parameter if it's {@code false} it denotes that the attacker was indeed the player, else it specifies that the damage was actually dealt by the player's summon
  932. * @param skill parameter is the skill that player used to attack NPC.
  933. * @return
  934. */
  935. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon, L2Skill skill)
  936. {
  937. return onAttack(npc, attacker, damage, isSummon);
  938. }
  939. /**
  940. * This function is called whenever an <b>exact instance</b> of a character who was previously registered for this event dies.<br>
  941. * The registration for {@link #onDeath(L2Character, L2Character, QuestState)} events <b>is not</b> done via the quest itself, but it is instead handled by the QuestState of a particular player.
  942. * @param killer this parameter contains a reference to the exact instance of the NPC that <b>killed</b> the character.
  943. * @param victim this parameter contains a reference to the exact instance of the character that got killed.
  944. * @param qs this parameter contains a reference to the QuestState of whomever was interested (waiting) for this kill.
  945. * @return
  946. */
  947. public String onDeath(L2Character killer, L2Character victim, QuestState qs)
  948. {
  949. return onAdvEvent("", ((killer instanceof L2Npc) ? ((L2Npc) killer) : null), qs.getPlayer());
  950. }
  951. /**
  952. * This function is called whenever a player clicks on a link in a quest dialog and whenever a timer fires.<br>
  953. * If is not overridden by a subclass, then default to the returned value of the simpler (and older) {@link #onEvent(String, QuestState)} override.<br>
  954. * If the player has a quest state, use it as parameter in the next call, otherwise return null.
  955. * @param event this parameter contains a string identifier for the event.<br>
  956. * Generally, this string is passed directly via the link.<br>
  957. * For example:<br>
  958. * <code>
  959. * &lt;a action="bypass -h Quest 626_ADarkTwilight 31517-01.htm"&gt;hello&lt;/a&gt;
  960. * </code><br>
  961. * The above link sets the event variable to "31517-01.htm" for the quest 626_ADarkTwilight.<br>
  962. * In the case of timers, this will be the name of the timer.<br>
  963. * This parameter serves as a sort of identifier.
  964. * @param npc this parameter contains a reference to the instance of NPC associated with this event.<br>
  965. * This may be the NPC registered in a timer, or the NPC with whom a player is speaking, etc.<br>
  966. * This parameter may be {@code null} in certain circumstances.
  967. * @param player this parameter contains a reference to the player participating in this function.<br>
  968. * It may be the player speaking to the NPC, or the player who caused a timer to start (and owns that timer).<br>
  969. * This parameter may be {@code null} in certain circumstances.
  970. * @return the text returned by the event (may be {@code null}, a filename or just text)
  971. */
  972. public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
  973. {
  974. if (player != null)
  975. {
  976. final QuestState qs = player.getQuestState(getName());
  977. if (qs != null)
  978. {
  979. return onEvent(event, qs);
  980. }
  981. }
  982. return null;
  983. }
  984. /**
  985. * This function is called in place of {@link #onAdvEvent(String, L2Npc, L2PcInstance)} if the former is not implemented.<br>
  986. * If a script contains both {@link #onAdvEvent(String, L2Npc, L2PcInstance)} and this implementation, then this method will never be called unless the script's {@link #onAdvEvent(String, L2Npc, L2PcInstance)} explicitly calls this method.
  987. * @param event this parameter contains a string identifier for the event.<br>
  988. * Generally, this string is passed directly via the link.<br>
  989. * For example:<br>
  990. * <code>
  991. * &lt;a action="bypass -h Quest 626_ADarkTwilight 31517-01.htm"&gt;hello&lt;/a&gt;
  992. * </code><br>
  993. * The above link sets the event variable to "31517-01.htm" for the quest 626_ADarkTwilight.<br>
  994. * In the case of timers, this will be the name of the timer.<br>
  995. * This parameter serves as a sort of identifier.
  996. * @param qs this parameter contains a reference to the quest state of the player who used the link or started the timer.
  997. * @return the text returned by the event (may be {@code null}, a filename or just text)
  998. */
  999. public String onEvent(String event, QuestState qs)
  1000. {
  1001. return null;
  1002. }
  1003. /**
  1004. * This function is called whenever a player kills a NPC that is registered for the quest.
  1005. * @param npc this parameter contains a reference to the exact instance of the NPC that got killed.
  1006. * @param killer this parameter contains a reference to the exact instance of the player who killed the NPC.
  1007. * @param isSummon this parameter if it's {@code false} it denotes that the attacker was indeed the player, else it specifies that the killer was the player's pet.
  1008. * @return the text returned by the event (may be {@code null}, a filename or just text)
  1009. */
  1010. public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon)
  1011. {
  1012. return null;
  1013. }
  1014. /**
  1015. * This function is called whenever a player clicks to the "Quest" link of an NPC that is registered for the quest.
  1016. * @param npc this parameter contains a reference to the exact instance of the NPC that the player is talking with.
  1017. * @param talker this parameter contains a reference to the exact instance of the player who is talking to the NPC.
  1018. * @return the text returned by the event (may be {@code null}, a filename or just text)
  1019. */
  1020. public String onTalk(L2Npc npc, L2PcInstance talker)
  1021. {
  1022. return null;
  1023. }
  1024. /**
  1025. * This function is called whenever a player talks to an NPC that is registered for the quest.<br>
  1026. * That is, it is triggered from the very first click on the NPC, not via another dialog.<br>
  1027. * <b>Note 1:</b><br>
  1028. * Each NPC can be registered to at most one quest for triggering this function.<br>
  1029. * In other words, the same one NPC cannot respond to an "onFirstTalk" request from two different quests.<br>
  1030. * Attempting to register an NPC in two different quests for this function will result in one of the two registration being ignored.<br>
  1031. * <b>Note 2:</b><br>
  1032. * Since a Quest link isn't clicked in order to reach this, a quest state can be invalid within this function.<br>
  1033. * The coder of the script may need to create a new quest state (if necessary).<br>
  1034. * <b>Note 3:</b><br>
  1035. * The returned value of onFirstTalk replaces the default HTML that would have otherwise been loaded from a sub-folder of DatapackRoot/game/data/html/.<br>
  1036. * If you wish to show the default HTML, within onFirstTalk do npc.showChatWindow(player) and then return ""<br>
  1037. * @param npc this parameter contains a reference to the exact instance of the NPC that the player is talking with.
  1038. * @param player this parameter contains a reference to the exact instance of the player who is talking to the NPC.
  1039. * @return the text returned by the event (may be {@code null}, a filename or just text)
  1040. * @since <a href="http://trac.l2jserver.com/changeset/771">Jython AI support for "onFirstTalk"</a>
  1041. */
  1042. public String onFirstTalk(L2Npc npc, L2PcInstance player)
  1043. {
  1044. return null;
  1045. }
  1046. /**
  1047. * @param item
  1048. * @param player
  1049. * @param event
  1050. * @return
  1051. */
  1052. public String onItemEvent(L2ItemInstance item, L2PcInstance player, String event)
  1053. {
  1054. return null;
  1055. }
  1056. /**
  1057. * This function is called whenever a player request a skill list.<br>
  1058. * TODO: Re-implement, since Skill Trees rework it's support was removed.
  1059. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill list.
  1060. * @param player this parameter contains a reference to the exact instance of the player who requested the skill list.
  1061. * @return
  1062. */
  1063. public String onAcquireSkillList(L2Npc npc, L2PcInstance player)
  1064. {
  1065. return null;
  1066. }
  1067. /**
  1068. * This function is called whenever a player request a skill info.
  1069. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill info.
  1070. * @param player this parameter contains a reference to the exact instance of the player who requested the skill info.
  1071. * @param skill this parameter contains a reference to the skill that the player requested its info.
  1072. * @return
  1073. */
  1074. public String onAcquireSkillInfo(L2Npc npc, L2PcInstance player, L2Skill skill)
  1075. {
  1076. return null;
  1077. }
  1078. /**
  1079. * This function is called whenever a player acquire a skill.<br>
  1080. * TODO: Re-implement, since Skill Trees rework it's support was removed.
  1081. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill.
  1082. * @param player this parameter contains a reference to the exact instance of the player who requested the skill.
  1083. * @param skill this parameter contains a reference to the skill that the player requested.
  1084. * @param type the skill learn type
  1085. * @return
  1086. */
  1087. public String onAcquireSkill(L2Npc npc, L2PcInstance player, L2Skill skill, AcquireSkillType type)
  1088. {
  1089. return null;
  1090. }
  1091. /**
  1092. * This function is called whenever a player uses a quest item that has a quest events list.<br>
  1093. * TODO: complete this documentation and unhardcode it to work with all item uses not with those listed.
  1094. * @param item the quest item that the player used
  1095. * @param player the player who used the item
  1096. * @return
  1097. */
  1098. public String onItemUse(L2Item item, L2PcInstance player)
  1099. {
  1100. return null;
  1101. }
  1102. /**
  1103. * This function is called whenever a player casts a skill near a registered NPC (1000 distance).<br>
  1104. * <b>Note:</b><br>
  1105. * If a skill does damage, both onSkillSee(..) and onAttack(..) will be triggered for the damaged NPC!<br>
  1106. * However, only onSkillSee(..) will be triggered if the skill does no damage,<br>
  1107. * or if it damages an NPC who has no onAttack(..) registration while near another NPC who has an onSkillSee registration.<br>
  1108. * TODO: confirm if the distance is 1000 and unhardcode.
  1109. * @param npc the NPC that saw the skill
  1110. * @param caster the player who cast the skill
  1111. * @param skill the actual skill that was used
  1112. * @param targets an array of all objects (can be any type of object, including mobs and players) that were affected by the skill
  1113. * @param isSummon if {@code true}, the skill was actually cast by the player's summon, not the player himself
  1114. * @return
  1115. */
  1116. public String onSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isSummon)
  1117. {
  1118. return null;
  1119. }
  1120. /**
  1121. * This function is called whenever an NPC finishes casting a skill.
  1122. * @param npc the NPC that casted the skill.
  1123. * @param player the player who is the target of the skill. Can be {@code null}.
  1124. * @param skill the actual skill that was used by the NPC.
  1125. * @return
  1126. */
  1127. public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
  1128. {
  1129. return null;
  1130. }
  1131. /**
  1132. * This function is called whenever a trap action is performed.
  1133. * @param trap this parameter contains a reference to the exact instance of the trap that was activated.
  1134. * @param trigger this parameter contains a reference to the exact instance of the character that triggered the action.
  1135. * @param action this parameter contains a reference to the action that was triggered.
  1136. * @return
  1137. */
  1138. public String onTrapAction(L2TrapInstance trap, L2Character trigger, TrapAction action)
  1139. {
  1140. return null;
  1141. }
  1142. /**
  1143. * This function is called whenever an NPC spawns or re-spawns and passes a reference to the newly (re)spawned NPC.<br>
  1144. * Currently the only function that has no reference to a player.<br>
  1145. * It is useful for initializations, starting quest timers, displaying chat (NpcSay), and more.
  1146. * @param npc this parameter contains a reference to the exact instance of the NPC who just (re)spawned.
  1147. * @return
  1148. */
  1149. public String onSpawn(L2Npc npc)
  1150. {
  1151. return null;
  1152. }
  1153. /**
  1154. * This function is called whenever an NPC is called by another NPC in the same faction.
  1155. * @param npc this parameter contains a reference to the exact instance of the NPC who is being asked for help.
  1156. * @param caller this parameter contains a reference to the exact instance of the NPC who is asking for help.<br>
  1157. * @param attacker this parameter contains a reference to the exact instance of the player who attacked.
  1158. * @param isSummon this parameter if it's {@code false} it denotes that the attacker was indeed the player, else it specifies that the attacker was the player's summon.
  1159. * @return
  1160. */
  1161. public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isSummon)
  1162. {
  1163. return null;
  1164. }
  1165. /**
  1166. * This function is called whenever a player enters an NPC aggression range.
  1167. * @param npc this parameter contains a reference to the exact instance of the NPC whose aggression range is being transgressed.
  1168. * @param player this parameter contains a reference to the exact instance of the player who is entering the NPC's aggression range.
  1169. * @param isSummon this parameter if it's {@code false} it denotes that the character that entered the aggression range was indeed the player, else it specifies that the character was the player's summon.
  1170. * @return
  1171. */
  1172. public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isSummon)
  1173. {
  1174. return null;
  1175. }
  1176. /**
  1177. * This function is called whenever a NPC "sees" a creature.
  1178. * @param npc the NPC who sees the creature
  1179. * @param creature the creature seen by the NPC
  1180. * @param isSummon this parameter if it's {@code false} it denotes that the character seen by the NPC was indeed the player, else it specifies that the character was the player's summon
  1181. * @return
  1182. */
  1183. public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon)
  1184. {
  1185. return null;
  1186. }
  1187. /**
  1188. * This function is called whenever a player enters the game.
  1189. * @param player this parameter contains a reference to the exact instance of the player who is entering to the world.
  1190. * @return
  1191. */
  1192. public String onEnterWorld(L2PcInstance player)
  1193. {
  1194. return null;
  1195. }
  1196. /**
  1197. * This function is called whenever a character enters a registered zone.
  1198. * @param character this parameter contains a reference to the exact instance of the character who is entering the zone.
  1199. * @param zone this parameter contains a reference to the zone.
  1200. * @return
  1201. */
  1202. public String onEnterZone(L2Character character, L2ZoneType zone)
  1203. {
  1204. return null;
  1205. }
  1206. /**
  1207. * This function is called whenever a character exits a registered zone.
  1208. * @param character this parameter contains a reference to the exact instance of the character who is exiting the zone.
  1209. * @param zone this parameter contains a reference to the zone.
  1210. * @return
  1211. */
  1212. public String onExitZone(L2Character character, L2ZoneType zone)
  1213. {
  1214. return null;
  1215. }
  1216. /**
  1217. * @param eventName - name of event
  1218. * @param sender - NPC, who sent event
  1219. * @param receiver - NPC, who received event
  1220. * @param reference - L2Object to pass, if needed
  1221. * @return
  1222. */
  1223. public String onEventReceived(String eventName, L2Npc sender, L2Npc receiver, L2Object reference)
  1224. {
  1225. return null;
  1226. }
  1227. /**
  1228. * This function is called whenever a player wins an Olympiad Game.
  1229. * @param winner this parameter contains a reference to the exact instance of the player who won the competition.
  1230. * @param type this parameter contains a reference to the competition type.
  1231. */
  1232. public void onOlympiadWin(L2PcInstance winner, CompetitionType type)
  1233. {
  1234. }
  1235. /**
  1236. * This function is called whenever a player looses an Olympiad Game.
  1237. * @param loser this parameter contains a reference to the exact instance of the player who lose the competition.
  1238. * @param type this parameter contains a reference to the competition type.
  1239. */
  1240. public void onOlympiadLose(L2PcInstance loser, CompetitionType type)
  1241. {
  1242. }
  1243. /**
  1244. * This function is called whenever a NPC finishes moving
  1245. * @param npc registered NPC
  1246. */
  1247. public void onMoveFinished(L2Npc npc)
  1248. {
  1249. }
  1250. /**
  1251. * This function is called whenever a walker NPC (controlled by WalkingManager) arrive a walking node
  1252. * @param npc registered NPC
  1253. */
  1254. public void onNodeArrived(L2Npc npc)
  1255. {
  1256. }
  1257. /**
  1258. * This function is called whenever a walker NPC (controlled by WalkingManager) arrive to last node
  1259. * @param npc registered NPC
  1260. */
  1261. public void onRouteFinished(L2Npc npc)
  1262. {
  1263. }
  1264. /**
  1265. * @param mob
  1266. * @param playable
  1267. * @return {@code true} if npc can hate the playable, {@code false} otherwise.
  1268. */
  1269. public boolean onNpcHate(L2Attackable mob, L2Playable playable)
  1270. {
  1271. return true;
  1272. }
  1273. /**
  1274. * @param summon
  1275. */
  1276. public void onSummon(L2Summon summon)
  1277. {
  1278. }
  1279. /**
  1280. * Show an error message to the specified player.
  1281. * @param player the player to whom to send the error (must be a GM)
  1282. * @param t the {@link Throwable} to get the message/stacktrace from
  1283. * @return {@code false}
  1284. */
  1285. public boolean showError(L2PcInstance player, Throwable t)
  1286. {
  1287. _log.log(Level.WARNING, getScriptFile().getAbsolutePath(), t);
  1288. if (t.getMessage() == null)
  1289. {
  1290. _log.warning(getClass().getSimpleName() + ": " + t.getMessage());
  1291. }
  1292. if ((player != null) && player.getAccessLevel().isGm())
  1293. {
  1294. String res = "<html><body><title>Script error</title>" + Util.getStackTrace(t) + "</body></html>";
  1295. return showResult(player, res);
  1296. }
  1297. return false;
  1298. }
  1299. /**
  1300. * @param player the player to whom to show the result
  1301. * @param res the message to show to the player
  1302. * @return {@code false} if the message was sent, {@code true} otherwise
  1303. * @see #showResult(L2PcInstance, String, L2Npc)
  1304. */
  1305. public boolean showResult(L2PcInstance player, String res)
  1306. {
  1307. return showResult(player, res, null);
  1308. }
  1309. /**
  1310. * Show a message to the specified player.<br>
  1311. * <u><i>Concept:</i></u><br>
  1312. * Three cases are managed according to the value of the {@code res} parameter:<br>
  1313. * <ul>
  1314. * <li><u>{@code res} ends with ".htm" or ".html":</u> the contents of the specified HTML file are shown in a dialog window</li>
  1315. * <li><u>{@code res} starts with "&lt;html&gt;":</u> the contents of the parameter are shown in a dialog window</li>
  1316. * <li><u>all other cases :</u> the text contained in the parameter is shown in chat</li>
  1317. * </ul>
  1318. * @param player the player to whom to show the result
  1319. * @param npc npc to show the result for
  1320. * @param res the message to show to the player
  1321. * @return {@code false} if the message was sent, {@code true} otherwise
  1322. */
  1323. public boolean showResult(L2PcInstance player, String res, L2Npc npc)
  1324. {
  1325. if ((res == null) || res.isEmpty() || (player == null))
  1326. {
  1327. return true;
  1328. }
  1329. if (res.endsWith(".htm") || res.endsWith(".html"))
  1330. {
  1331. showHtmlFile(player, res, npc);
  1332. }
  1333. else if (res.startsWith("<html>"))
  1334. {
  1335. final NpcHtmlMessage npcReply = new NpcHtmlMessage(npc != null ? npc.getObjectId() : 0, res);
  1336. npcReply.replace("%playername%", player.getName());
  1337. player.sendPacket(npcReply);
  1338. player.sendPacket(ActionFailed.STATIC_PACKET);
  1339. }
  1340. else
  1341. {
  1342. player.sendMessage(res);
  1343. }
  1344. return false;
  1345. }
  1346. /**
  1347. * Loads all quest states and variables for the specified player.
  1348. * @param player the player who is entering the world
  1349. */
  1350. public static final void playerEnter(L2PcInstance player)
  1351. {
  1352. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1353. PreparedStatement invalidQuestData = con.prepareStatement("DELETE FROM character_quests WHERE charId = ? AND name = ?");
  1354. PreparedStatement invalidQuestDataVar = con.prepareStatement("DELETE FROM character_quests WHERE charId = ? AND name = ? AND var = ?");
  1355. PreparedStatement ps1 = con.prepareStatement("SELECT name, value FROM character_quests WHERE charId = ? AND var = ?"))
  1356. {
  1357. // Get list of quests owned by the player from database
  1358. ps1.setInt(1, player.getObjectId());
  1359. ps1.setString(2, "<state>");
  1360. try (ResultSet rs = ps1.executeQuery())
  1361. {
  1362. while (rs.next())
  1363. {
  1364. // Get the ID of the quest and its state
  1365. String questId = rs.getString("name");
  1366. String statename = rs.getString("value");
  1367. // Search quest associated with the ID
  1368. Quest q = QuestManager.getInstance().getQuest(questId);
  1369. if (q == null)
  1370. {
  1371. _log.finer("Unknown quest " + questId + " for player " + player.getName());
  1372. if (Config.AUTODELETE_INVALID_QUEST_DATA)
  1373. {
  1374. invalidQuestData.setInt(1, player.getObjectId());
  1375. invalidQuestData.setString(2, questId);
  1376. invalidQuestData.executeUpdate();
  1377. }
  1378. continue;
  1379. }
  1380. // Create a new QuestState for the player that will be added to the player's list of quests
  1381. new QuestState(q, player, State.getStateId(statename));
  1382. }
  1383. }
  1384. // Get list of quests owned by the player from the DB in order to add variables used in the quest.
  1385. try (PreparedStatement ps2 = con.prepareStatement("SELECT name, var, value FROM character_quests WHERE charId = ? AND var <> ?"))
  1386. {
  1387. ps2.setInt(1, player.getObjectId());
  1388. ps2.setString(2, "<state>");
  1389. try (ResultSet rs = ps2.executeQuery())
  1390. {
  1391. while (rs.next())
  1392. {
  1393. String questId = rs.getString("name");
  1394. String var = rs.getString("var");
  1395. String value = rs.getString("value");
  1396. // Get the QuestState saved in the loop before
  1397. QuestState qs = player.getQuestState(questId);
  1398. if (qs == null)
  1399. {
  1400. _log.finer("Lost variable " + var + " in quest " + questId + " for player " + player.getName());
  1401. if (Config.AUTODELETE_INVALID_QUEST_DATA)
  1402. {
  1403. invalidQuestDataVar.setInt(1, player.getObjectId());
  1404. invalidQuestDataVar.setString(2, questId);
  1405. invalidQuestDataVar.setString(3, var);
  1406. invalidQuestDataVar.executeUpdate();
  1407. }
  1408. continue;
  1409. }
  1410. // Add parameter to the quest
  1411. qs.setInternal(var, value);
  1412. }
  1413. }
  1414. }
  1415. }
  1416. catch (Exception e)
  1417. {
  1418. _log.log(Level.WARNING, "could not insert char quest:", e);
  1419. }
  1420. // events
  1421. for (String name : _allEventsS.keySet())
  1422. {
  1423. player.processQuestEvent(name, "enter");
  1424. }
  1425. }
  1426. /**
  1427. * Insert (or update) in the database variables that need to stay persistent for this quest after a reboot.<br>
  1428. * This function is for storage of values that do not related to a specific player but are global for all characters.<br>
  1429. * For example, if we need to disable a quest-gatekeeper until a certain time (as is done with some grand-boss gatekeepers), we can save that time in the DB.
  1430. * @param var the name of the variable to save
  1431. * @param value the value of the variable
  1432. */
  1433. public final void saveGlobalQuestVar(String var, String value)
  1434. {
  1435. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1436. PreparedStatement statement = con.prepareStatement("REPLACE INTO quest_global_data (quest_name,var,value) VALUES (?,?,?)"))
  1437. {
  1438. statement.setString(1, getName());
  1439. statement.setString(2, var);
  1440. statement.setString(3, value);
  1441. statement.executeUpdate();
  1442. }
  1443. catch (Exception e)
  1444. {
  1445. _log.log(Level.WARNING, "could not insert global quest variable:", e);
  1446. }
  1447. }
  1448. /**
  1449. * Read from the database a previously saved variable for this quest.<br>
  1450. * Due to performance considerations, this function should best be used only when the quest is first loaded.<br>
  1451. * Subclasses of this class can define structures into which these loaded values can be saved.<br>
  1452. * However, on-demand usage of this function throughout the script is not prohibited, only not recommended.<br>
  1453. * Values read from this function were entered by calls to "saveGlobalQuestVar".
  1454. * @param var the name of the variable to load
  1455. * @return the current value of the specified variable, or an empty string if the variable does not exist
  1456. */
  1457. public final String loadGlobalQuestVar(String var)
  1458. {
  1459. String result = "";
  1460. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1461. PreparedStatement statement = con.prepareStatement("SELECT value FROM quest_global_data WHERE quest_name = ? AND var = ?"))
  1462. {
  1463. statement.setString(1, getName());
  1464. statement.setString(2, var);
  1465. try (ResultSet rs = statement.executeQuery())
  1466. {
  1467. if (rs.first())
  1468. {
  1469. result = rs.getString(1);
  1470. }
  1471. }
  1472. }
  1473. catch (Exception e)
  1474. {
  1475. _log.log(Level.WARNING, "could not load global quest variable:", e);
  1476. }
  1477. return result;
  1478. }
  1479. /**
  1480. * Permanently delete from the database a global quest variable that was previously saved for this quest.
  1481. * @param var the name of the variable to delete
  1482. */
  1483. public final void deleteGlobalQuestVar(String var)
  1484. {
  1485. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1486. PreparedStatement statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ? AND var = ?"))
  1487. {
  1488. statement.setString(1, getName());
  1489. statement.setString(2, var);
  1490. statement.executeUpdate();
  1491. }
  1492. catch (Exception e)
  1493. {
  1494. _log.log(Level.WARNING, "could not delete global quest variable:", e);
  1495. }
  1496. }
  1497. /**
  1498. * Permanently delete from the database all global quest variables that were previously saved for this quest.
  1499. */
  1500. public final void deleteAllGlobalQuestVars()
  1501. {
  1502. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1503. PreparedStatement statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ?"))
  1504. {
  1505. statement.setString(1, getName());
  1506. statement.executeUpdate();
  1507. }
  1508. catch (Exception e)
  1509. {
  1510. _log.log(Level.WARNING, "could not delete global quest variables:", e);
  1511. }
  1512. }
  1513. /**
  1514. * Insert in the database the quest for the player.
  1515. * @param qs the {@link QuestState} object whose variable to insert
  1516. * @param var the name of the variable
  1517. * @param value the value of the variable
  1518. */
  1519. public static void createQuestVarInDb(QuestState qs, String var, String value)
  1520. {
  1521. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1522. PreparedStatement statement = con.prepareStatement("INSERT INTO character_quests (charId,name,var,value) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE value=?"))
  1523. {
  1524. statement.setInt(1, qs.getPlayer().getObjectId());
  1525. statement.setString(2, qs.getQuestName());
  1526. statement.setString(3, var);
  1527. statement.setString(4, value);
  1528. statement.setString(5, value);
  1529. statement.executeUpdate();
  1530. }
  1531. catch (Exception e)
  1532. {
  1533. _log.log(Level.WARNING, "could not insert char quest:", e);
  1534. }
  1535. }
  1536. /**
  1537. * Update the value of the variable "var" for the specified quest in database
  1538. * @param qs the {@link QuestState} object whose variable to update
  1539. * @param var the name of the variable
  1540. * @param value the value of the variable
  1541. */
  1542. public static void updateQuestVarInDb(QuestState qs, String var, String value)
  1543. {
  1544. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1545. PreparedStatement statement = con.prepareStatement("UPDATE character_quests SET value=? WHERE charId=? AND name=? AND var = ?"))
  1546. {
  1547. statement.setString(1, value);
  1548. statement.setInt(2, qs.getPlayer().getObjectId());
  1549. statement.setString(3, qs.getQuestName());
  1550. statement.setString(4, var);
  1551. statement.executeUpdate();
  1552. }
  1553. catch (Exception e)
  1554. {
  1555. _log.log(Level.WARNING, "could not update char quest:", e);
  1556. }
  1557. }
  1558. /**
  1559. * Delete a variable of player's quest from the database.
  1560. * @param qs the {@link QuestState} object whose variable to delete
  1561. * @param var the name of the variable to delete
  1562. */
  1563. public static void deleteQuestVarInDb(QuestState qs, String var)
  1564. {
  1565. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1566. PreparedStatement statement = con.prepareStatement("DELETE FROM character_quests WHERE charId=? AND name=? AND var=?"))
  1567. {
  1568. statement.setInt(1, qs.getPlayer().getObjectId());
  1569. statement.setString(2, qs.getQuestName());
  1570. statement.setString(3, var);
  1571. statement.executeUpdate();
  1572. }
  1573. catch (Exception e)
  1574. {
  1575. _log.log(Level.WARNING, "could not delete char quest:", e);
  1576. }
  1577. }
  1578. /**
  1579. * Delete from the database all variables and states of the specified quest state.
  1580. * @param qs the {@link QuestState} object whose variables to delete
  1581. * @param repeatable if {@code false}, the state variable will be preserved, otherwise it will be deleted as well
  1582. */
  1583. public static void deleteQuestInDb(QuestState qs, boolean repeatable)
  1584. {
  1585. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  1586. PreparedStatement ps = con.prepareStatement(repeatable ? QUEST_DELETE_FROM_CHAR_QUERY : QUEST_DELETE_FROM_CHAR_QUERY_NON_REPEATABLE_QUERY))
  1587. {
  1588. ps.setInt(1, qs.getPlayer().getObjectId());
  1589. ps.setString(2, qs.getQuestName());
  1590. if (!repeatable)
  1591. {
  1592. ps.setString(3, "<state>");
  1593. }
  1594. ps.executeUpdate();
  1595. }
  1596. catch (Exception e)
  1597. {
  1598. _log.log(Level.WARNING, "could not delete char quest:", e);
  1599. }
  1600. }
  1601. /**
  1602. * Create a database record for the specified quest state.
  1603. * @param qs the {@link QuestState} object whose data to write in the database
  1604. */
  1605. public static void createQuestInDb(QuestState qs)
  1606. {
  1607. createQuestVarInDb(qs, "<state>", State.getStateName(qs.getState()));
  1608. }
  1609. /**
  1610. * Update a quest state record of the specified quest state in database.
  1611. * @param qs the {@link QuestState} object whose data to update in the database
  1612. */
  1613. public static void updateQuestInDb(QuestState qs)
  1614. {
  1615. updateQuestVarInDb(qs, "<state>", State.getStateName(qs.getState()));
  1616. }
  1617. /**
  1618. * @param player the player whose language settings to use in finding the html of the right language
  1619. * @return the default html for when no quest is available: "You are either not on a quest that involves this NPC.."
  1620. */
  1621. public static String getNoQuestMsg(L2PcInstance player)
  1622. {
  1623. final String result = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), "data/html/noquest.htm");
  1624. if ((result != null) && (result.length() > 0))
  1625. {
  1626. return result;
  1627. }
  1628. return DEFAULT_NO_QUEST_MSG;
  1629. }
  1630. /**
  1631. * @param player the player whose language settings to use in finding the html of the right language
  1632. * @return the default html for when no quest is already completed: "This quest has already been completed."
  1633. */
  1634. public static String getAlreadyCompletedMsg(L2PcInstance player)
  1635. {
  1636. final String result = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), "data/html/alreadycompleted.htm");
  1637. if ((result != null) && (result.length() > 0))
  1638. {
  1639. return result;
  1640. }
  1641. return DEFAULT_ALREADY_COMPLETED_MSG;
  1642. }
  1643. /**
  1644. * Add this quest to the list of quests that the passed mob will respond to for the specified Event type.
  1645. * @param eventType type of event being registered
  1646. * @param npcId the ID of the NPC to register
  1647. */
  1648. public void addEventId(QuestEventType eventType, int npcId)
  1649. {
  1650. try
  1651. {
  1652. final L2NpcTemplate t = NpcData.getInstance().getTemplate(npcId);
  1653. if (t != null)
  1654. {
  1655. t.addQuestEvent(eventType, this);
  1656. _questInvolvedNpcs.add(npcId);
  1657. }
  1658. }
  1659. catch (Exception e)
  1660. {
  1661. _log.log(Level.WARNING, "Exception on addEventId(): " + e.getMessage(), e);
  1662. }
  1663. }
  1664. /**
  1665. * Add this quest to the list of quests that the passed mob will respond to for the specified Event type.
  1666. * @param eventType type of event being registered
  1667. * @param npcIds the IDs of the NPCs to register
  1668. */
  1669. public void addEventId(QuestEventType eventType, int... npcIds)
  1670. {
  1671. for (int npcId : npcIds)
  1672. {
  1673. addEventId(eventType, npcId);
  1674. }
  1675. }
  1676. /**
  1677. * Add this quest to the list of quests that the passed mob will respond to for the specified Event type.
  1678. * @param eventType type of event being registered
  1679. * @param npcIds the IDs of the NPCs to register
  1680. */
  1681. public void addEventId(QuestEventType eventType, Collection<Integer> npcIds)
  1682. {
  1683. for (int npcId : npcIds)
  1684. {
  1685. addEventId(eventType, npcId);
  1686. }
  1687. }
  1688. // TODO: Remove after all Jython scripts are replaced with Java versions.
  1689. public void addStartNpc(int npcId)
  1690. {
  1691. addEventId(QuestEventType.QUEST_START, npcId);
  1692. }
  1693. public void addFirstTalkId(int npcId)
  1694. {
  1695. addEventId(QuestEventType.ON_FIRST_TALK, npcId);
  1696. }
  1697. public void addTalkId(int npcId)
  1698. {
  1699. addEventId(QuestEventType.ON_TALK, npcId);
  1700. }
  1701. public void addKillId(int killId)
  1702. {
  1703. addEventId(QuestEventType.ON_KILL, killId);
  1704. }
  1705. public void addAttackId(int npcId)
  1706. {
  1707. addEventId(QuestEventType.ON_ATTACK, npcId);
  1708. }
  1709. /**
  1710. * Add the quest to the NPC's startQuest
  1711. * @param npcIds the IDs of the NPCs to register
  1712. */
  1713. public void addStartNpc(int... npcIds)
  1714. {
  1715. addEventId(QuestEventType.QUEST_START, npcIds);
  1716. }
  1717. /**
  1718. * Add the quest to the NPC's startQuest
  1719. * @param npcIds the IDs of the NPCs to register
  1720. */
  1721. public void addStartNpc(Collection<Integer> npcIds)
  1722. {
  1723. addEventId(QuestEventType.QUEST_START, npcIds);
  1724. }
  1725. /**
  1726. * Add the quest to the NPC's first-talk (default action dialog).
  1727. * @param npcIds the IDs of the NPCs to register
  1728. */
  1729. public void addFirstTalkId(int... npcIds)
  1730. {
  1731. addEventId(QuestEventType.ON_FIRST_TALK, npcIds);
  1732. }
  1733. /**
  1734. * Add the quest to the NPC's first-talk (default action dialog).
  1735. * @param npcIds the IDs of the NPCs to register
  1736. */
  1737. public void addFirstTalkId(Collection<Integer> npcIds)
  1738. {
  1739. addEventId(QuestEventType.ON_FIRST_TALK, npcIds);
  1740. }
  1741. /**
  1742. * Add the NPC to the AcquireSkill dialog.
  1743. * @param npcIds the IDs of the NPCs to register
  1744. */
  1745. public void addAcquireSkillId(int... npcIds)
  1746. {
  1747. addEventId(QuestEventType.ON_SKILL_LEARN, npcIds);
  1748. }
  1749. /**
  1750. * Add the NPC to the AcquireSkill dialog.
  1751. * @param npcIds the IDs of the NPCs to register
  1752. */
  1753. public void addAcquireSkillId(Collection<Integer> npcIds)
  1754. {
  1755. addEventId(QuestEventType.ON_SKILL_LEARN, npcIds);
  1756. }
  1757. /**
  1758. * Add this quest to the list of quests that the passed mob will respond to for attack events.
  1759. * @param npcIds the IDs of the NPCs to register
  1760. */
  1761. public void addAttackId(int... npcIds)
  1762. {
  1763. addEventId(QuestEventType.ON_ATTACK, npcIds);
  1764. }
  1765. /**
  1766. * Add this quest to the list of quests that the passed mob will respond to for attack events.
  1767. * @param npcIds the IDs of the NPCs to register
  1768. */
  1769. public void addAttackId(Collection<Integer> npcIds)
  1770. {
  1771. addEventId(QuestEventType.ON_ATTACK, npcIds);
  1772. }
  1773. /**
  1774. * Add this quest to the list of quests that the passed mob will respond to for kill events.
  1775. * @param killIds
  1776. */
  1777. public void addKillId(int... killIds)
  1778. {
  1779. addEventId(QuestEventType.ON_KILL, killIds);
  1780. }
  1781. /**
  1782. * Add this quest event to the collection of NPC IDs that will respond to for on kill events.
  1783. * @param killIds the collection of NPC IDs
  1784. */
  1785. public void addKillId(Collection<Integer> killIds)
  1786. {
  1787. addEventId(QuestEventType.ON_KILL, killIds);
  1788. }
  1789. /**
  1790. * Add this quest to the list of quests that the passed npc will respond to for Talk Events.
  1791. * @param npcIds the IDs of the NPCs to register
  1792. */
  1793. public void addTalkId(int... npcIds)
  1794. {
  1795. addEventId(QuestEventType.ON_TALK, npcIds);
  1796. }
  1797. public void addTalkId(Collection<Integer> npcIds)
  1798. {
  1799. addEventId(QuestEventType.ON_TALK, npcIds);
  1800. }
  1801. /**
  1802. * Add this quest to the list of quests that the passed npc will respond to for spawn events.
  1803. * @param npcIds the IDs of the NPCs to register
  1804. */
  1805. public void addSpawnId(int... npcIds)
  1806. {
  1807. addEventId(QuestEventType.ON_SPAWN, npcIds);
  1808. }
  1809. /**
  1810. * Add this quest to the list of quests that the passed npc will respond to for spawn events.
  1811. * @param npcIds the IDs of the NPCs to register
  1812. */
  1813. public void addSpawnId(Collection<Integer> npcIds)
  1814. {
  1815. addEventId(QuestEventType.ON_SPAWN, npcIds);
  1816. }
  1817. /**
  1818. * Add this quest to the list of quests that the passed npc will respond to for skill see events.
  1819. * @param npcIds the IDs of the NPCs to register
  1820. */
  1821. public void addSkillSeeId(int... npcIds)
  1822. {
  1823. addEventId(QuestEventType.ON_SKILL_SEE, npcIds);
  1824. }
  1825. /**
  1826. * Add this quest to the list of quests that the passed npc will respond to for skill see events.
  1827. * @param npcIds the IDs of the NPCs to register
  1828. */
  1829. public void addSkillSeeId(Collection<Integer> npcIds)
  1830. {
  1831. addEventId(QuestEventType.ON_SKILL_SEE, npcIds);
  1832. }
  1833. /**
  1834. * @param npcIds the IDs of the NPCs to register
  1835. */
  1836. public void addSpellFinishedId(int... npcIds)
  1837. {
  1838. addEventId(QuestEventType.ON_SPELL_FINISHED, npcIds);
  1839. }
  1840. /**
  1841. * @param npcIds the IDs of the NPCs to register
  1842. */
  1843. public void addSpellFinishedId(Collection<Integer> npcIds)
  1844. {
  1845. addEventId(QuestEventType.ON_SPELL_FINISHED, npcIds);
  1846. }
  1847. /**
  1848. * @param npcIds the IDs of the NPCs to register
  1849. */
  1850. public void addTrapActionId(int... npcIds)
  1851. {
  1852. addEventId(QuestEventType.ON_TRAP_ACTION, npcIds);
  1853. }
  1854. /**
  1855. * @param npcIds the IDs of the NPCs to register
  1856. */
  1857. public void addTrapActionId(Collection<Integer> npcIds)
  1858. {
  1859. addEventId(QuestEventType.ON_TRAP_ACTION, npcIds);
  1860. }
  1861. /**
  1862. * Add this quest to the list of quests that the passed npc will respond to for faction call events.
  1863. * @param npcIds the IDs of the NPCs to register
  1864. */
  1865. public void addFactionCallId(int... npcIds)
  1866. {
  1867. addEventId(QuestEventType.ON_FACTION_CALL, npcIds);
  1868. }
  1869. /**
  1870. * Add this quest to the list of quests that the passed npc will respond to for faction call events.
  1871. * @param npcIds the IDs of the NPCs to register
  1872. */
  1873. public void addFactionCallId(Collection<Integer> npcIds)
  1874. {
  1875. addEventId(QuestEventType.ON_FACTION_CALL, npcIds);
  1876. }
  1877. /**
  1878. * Add this quest to the list of quests that the passed npc will respond to for character see events.
  1879. * @param npcIds the IDs of the NPCs to register
  1880. */
  1881. public void addAggroRangeEnterId(int... npcIds)
  1882. {
  1883. addEventId(QuestEventType.ON_AGGRO_RANGE_ENTER, npcIds);
  1884. }
  1885. /**
  1886. * Add this quest to the list of quests that the passed npc will respond to for character see events.
  1887. * @param npcIds the IDs of the NPCs to register
  1888. */
  1889. public void addAggroRangeEnterId(Collection<Integer> npcIds)
  1890. {
  1891. addEventId(QuestEventType.ON_AGGRO_RANGE_ENTER, npcIds);
  1892. }
  1893. /**
  1894. * @param npcIds the IDs of the NPCs to register
  1895. */
  1896. public void addSeeCreatureId(int... npcIds)
  1897. {
  1898. addEventId(QuestEventType.ON_SEE_CREATURE, npcIds);
  1899. }
  1900. /**
  1901. * @param npcIds the IDs of the NPCs to register
  1902. */
  1903. public void addSeeCreatureId(Collection<Integer> npcIds)
  1904. {
  1905. addEventId(QuestEventType.ON_SEE_CREATURE, npcIds);
  1906. }
  1907. /**
  1908. * Register onEnterZone trigger for zone
  1909. * @param zoneId the ID of the zone to register
  1910. */
  1911. public void addEnterZoneId(int zoneId)
  1912. {
  1913. final L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1914. if (zone != null)
  1915. {
  1916. zone.addQuestEvent(QuestEventType.ON_ENTER_ZONE, this);
  1917. }
  1918. }
  1919. /**
  1920. * Register onEnterZone trigger for zones
  1921. * @param zoneIds the IDs of the zones to register
  1922. */
  1923. public void addEnterZoneId(int... zoneIds)
  1924. {
  1925. for (int zoneId : zoneIds)
  1926. {
  1927. addEnterZoneId(zoneId);
  1928. }
  1929. }
  1930. /**
  1931. * Register onEnterZone trigger for zones
  1932. * @param zoneIds the IDs of the zones to register
  1933. */
  1934. public void addEnterZoneId(Collection<Integer> zoneIds)
  1935. {
  1936. for (int zoneId : zoneIds)
  1937. {
  1938. addEnterZoneId(zoneId);
  1939. }
  1940. }
  1941. /**
  1942. * Register onExitZone trigger for zone
  1943. * @param zoneId the ID of the zone to register
  1944. */
  1945. public void addExitZoneId(int zoneId)
  1946. {
  1947. L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1948. if (zone != null)
  1949. {
  1950. zone.addQuestEvent(QuestEventType.ON_EXIT_ZONE, this);
  1951. }
  1952. }
  1953. /**
  1954. * Register onExitZone trigger for zones
  1955. * @param zoneIds the IDs of the zones to register
  1956. */
  1957. public void addExitZoneId(int... zoneIds)
  1958. {
  1959. for (int zoneId : zoneIds)
  1960. {
  1961. addExitZoneId(zoneId);
  1962. }
  1963. }
  1964. /**
  1965. * Register onExitZone trigger for zones
  1966. * @param zoneIds the IDs of the zones to register
  1967. */
  1968. public void addExitZoneId(Collection<Integer> zoneIds)
  1969. {
  1970. for (int zoneId : zoneIds)
  1971. {
  1972. addExitZoneId(zoneId);
  1973. }
  1974. }
  1975. /**
  1976. * Register onEventReceived trigger for NPC
  1977. * @param npcIds the IDs of the NPCs to register
  1978. */
  1979. public void addEventReceivedId(int... npcIds)
  1980. {
  1981. addEventId(QuestEventType.ON_EVENT_RECEIVED, npcIds);
  1982. }
  1983. /**
  1984. * Register onEventReceived trigger for NPC
  1985. * @param npcIds the IDs of the NPCs to register
  1986. */
  1987. public void addEventReceivedId(Collection<Integer> npcIds)
  1988. {
  1989. addEventId(QuestEventType.ON_EVENT_RECEIVED, npcIds);
  1990. }
  1991. /**
  1992. * Register onMoveFinished trigger for NPC
  1993. * @param npcIds the IDs of the NPCs to register
  1994. */
  1995. public void addMoveFinishedId(int... npcIds)
  1996. {
  1997. addEventId(QuestEventType.ON_MOVE_FINISHED, npcIds);
  1998. }
  1999. /**
  2000. * Register onMoveFinished trigger for NPC
  2001. * @param npcIds the IDs of the NPCs to register
  2002. */
  2003. public void addMoveFinishedId(Collection<Integer> npcIds)
  2004. {
  2005. addEventId(QuestEventType.ON_MOVE_FINISHED, npcIds);
  2006. }
  2007. /**
  2008. * Register onNodeArrived trigger for NPC
  2009. * @param npcIds the IDs of the NPCs to register
  2010. */
  2011. public void addNodeArrivedId(int... npcIds)
  2012. {
  2013. addEventId(QuestEventType.ON_NODE_ARRIVED, npcIds);
  2014. }
  2015. /**
  2016. * Register onNodeArrived trigger for NPC
  2017. * @param npcIds the IDs of the NPCs to register
  2018. */
  2019. public void addNodeArrivedId(Collection<Integer> npcIds)
  2020. {
  2021. addEventId(QuestEventType.ON_NODE_ARRIVED, npcIds);
  2022. }
  2023. /**
  2024. * Register onRouteFinished trigger for NPC
  2025. * @param npcIds the IDs of the NPCs to register
  2026. */
  2027. public void addRouteFinishedId(int... npcIds)
  2028. {
  2029. addEventId(QuestEventType.ON_ROUTE_FINISHED, npcIds);
  2030. }
  2031. /**
  2032. * Register onRouteFinished trigger for NPC
  2033. * @param npcIds the IDs of the NPCs to register
  2034. */
  2035. public void addRouteFinishedId(Collection<Integer> npcIds)
  2036. {
  2037. addEventId(QuestEventType.ON_ROUTE_FINISHED, npcIds);
  2038. }
  2039. /**
  2040. * Register onNpcHate trigger for NPC
  2041. * @param npcIds
  2042. */
  2043. public void addNpcHateId(int... npcIds)
  2044. {
  2045. addEventId(QuestEventType.ON_NPC_HATE, npcIds);
  2046. }
  2047. /**
  2048. * Register onNpcHate trigger for NPC
  2049. * @param npcIds
  2050. */
  2051. public void addNpcHateId(Collection<Integer> npcIds)
  2052. {
  2053. addEventId(QuestEventType.ON_NPC_HATE, npcIds);
  2054. }
  2055. /**
  2056. * Register onSummon trigger when summon is spawned.
  2057. * @param npcIds
  2058. */
  2059. public void addSummonId(int... npcIds)
  2060. {
  2061. addEventId(QuestEventType.ON_SUMMON, npcIds);
  2062. }
  2063. /**
  2064. * Register onSummon trigger when summon is spawned.
  2065. * @param npcIds
  2066. */
  2067. public void addSummonId(Collection<Integer> npcIds)
  2068. {
  2069. addEventId(QuestEventType.ON_SUMMON, npcIds);
  2070. }
  2071. /**
  2072. * Use this method to get a random party member from a player's party.<br>
  2073. * Useful when distributing rewards after killing an NPC.
  2074. * @param player this parameter represents the player whom the party will taken.
  2075. * @return {@code null} if {@code player} is {@code null}, {@code player} itself if the player does not have a party, and a random party member in all other cases
  2076. */
  2077. public L2PcInstance getRandomPartyMember(L2PcInstance player)
  2078. {
  2079. if (player == null)
  2080. {
  2081. return null;
  2082. }
  2083. final L2Party party = player.getParty();
  2084. if ((party == null) || (party.getMembers().isEmpty()))
  2085. {
  2086. return player;
  2087. }
  2088. return party.getMembers().get(Rnd.get(party.getMembers().size()));
  2089. }
  2090. /**
  2091. * Get a random party member with required cond value.
  2092. * @param player the instance of a player whose party is to be searched
  2093. * @param cond the value of the "cond" variable that must be matched
  2094. * @return a random party member that matches the specified condition, or {@code null} if no match was found
  2095. */
  2096. public L2PcInstance getRandomPartyMember(L2PcInstance player, int cond)
  2097. {
  2098. return getRandomPartyMember(player, "cond", String.valueOf(cond));
  2099. }
  2100. /**
  2101. * Auxiliary function for party quests.<br>
  2102. * Note: This function is only here because of how commonly it may be used by quest developers.<br>
  2103. * For any variations on this function, the quest script can always handle things on its own.
  2104. * @param player the instance of a player whose party is to be searched
  2105. * @param var the quest variable to look for in party members. If {@code null}, it simply unconditionally returns a random party member
  2106. * @param value the value of the specified quest variable the random party member must have
  2107. * @return a random party member that matches the specified conditions or {@code null} if no match was found.<br>
  2108. * If the {@code var} parameter is {@code null}, a random party member is selected without any conditions.<br>
  2109. * The party member must be within a range of 1500 ingame units of the target of the reference player, or, if no target exists, within the same range of the player itself
  2110. */
  2111. public L2PcInstance getRandomPartyMember(L2PcInstance player, String var, String value)
  2112. {
  2113. // if no valid player instance is passed, there is nothing to check...
  2114. if (player == null)
  2115. {
  2116. return null;
  2117. }
  2118. // for null var condition, return any random party member.
  2119. if (var == null)
  2120. {
  2121. return getRandomPartyMember(player);
  2122. }
  2123. // normal cases...if the player is not in a party, check the player's state
  2124. QuestState temp = null;
  2125. L2Party party = player.getParty();
  2126. // if this player is not in a party, just check if this player instance matches the conditions itself
  2127. if ((party == null) || (party.getMembers().isEmpty()))
  2128. {
  2129. temp = player.getQuestState(getName());
  2130. if ((temp != null) && temp.isSet(var) && temp.get(var).equalsIgnoreCase(value))
  2131. {
  2132. return player; // match
  2133. }
  2134. return null; // no match
  2135. }
  2136. // if the player is in a party, gather a list of all matching party members (possibly including this player)
  2137. List<L2PcInstance> candidates = new ArrayList<>();
  2138. // get the target for enforcing distance limitations.
  2139. L2Object target = player.getTarget();
  2140. if (target == null)
  2141. {
  2142. target = player;
  2143. }
  2144. for (L2PcInstance partyMember : party.getMembers())
  2145. {
  2146. if (partyMember == null)
  2147. {
  2148. continue;
  2149. }
  2150. temp = partyMember.getQuestState(getName());
  2151. if ((temp != null) && (temp.get(var) != null) && (temp.get(var)).equalsIgnoreCase(value) && partyMember.isInsideRadius(target, 1500, true, false))
  2152. {
  2153. candidates.add(partyMember);
  2154. }
  2155. }
  2156. // if there was no match, return null...
  2157. if (candidates.isEmpty())
  2158. {
  2159. return null;
  2160. }
  2161. // if a match was found from the party, return one of them at random.
  2162. return candidates.get(Rnd.get(candidates.size()));
  2163. }
  2164. /**
  2165. * Auxiliary function for party quests.<br>
  2166. * Note: This function is only here because of how commonly it may be used by quest developers.<br>
  2167. * For any variations on this function, the quest script can always handle things on its own.
  2168. * @param player the player whose random party member is to be selected
  2169. * @param state the quest state required of the random party member
  2170. * @return {@code null} if nothing was selected or a random party member that has the specified quest state
  2171. */
  2172. public L2PcInstance getRandomPartyMemberState(L2PcInstance player, byte state)
  2173. {
  2174. // if no valid player instance is passed, there is nothing to check...
  2175. if (player == null)
  2176. {
  2177. return null;
  2178. }
  2179. // normal cases...if the player is not in a party check the player's state
  2180. QuestState temp = null;
  2181. L2Party party = player.getParty();
  2182. // if this player is not in a party, just check if this player instance matches the conditions itself
  2183. if ((party == null) || (party.getMembers().isEmpty()))
  2184. {
  2185. temp = player.getQuestState(getName());
  2186. if ((temp != null) && (temp.getState() == state))
  2187. {
  2188. return player; // match
  2189. }
  2190. return null; // no match
  2191. }
  2192. // if the player is in a party, gather a list of all matching party members (possibly
  2193. // including this player)
  2194. List<L2PcInstance> candidates = new ArrayList<>();
  2195. // get the target for enforcing distance limitations.
  2196. L2Object target = player.getTarget();
  2197. if (target == null)
  2198. {
  2199. target = player;
  2200. }
  2201. for (L2PcInstance partyMember : party.getMembers())
  2202. {
  2203. if (partyMember == null)
  2204. {
  2205. continue;
  2206. }
  2207. temp = partyMember.getQuestState(getName());
  2208. if ((temp != null) && (temp.getState() == state) && partyMember.isInsideRadius(target, 1500, true, false))
  2209. {
  2210. candidates.add(partyMember);
  2211. }
  2212. }
  2213. // if there was no match, return null...
  2214. if (candidates.isEmpty())
  2215. {
  2216. return null;
  2217. }
  2218. // if a match was found from the party, return one of them at random.
  2219. return candidates.get(Rnd.get(candidates.size()));
  2220. }
  2221. /**
  2222. * Get a random party member from the specified player's party.<br>
  2223. * If the player is not in a party, only the player himself is checked.<br>
  2224. * The lucky member is chosen by standard loot roll rules -<br>
  2225. * each member rolls a random number, the one with the highest roll wins.
  2226. * @param player the player whose party to check
  2227. * @param npc the NPC used for distance and other checks (if {@link #checkPartyMember(L2PcInstance, L2Npc)} is overriden)
  2228. * @return the random party member or {@code null}
  2229. */
  2230. public L2PcInstance getRandomPartyMember(L2PcInstance player, L2Npc npc)
  2231. {
  2232. if ((player == null) || !checkDistanceToTarget(player, npc))
  2233. {
  2234. return null;
  2235. }
  2236. final L2Party party = player.getParty();
  2237. L2PcInstance luckyPlayer = null;
  2238. if (party == null)
  2239. {
  2240. if (checkPartyMember(player, npc))
  2241. {
  2242. luckyPlayer = player;
  2243. }
  2244. }
  2245. else
  2246. {
  2247. int highestRoll = 0;
  2248. for (L2PcInstance member : party.getMembers())
  2249. {
  2250. final int rnd = getRandom(1000);
  2251. if ((rnd > highestRoll) && checkPartyMember(member, npc))
  2252. {
  2253. highestRoll = rnd;
  2254. luckyPlayer = member;
  2255. }
  2256. }
  2257. }
  2258. if ((luckyPlayer != null) && checkDistanceToTarget(luckyPlayer, npc))
  2259. {
  2260. return luckyPlayer;
  2261. }
  2262. return null;
  2263. }
  2264. /**
  2265. * This method is called for every party member in {@link #getRandomPartyMember(L2PcInstance, L2Npc)}.<br>
  2266. * It is intended to be overriden by the specific quest implementations.
  2267. * @param player the player to check
  2268. * @param npc the NPC that was passed to {@link #getRandomPartyMember(L2PcInstance, L2Npc)}
  2269. * @return {@code true} if this party member passes the check, {@code false} otherwise
  2270. */
  2271. public boolean checkPartyMember(L2PcInstance player, L2Npc npc)
  2272. {
  2273. return true;
  2274. }
  2275. /**
  2276. * Get a random party member from the player's party who has this quest at the specified quest progress.<br>
  2277. * If the player is not in a party, only the player himself is checked.
  2278. * @param player the player whose random party member state to get
  2279. * @param condition the quest progress step the random member should be at (-1 = check only if quest is started)
  2280. * @param playerChance how many times more chance does the player get compared to other party members (3 - 3x more chance).<br>
  2281. * On retail servers, the killer usually gets 2-3x more chance than other party members
  2282. * @param target the NPC to use for the distance check (can be null)
  2283. * @return the {@link QuestState} object of the random party member or {@code null} if none matched the condition
  2284. */
  2285. public QuestState getRandomPartyMemberState(L2PcInstance player, int condition, int playerChance, L2Npc target)
  2286. {
  2287. if ((player == null) || (playerChance < 1))
  2288. {
  2289. return null;
  2290. }
  2291. QuestState qs = player.getQuestState(getName());
  2292. if (!player.isInParty())
  2293. {
  2294. if (!checkPartyMemberConditions(qs, condition, target))
  2295. {
  2296. return null;
  2297. }
  2298. if (!checkDistanceToTarget(player, target))
  2299. {
  2300. return null;
  2301. }
  2302. return qs;
  2303. }
  2304. final List<QuestState> candidates = new ArrayList<>();
  2305. if (checkPartyMemberConditions(qs, condition, target) && (playerChance > 0))
  2306. {
  2307. for (int i = 0; i < playerChance; i++)
  2308. {
  2309. candidates.add(qs);
  2310. }
  2311. }
  2312. for (L2PcInstance member : player.getParty().getMembers())
  2313. {
  2314. if (member == player)
  2315. {
  2316. continue;
  2317. }
  2318. qs = member.getQuestState(getName());
  2319. if (checkPartyMemberConditions(qs, condition, target))
  2320. {
  2321. candidates.add(qs);
  2322. }
  2323. }
  2324. if (candidates.isEmpty())
  2325. {
  2326. return null;
  2327. }
  2328. qs = candidates.get(getRandom(candidates.size()));
  2329. if (!checkDistanceToTarget(qs.getPlayer(), target))
  2330. {
  2331. return null;
  2332. }
  2333. return qs;
  2334. }
  2335. private boolean checkPartyMemberConditions(QuestState qs, int condition, L2Npc npc)
  2336. {
  2337. return ((qs != null) && ((condition == -1) ? qs.isStarted() : qs.isCond(condition)) && checkPartyMember(qs, npc));
  2338. }
  2339. private static boolean checkDistanceToTarget(L2PcInstance player, L2Npc target)
  2340. {
  2341. return ((target == null) || com.l2jserver.gameserver.util.Util.checkIfInRange(1500, player, target, true));
  2342. }
  2343. /**
  2344. * This method is called for every party member in {@link #getRandomPartyMemberState(L2PcInstance, int, int, L2Npc)} if/after all the standard checks are passed.<br>
  2345. * It is intended to be overriden by the specific quest implementations.<br>
  2346. * It can be used in cases when there are more checks performed than simply a quest condition check,<br>
  2347. * for example, if an item is required in the player's inventory.
  2348. * @param qs the {@link QuestState} object of the party member
  2349. * @param npc the NPC that was passed as the last parameter to {@link #getRandomPartyMemberState(L2PcInstance, int, int, L2Npc)}
  2350. * @return {@code true} if this party member passes the check, {@code false} otherwise
  2351. */
  2352. public boolean checkPartyMember(QuestState qs, L2Npc npc)
  2353. {
  2354. return true;
  2355. }
  2356. /**
  2357. * Show an on screen message to the player.
  2358. * @param player the player to display the message to
  2359. * @param text the message to display
  2360. * @param time the duration of the message in milliseconds
  2361. */
  2362. public static void showOnScreenMsg(L2PcInstance player, String text, int time)
  2363. {
  2364. player.sendPacket(new ExShowScreenMessage(text, time));
  2365. }
  2366. /**
  2367. * Show an on screen message to the player.
  2368. * @param player the player to display the message to
  2369. * @param npcString the NPC string to display
  2370. * @param position the position of the message on the screen
  2371. * @param time the duration of the message in milliseconds
  2372. * @param params values of parameters to replace in the NPC String (like S1, C1 etc.)
  2373. */
  2374. public static void showOnScreenMsg(L2PcInstance player, NpcStringId npcString, int position, int time, String... params)
  2375. {
  2376. player.sendPacket(new ExShowScreenMessage(npcString, position, time, params));
  2377. }
  2378. /**
  2379. * Show an on screen message to the player.
  2380. * @param player the player to display the message to
  2381. * @param systemMsg the system message to display
  2382. * @param position the position of the message on the screen
  2383. * @param time the duration of the message in milliseconds
  2384. * @param params values of parameters to replace in the system message (like S1, C1 etc.)
  2385. */
  2386. public static void showOnScreenMsg(L2PcInstance player, SystemMessageId systemMsg, int position, int time, String... params)
  2387. {
  2388. player.sendPacket(new ExShowScreenMessage(systemMsg, position, time, params));
  2389. }
  2390. /**
  2391. * Send an HTML file to the specified player.
  2392. * @param player the player to send the HTML to
  2393. * @param filename the name of the HTML file to show
  2394. * @return the contents of the HTML file that was sent to the player
  2395. * @see #showHtmlFile(L2PcInstance, String, L2Npc)
  2396. */
  2397. public String showHtmlFile(L2PcInstance player, String filename)
  2398. {
  2399. return showHtmlFile(player, filename, null);
  2400. }
  2401. /**
  2402. * Send an HTML file to the specified player.
  2403. * @param player the player to send the HTML file to
  2404. * @param filename the name of the HTML file to show
  2405. * @param npc the NPC that is showing the HTML file
  2406. * @return the contents of the HTML file that was sent to the player
  2407. * @see #showHtmlFile(L2PcInstance, String, L2Npc)
  2408. */
  2409. public String showHtmlFile(L2PcInstance player, String filename, L2Npc npc)
  2410. {
  2411. boolean questwindow = !filename.endsWith(".html");
  2412. int questId = getId();
  2413. // Create handler to file linked to the quest
  2414. String content = getHtm(player.getHtmlPrefix(), filename);
  2415. // Send message to client if message not empty
  2416. if (content != null)
  2417. {
  2418. if (npc != null)
  2419. {
  2420. content = content.replaceAll("%objectId%", Integer.toString(npc.getObjectId()));
  2421. }
  2422. if (questwindow && (questId > 0) && (questId < 20000) && (questId != 999))
  2423. {
  2424. NpcQuestHtmlMessage npcReply = new NpcQuestHtmlMessage(npc != null ? npc.getObjectId() : 0, questId);
  2425. npcReply.setHtml(content);
  2426. npcReply.replace("%playername%", player.getName());
  2427. player.sendPacket(npcReply);
  2428. }
  2429. else
  2430. {
  2431. final NpcHtmlMessage npcReply = new NpcHtmlMessage(npc != null ? npc.getObjectId() : 0, content);
  2432. npcReply.replace("%playername%", player.getName());
  2433. player.sendPacket(npcReply);
  2434. }
  2435. player.sendPacket(ActionFailed.STATIC_PACKET);
  2436. }
  2437. return content;
  2438. }
  2439. /**
  2440. * @param prefix player's language prefix.
  2441. * @param fileName the html file to be get.
  2442. * @return the HTML file contents
  2443. */
  2444. public String getHtm(String prefix, String fileName)
  2445. {
  2446. final HtmCache hc = HtmCache.getInstance();
  2447. String content = hc.getHtm(prefix, fileName.startsWith("data/") ? fileName : "data/scripts/" + getDescr().toLowerCase() + "/" + getName() + "/" + fileName);
  2448. if (content == null)
  2449. {
  2450. content = hc.getHtm(prefix, "data/scripts/" + getDescr() + "/" + getName() + "/" + fileName);
  2451. if (content == null)
  2452. {
  2453. content = hc.getHtmForce(prefix, "data/scripts/quests/" + getName() + "/" + fileName);
  2454. }
  2455. }
  2456. return content;
  2457. }
  2458. /**
  2459. * Add a temporary spawn of the specified NPC.
  2460. * @param npcId the ID of the NPC to spawn
  2461. * @param pos the object containing the spawn location coordinates
  2462. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2463. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2464. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2465. */
  2466. public static L2Npc addSpawn(int npcId, IPositionable pos)
  2467. {
  2468. return addSpawn(npcId, pos.getX(), pos.getY(), pos.getZ(), pos.getHeading(), false, 0, false, 0);
  2469. }
  2470. /**
  2471. * Add a temporary spawn of the specified NPC.
  2472. * @param npcId the ID of the NPC to spawn
  2473. * @param pos the object containing the spawn location coordinates
  2474. * @param isSummonSpawn if {@code true}, displays a summon animation on NPC spawn
  2475. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2476. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2477. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2478. */
  2479. public static L2Npc addSpawn(int npcId, IPositionable pos, boolean isSummonSpawn)
  2480. {
  2481. return addSpawn(npcId, pos.getX(), pos.getY(), pos.getZ(), pos.getHeading(), false, 0, isSummonSpawn, 0);
  2482. }
  2483. /**
  2484. * Add a temporary spawn of the specified NPC.
  2485. * @param npcId the ID of the NPC to spawn
  2486. * @param pos the object containing the spawn location coordinates
  2487. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2488. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2489. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2490. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2491. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2492. */
  2493. public static L2Npc addSpawn(int npcId, IPositionable pos, boolean randomOffset, long despawnDelay)
  2494. {
  2495. return addSpawn(npcId, pos.getX(), pos.getY(), pos.getZ(), pos.getHeading(), randomOffset, despawnDelay, false, 0);
  2496. }
  2497. /**
  2498. * Add a temporary spawn of the specified NPC.
  2499. * @param npcId the ID of the NPC to spawn
  2500. * @param pos the object containing the spawn location coordinates
  2501. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2502. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2503. * @param isSummonSpawn if {@code true}, displays a summon animation on NPC spawn
  2504. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2505. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2506. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2507. */
  2508. public static L2Npc addSpawn(int npcId, IPositionable pos, boolean randomOffset, long despawnDelay, boolean isSummonSpawn)
  2509. {
  2510. return addSpawn(npcId, pos.getX(), pos.getY(), pos.getZ(), pos.getHeading(), randomOffset, despawnDelay, isSummonSpawn, 0);
  2511. }
  2512. /**
  2513. * Add a temporary spawn of the specified NPC.
  2514. * @param npcId the ID of the NPC to spawn
  2515. * @param pos the object containing the spawn location coordinates
  2516. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2517. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2518. * @param isSummonSpawn if {@code true}, displays a summon animation on NPC spawn
  2519. * @param instanceId the ID of the instance to spawn the NPC in (0 - the open world)
  2520. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2521. * @see #addSpawn(int, IPositionable)
  2522. * @see #addSpawn(int, IPositionable, boolean)
  2523. * @see #addSpawn(int, IPositionable, boolean, long)
  2524. * @see #addSpawn(int, IPositionable, boolean, long, boolean)
  2525. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2526. */
  2527. public static L2Npc addSpawn(int npcId, IPositionable pos, boolean randomOffset, long despawnDelay, boolean isSummonSpawn, int instanceId)
  2528. {
  2529. return addSpawn(npcId, pos.getX(), pos.getY(), pos.getZ(), pos.getHeading(), randomOffset, despawnDelay, isSummonSpawn, instanceId);
  2530. }
  2531. /**
  2532. * Add a temporary spawn of the specified NPC.
  2533. * @param npcId the ID of the NPC to spawn
  2534. * @param x the X coordinate of the spawn location
  2535. * @param y the Y coordinate of the spawn location
  2536. * @param z the Z coordinate (height) of the spawn location
  2537. * @param heading the heading of the NPC
  2538. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2539. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2540. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2541. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2542. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2543. */
  2544. public static L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay)
  2545. {
  2546. return addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, false, 0);
  2547. }
  2548. /**
  2549. * Add a temporary spawn of the specified NPC.
  2550. * @param npcId the ID of the NPC to spawn
  2551. * @param x the X coordinate of the spawn location
  2552. * @param y the Y coordinate of the spawn location
  2553. * @param z the Z coordinate (height) of the spawn location
  2554. * @param heading the heading of the NPC
  2555. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2556. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2557. * @param isSummonSpawn if {@code true}, displays a summon animation on NPC spawn
  2558. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2559. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2560. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean, int)
  2561. */
  2562. public static L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay, boolean isSummonSpawn)
  2563. {
  2564. return addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn, 0);
  2565. }
  2566. /**
  2567. * Add a temporary spawn of the specified NPC.
  2568. * @param npcId the ID of the NPC to spawn
  2569. * @param x the X coordinate of the spawn location
  2570. * @param y the Y coordinate of the spawn location
  2571. * @param z the Z coordinate (height) of the spawn location
  2572. * @param heading the heading of the NPC
  2573. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  2574. * @param despawnDelay time in milliseconds till the NPC is despawned (0 - only despawned on server shutdown)
  2575. * @param isSummonSpawn if {@code true}, displays a summon animation on NPC spawn
  2576. * @param instanceId the ID of the instance to spawn the NPC in (0 - the open world)
  2577. * @return the {@link L2Npc} object of the newly spawned NPC or {@code null} if the NPC doesn't exist
  2578. * @see #addSpawn(int, IPositionable, boolean, long, boolean, int)
  2579. * @see #addSpawn(int, int, int, int, int, boolean, long)
  2580. * @see #addSpawn(int, int, int, int, int, boolean, long, boolean)
  2581. */
  2582. public static L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay, boolean isSummonSpawn, int instanceId)
  2583. {
  2584. try
  2585. {
  2586. L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
  2587. if (template == null)
  2588. {
  2589. _log.log(Level.SEVERE, "addSpawn(): no NPC template found for NPC #" + npcId + "!");
  2590. }
  2591. else
  2592. {
  2593. if ((x == 0) && (y == 0))
  2594. {
  2595. _log.log(Level.SEVERE, "addSpawn(): invalid spawn coordinates for NPC #" + npcId + "!");
  2596. return null;
  2597. }
  2598. if (randomOffset)
  2599. {
  2600. int offset = Rnd.get(50, 100);
  2601. if (Rnd.nextBoolean())
  2602. {
  2603. offset *= -1;
  2604. }
  2605. x += offset;
  2606. offset = Rnd.get(50, 100);
  2607. if (Rnd.nextBoolean())
  2608. {
  2609. offset *= -1;
  2610. }
  2611. y += offset;
  2612. }
  2613. L2Spawn spawn = new L2Spawn(template);
  2614. spawn.setInstanceId(instanceId);
  2615. spawn.setHeading(heading);
  2616. spawn.setX(x);
  2617. spawn.setY(y);
  2618. spawn.setZ(z);
  2619. spawn.stopRespawn();
  2620. L2Npc result = spawn.spawnOne(isSummonSpawn);
  2621. if (despawnDelay > 0)
  2622. {
  2623. result.scheduleDespawn(despawnDelay);
  2624. }
  2625. return result;
  2626. }
  2627. }
  2628. catch (Exception e1)
  2629. {
  2630. _log.warning("Could not spawn NPC #" + npcId + "; error: " + e1.getMessage());
  2631. }
  2632. return null;
  2633. }
  2634. /**
  2635. * @param trapId
  2636. * @param x
  2637. * @param y
  2638. * @param z
  2639. * @param heading
  2640. * @param skill
  2641. * @param instanceId
  2642. * @return
  2643. */
  2644. public L2TrapInstance addTrap(int trapId, int x, int y, int z, int heading, L2Skill skill, int instanceId)
  2645. {
  2646. final L2NpcTemplate npcTemplate = NpcData.getInstance().getTemplate(trapId);
  2647. L2TrapInstance trap = new L2TrapInstance(IdFactory.getInstance().getNextId(), npcTemplate, instanceId, -1);
  2648. trap.setCurrentHp(trap.getMaxHp());
  2649. trap.setCurrentMp(trap.getMaxMp());
  2650. trap.setIsInvul(true);
  2651. trap.setHeading(heading);
  2652. trap.spawnMe(x, y, z);
  2653. return trap;
  2654. }
  2655. /**
  2656. * @param master
  2657. * @param minionId
  2658. * @return
  2659. */
  2660. public L2Npc addMinion(L2MonsterInstance master, int minionId)
  2661. {
  2662. return MinionList.spawnMinion(master, minionId);
  2663. }
  2664. /**
  2665. * @return the registered quest items IDs.
  2666. */
  2667. public int[] getRegisteredItemIds()
  2668. {
  2669. return questItemIds;
  2670. }
  2671. /**
  2672. * Registers all items that have to be destroyed in case player abort the quest or finish it.
  2673. * @param items
  2674. */
  2675. public void registerQuestItems(int... items)
  2676. {
  2677. questItemIds = items;
  2678. }
  2679. @Override
  2680. public String getScriptName()
  2681. {
  2682. return getName();
  2683. }
  2684. @Override
  2685. public void setActive(boolean status)
  2686. {
  2687. // TODO: Implement me.
  2688. }
  2689. @Override
  2690. public boolean reload()
  2691. {
  2692. unload();
  2693. return super.reload();
  2694. }
  2695. @Override
  2696. public boolean unload()
  2697. {
  2698. return unload(true);
  2699. }
  2700. /**
  2701. * @param removeFromList
  2702. * @return
  2703. */
  2704. public boolean unload(boolean removeFromList)
  2705. {
  2706. saveGlobalData();
  2707. // cancel all pending timers before reloading.
  2708. // if timers ought to be restarted, the quest can take care of it
  2709. // with its code (example: save global data indicating what timer must be restarted).
  2710. for (List<QuestTimer> timers : _allEventTimers.values())
  2711. {
  2712. _readLock.lock();
  2713. try
  2714. {
  2715. for (QuestTimer timer : timers)
  2716. {
  2717. timer.cancel();
  2718. }
  2719. }
  2720. finally
  2721. {
  2722. _readLock.unlock();
  2723. }
  2724. timers.clear();
  2725. }
  2726. _allEventTimers.clear();
  2727. for (Integer npcId : _questInvolvedNpcs)
  2728. {
  2729. L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId.intValue());
  2730. if (template != null)
  2731. {
  2732. template.removeQuest(this);
  2733. }
  2734. }
  2735. _questInvolvedNpcs.clear();
  2736. if (removeFromList)
  2737. {
  2738. return QuestManager.getInstance().removeQuest(this);
  2739. }
  2740. return true;
  2741. }
  2742. public Set<Integer> getQuestInvolvedNpcs()
  2743. {
  2744. return _questInvolvedNpcs;
  2745. }
  2746. @Override
  2747. public ScriptManager<?> getScriptManager()
  2748. {
  2749. return QuestManager.getInstance();
  2750. }
  2751. /**
  2752. * @param val
  2753. */
  2754. public void setOnEnterWorld(boolean val)
  2755. {
  2756. _onEnterWorld = val;
  2757. }
  2758. /**
  2759. * @return
  2760. */
  2761. public boolean getOnEnterWorld()
  2762. {
  2763. return _onEnterWorld;
  2764. }
  2765. /**
  2766. * If a quest is set as custom, it will display it's name in the NPC Quest List.<br>
  2767. * Retail quests are unhardcoded to display the name using a client string.
  2768. * @param val if {@code true} the quest script will be set as custom quest.
  2769. */
  2770. public void setIsCustom(boolean val)
  2771. {
  2772. _isCustom = val;
  2773. }
  2774. /**
  2775. * @return {@code true} if the quest script is a custom quest, {@code false} otherwise.
  2776. */
  2777. public boolean isCustomQuest()
  2778. {
  2779. return _isCustom;
  2780. }
  2781. /**
  2782. * @param val
  2783. */
  2784. public void setOlympiadUse(boolean val)
  2785. {
  2786. _isOlympiadUse = val;
  2787. }
  2788. /**
  2789. * @return {@code true} if the quest script is used for Olympiad quests, {@code false} otherwise.
  2790. */
  2791. public boolean isOlympiadUse()
  2792. {
  2793. return _isOlympiadUse;
  2794. }
  2795. /**
  2796. * Get the amount of an item in player's inventory.
  2797. * @param player the player whose inventory to check
  2798. * @param itemId the ID of the item whose amount to get
  2799. * @return the amount of the specified item in player's inventory
  2800. */
  2801. public static long getQuestItemsCount(L2PcInstance player, int itemId)
  2802. {
  2803. return player.getInventory().getInventoryItemCount(itemId, -1);
  2804. }
  2805. /**
  2806. * Get the total amount of all specified items in player's inventory.
  2807. * @param player the player whose inventory to check
  2808. * @param itemIds a list of IDs of items whose amount to get
  2809. * @return the summary amount of all listed items in player's inventory
  2810. */
  2811. public long getQuestItemsCount(L2PcInstance player, int... itemIds)
  2812. {
  2813. long count = 0;
  2814. for (L2ItemInstance item : player.getInventory().getItems())
  2815. {
  2816. if (item == null)
  2817. {
  2818. continue;
  2819. }
  2820. for (int itemId : itemIds)
  2821. {
  2822. if (item.getId() == itemId)
  2823. {
  2824. if ((count + item.getCount()) > Long.MAX_VALUE)
  2825. {
  2826. return Long.MAX_VALUE;
  2827. }
  2828. count += item.getCount();
  2829. }
  2830. }
  2831. }
  2832. return count;
  2833. }
  2834. /**
  2835. * Check if the player has the specified item in his inventory.
  2836. * @param player the player whose inventory to check for the specified item
  2837. * @param item the {@link ItemHolder} object containing the ID and count of the item to check
  2838. * @return {@code true} if the player has the required count of the item
  2839. */
  2840. protected static boolean hasItem(L2PcInstance player, ItemHolder item)
  2841. {
  2842. return hasItem(player, item, true);
  2843. }
  2844. /**
  2845. * Check if the player has the required count of the specified item in his inventory.
  2846. * @param player the player whose inventory to check for the specified item
  2847. * @param item the {@link ItemHolder} object containing the ID and count of the item to check
  2848. * @param checkCount if {@code true}, check if each item is at least of the count specified in the ItemHolder,<br>
  2849. * otherwise check only if the player has the item at all
  2850. * @return {@code true} if the player has the item
  2851. */
  2852. protected static boolean hasItem(L2PcInstance player, ItemHolder item, boolean checkCount)
  2853. {
  2854. if (item == null)
  2855. {
  2856. return false;
  2857. }
  2858. if (checkCount)
  2859. {
  2860. return (getQuestItemsCount(player, item.getId()) >= item.getCount());
  2861. }
  2862. return hasQuestItems(player, item.getId());
  2863. }
  2864. /**
  2865. * Check if the player has all the specified items in his inventory and, if necessary, if their count is also as required.
  2866. * @param player the player whose inventory to check for the specified item
  2867. * @param checkCount if {@code true}, check if each item is at least of the count specified in the ItemHolder,<br>
  2868. * otherwise check only if the player has the item at all
  2869. * @param itemList a list of {@link ItemHolder} objects containing the IDs of the items to check
  2870. * @return {@code true} if the player has all the items from the list
  2871. */
  2872. protected static boolean hasAllItems(L2PcInstance player, boolean checkCount, ItemHolder... itemList)
  2873. {
  2874. if ((itemList == null) || (itemList.length == 0))
  2875. {
  2876. return false;
  2877. }
  2878. for (ItemHolder item : itemList)
  2879. {
  2880. if (!hasItem(player, item, checkCount))
  2881. {
  2882. return false;
  2883. }
  2884. }
  2885. return true;
  2886. }
  2887. /**
  2888. * Check for an item in player's inventory.
  2889. * @param player the player whose inventory to check for quest items
  2890. * @param itemId the ID of the item to check for
  2891. * @return {@code true} if the item exists in player's inventory, {@code false} otherwise
  2892. */
  2893. public static boolean hasQuestItems(L2PcInstance player, int itemId)
  2894. {
  2895. return (player.getInventory().getItemByItemId(itemId) != null);
  2896. }
  2897. /**
  2898. * Check for multiple items in player's inventory.
  2899. * @param player the player whose inventory to check for quest items
  2900. * @param itemIds a list of item IDs to check for
  2901. * @return {@code true} if all items exist in player's inventory, {@code false} otherwise
  2902. */
  2903. public static boolean hasQuestItems(L2PcInstance player, int... itemIds)
  2904. {
  2905. if ((itemIds == null) || (itemIds.length == 0))
  2906. {
  2907. return false;
  2908. }
  2909. final PcInventory inv = player.getInventory();
  2910. for (int itemId : itemIds)
  2911. {
  2912. if (inv.getItemByItemId(itemId) == null)
  2913. {
  2914. return false;
  2915. }
  2916. }
  2917. return true;
  2918. }
  2919. /**
  2920. * Check for multiple items in player's inventory.
  2921. * @param player the player whose inventory to check for quest items
  2922. * @param itemIds a list of item IDs to check for
  2923. * @return {@code true} if at least one items exist in player's inventory, {@code false} otherwise
  2924. */
  2925. public boolean hasAtLeastOneQuestItem(L2PcInstance player, int... itemIds)
  2926. {
  2927. final PcInventory inv = player.getInventory();
  2928. for (int itemId : itemIds)
  2929. {
  2930. if (inv.getItemByItemId(itemId) != null)
  2931. {
  2932. return true;
  2933. }
  2934. }
  2935. return false;
  2936. }
  2937. /**
  2938. * Get the enchantment level of an item in player's inventory.
  2939. * @param player the player whose item to check
  2940. * @param itemId the ID of the item whose enchantment level to get
  2941. * @return the enchantment level of the item or 0 if the item was not found
  2942. */
  2943. public static int getEnchantLevel(L2PcInstance player, int itemId)
  2944. {
  2945. final L2ItemInstance enchantedItem = player.getInventory().getItemByItemId(itemId);
  2946. if (enchantedItem == null)
  2947. {
  2948. return 0;
  2949. }
  2950. return enchantedItem.getEnchantLevel();
  2951. }
  2952. /**
  2953. * Give Adena to the player.
  2954. * @param player the player to whom to give the Adena
  2955. * @param count the amount of Adena to give
  2956. * @param applyRates if {@code true} quest rates will be applied to the amount
  2957. */
  2958. public void giveAdena(L2PcInstance player, long count, boolean applyRates)
  2959. {
  2960. if (applyRates)
  2961. {
  2962. rewardItems(player, Inventory.ADENA_ID, count);
  2963. }
  2964. else
  2965. {
  2966. giveItems(player, Inventory.ADENA_ID, count);
  2967. }
  2968. }
  2969. /**
  2970. * Give a reward to player using multipliers.
  2971. * @param player the player to whom to give the item
  2972. * @param holder
  2973. */
  2974. public static void rewardItems(L2PcInstance player, ItemHolder holder)
  2975. {
  2976. rewardItems(player, holder.getId(), holder.getCount());
  2977. }
  2978. /**
  2979. * Give a reward to player using multipliers.
  2980. * @param player the player to whom to give the item
  2981. * @param itemId the ID of the item to give
  2982. * @param count the amount of items to give
  2983. */
  2984. public static void rewardItems(L2PcInstance player, int itemId, long count)
  2985. {
  2986. if (count <= 0)
  2987. {
  2988. return;
  2989. }
  2990. final L2ItemInstance _tmpItem = ItemTable.getInstance().createDummyItem(itemId);
  2991. if (_tmpItem == null)
  2992. {
  2993. return;
  2994. }
  2995. try
  2996. {
  2997. if (itemId == Inventory.ADENA_ID)
  2998. {
  2999. count *= Config.RATE_QUEST_REWARD_ADENA;
  3000. }
  3001. else if (Config.RATE_QUEST_REWARD_USE_MULTIPLIERS)
  3002. {
  3003. if (_tmpItem.isEtcItem())
  3004. {
  3005. switch (_tmpItem.getEtcItem().getItemType())
  3006. {
  3007. case POTION:
  3008. count *= Config.RATE_QUEST_REWARD_POTION;
  3009. break;
  3010. case SCRL_ENCHANT_WP:
  3011. case SCRL_ENCHANT_AM:
  3012. case SCROLL:
  3013. count *= Config.RATE_QUEST_REWARD_SCROLL;
  3014. break;
  3015. case RECIPE:
  3016. count *= Config.RATE_QUEST_REWARD_RECIPE;
  3017. break;
  3018. case MATERIAL:
  3019. count *= Config.RATE_QUEST_REWARD_MATERIAL;
  3020. break;
  3021. default:
  3022. count *= Config.RATE_QUEST_REWARD;
  3023. }
  3024. }
  3025. }
  3026. else
  3027. {
  3028. count *= Config.RATE_QUEST_REWARD;
  3029. }
  3030. }
  3031. catch (Exception e)
  3032. {
  3033. count = Long.MAX_VALUE;
  3034. }
  3035. // Add items to player's inventory
  3036. L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  3037. if (item == null)
  3038. {
  3039. return;
  3040. }
  3041. sendItemGetMessage(player, item, count);
  3042. }
  3043. /**
  3044. * Send the system message and the status update packets to the player.
  3045. * @param player the player that has got the item
  3046. * @param item the item obtain by the player
  3047. * @param count the item count
  3048. */
  3049. private static void sendItemGetMessage(L2PcInstance player, L2ItemInstance item, long count)
  3050. {
  3051. // If item for reward is gold, send message of gold reward to client
  3052. if (item.getId() == Inventory.ADENA_ID)
  3053. {
  3054. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA);
  3055. smsg.addLong(count);
  3056. player.sendPacket(smsg);
  3057. }
  3058. // Otherwise, send message of object reward to client
  3059. else
  3060. {
  3061. if (count > 1)
  3062. {
  3063. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
  3064. smsg.addItemName(item);
  3065. smsg.addLong(count);
  3066. player.sendPacket(smsg);
  3067. }
  3068. else
  3069. {
  3070. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
  3071. smsg.addItemName(item);
  3072. player.sendPacket(smsg);
  3073. }
  3074. }
  3075. // send packets
  3076. StatusUpdate su = new StatusUpdate(player);
  3077. su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  3078. player.sendPacket(su);
  3079. }
  3080. /**
  3081. * Give item/reward to the player
  3082. * @param player
  3083. * @param itemId
  3084. * @param count
  3085. */
  3086. public static void giveItems(L2PcInstance player, int itemId, long count)
  3087. {
  3088. giveItems(player, itemId, count, 0);
  3089. }
  3090. /**
  3091. * Give item/reward to the player
  3092. * @param player
  3093. * @param holder
  3094. */
  3095. protected static void giveItems(L2PcInstance player, ItemHolder holder)
  3096. {
  3097. giveItems(player, holder.getId(), holder.getCount());
  3098. }
  3099. /**
  3100. * @param player
  3101. * @param itemId
  3102. * @param count
  3103. * @param enchantlevel
  3104. */
  3105. public static void giveItems(L2PcInstance player, int itemId, long count, int enchantlevel)
  3106. {
  3107. if (count <= 0)
  3108. {
  3109. return;
  3110. }
  3111. // Add items to player's inventory
  3112. final L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  3113. if (item == null)
  3114. {
  3115. return;
  3116. }
  3117. // set enchant level for item if that item is not adena
  3118. if ((enchantlevel > 0) && (itemId != Inventory.ADENA_ID))
  3119. {
  3120. item.setEnchantLevel(enchantlevel);
  3121. }
  3122. sendItemGetMessage(player, item, count);
  3123. }
  3124. /**
  3125. * @param player
  3126. * @param itemId
  3127. * @param count
  3128. * @param attributeId
  3129. * @param attributeLevel
  3130. */
  3131. public static void giveItems(L2PcInstance player, int itemId, long count, byte attributeId, int attributeLevel)
  3132. {
  3133. if (count <= 0)
  3134. {
  3135. return;
  3136. }
  3137. // Add items to player's inventory
  3138. final L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  3139. if (item == null)
  3140. {
  3141. return;
  3142. }
  3143. // set enchant level for item if that item is not adena
  3144. if ((attributeId >= 0) && (attributeLevel > 0))
  3145. {
  3146. item.setElementAttr(attributeId, attributeLevel);
  3147. if (item.isEquipped())
  3148. {
  3149. item.updateElementAttrBonus(player);
  3150. }
  3151. InventoryUpdate iu = new InventoryUpdate();
  3152. iu.addModifiedItem(item);
  3153. player.sendPacket(iu);
  3154. }
  3155. sendItemGetMessage(player, item, count);
  3156. }
  3157. /**
  3158. * Give the specified player a set amount of items if he is lucky enough.<br>
  3159. * Not recommended to use this for non-stacking items.
  3160. * @param player the player to give the item(s) to
  3161. * @param itemId the ID of the item to give
  3162. * @param amountToGive the amount of items to give
  3163. * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. 0 - no limit.
  3164. * @param dropChance the drop chance as a decimal digit from 0 to 1
  3165. * @param playSound if true, plays ItemSound.quest_itemget when items are given and ItemSound.quest_middle when the limit is reached
  3166. * @return {@code true} if limit > 0 and the limit was reached or if limit <= 0 and items were given; {@code false} in all other cases
  3167. */
  3168. public static boolean giveItemRandomly(L2PcInstance player, int itemId, long amountToGive, long limit, double dropChance, boolean playSound)
  3169. {
  3170. return giveItemRandomly(player, null, itemId, amountToGive, amountToGive, limit, dropChance, playSound);
  3171. }
  3172. /**
  3173. * Give the specified player a set amount of items if he is lucky enough.<br>
  3174. * Not recommended to use this for non-stacking items.
  3175. * @param player the player to give the item(s) to
  3176. * @param npc the NPC that "dropped" the item (can be null)
  3177. * @param itemId the ID of the item to give
  3178. * @param amountToGive the amount of items to give
  3179. * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. 0 - no limit.
  3180. * @param dropChance the drop chance as a decimal digit from 0 to 1
  3181. * @param playSound if true, plays ItemSound.quest_itemget when items are given and ItemSound.quest_middle when the limit is reached
  3182. * @return {@code true} if limit > 0 and the limit was reached or if limit <= 0 and items were given; {@code false} in all other cases
  3183. */
  3184. public static boolean giveItemRandomly(L2PcInstance player, L2Npc npc, int itemId, long amountToGive, long limit, double dropChance, boolean playSound)
  3185. {
  3186. return giveItemRandomly(player, npc, itemId, amountToGive, amountToGive, limit, dropChance, playSound);
  3187. }
  3188. /**
  3189. * Give the specified player a random amount of items if he is lucky enough.<br>
  3190. * Not recommended to use this for non-stacking items.
  3191. * @param player the player to give the item(s) to
  3192. * @param npc the NPC that "dropped" the item (can be null)
  3193. * @param itemId the ID of the item to give
  3194. * @param minAmount the minimum amount of items to give
  3195. * @param maxAmount the maximum amount of items to give (will give a random amount between min/maxAmount multiplied by quest rates)
  3196. * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. 0 - no limit.
  3197. * @param dropChance the drop chance as a decimal digit from 0 to 1
  3198. * @param playSound if true, plays ItemSound.quest_itemget when items are given and ItemSound.quest_middle when the limit is reached
  3199. * @return {@code true} if limit > 0 and the limit was reached or if limit <= 0 and items were given; {@code false} in all other cases
  3200. */
  3201. public static boolean giveItemRandomly(L2PcInstance player, L2Npc npc, int itemId, long minAmount, long maxAmount, long limit, double dropChance, boolean playSound)
  3202. {
  3203. final long currentCount = getQuestItemsCount(player, itemId);
  3204. if ((limit > 0) && (currentCount >= limit))
  3205. {
  3206. return true;
  3207. }
  3208. minAmount *= Config.RATE_QUEST_DROP;
  3209. maxAmount *= Config.RATE_QUEST_DROP;
  3210. dropChance *= Config.RATE_QUEST_DROP; // TODO separate configs for rate and amount
  3211. if ((npc != null) && Config.L2JMOD_CHAMPION_ENABLE && npc.isChampion())
  3212. {
  3213. dropChance *= Config.L2JMOD_CHAMPION_REWARDS;
  3214. if ((itemId == Inventory.ADENA_ID) || (itemId == Inventory.ANCIENT_ADENA_ID))
  3215. {
  3216. minAmount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  3217. maxAmount *= Config.L2JMOD_CHAMPION_ADENAS_REWARDS;
  3218. }
  3219. else
  3220. {
  3221. minAmount *= Config.L2JMOD_CHAMPION_REWARDS;
  3222. maxAmount *= Config.L2JMOD_CHAMPION_REWARDS;
  3223. }
  3224. }
  3225. long amountToGive = ((minAmount == maxAmount) ? minAmount : Rnd.get(minAmount, maxAmount));
  3226. final double random = Rnd.nextDouble();
  3227. // Inventory slot check (almost useless for non-stacking items)
  3228. if ((dropChance >= random) && (amountToGive > 0) && player.getInventory().validateCapacityByItemId(itemId))
  3229. {
  3230. if ((limit > 0) && ((currentCount + amountToGive) > limit))
  3231. {
  3232. amountToGive = limit - currentCount;
  3233. }
  3234. // Give the item to player
  3235. L2ItemInstance item = player.addItem("Quest", itemId, amountToGive, npc, true);
  3236. if (item != null)
  3237. {
  3238. // limit reached (if there is no limit, this block doesn't execute)
  3239. if ((currentCount + amountToGive) == limit)
  3240. {
  3241. if (playSound)
  3242. {
  3243. playSound(player, QuestSound.ITEMSOUND_QUEST_MIDDLE);
  3244. }
  3245. return true;
  3246. }
  3247. if (playSound)
  3248. {
  3249. playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET);
  3250. }
  3251. // if there is no limit, return true every time an item is given
  3252. if (limit <= 0)
  3253. {
  3254. return true;
  3255. }
  3256. }
  3257. }
  3258. return false;
  3259. }
  3260. /**
  3261. * Take an amount of a specified item from player's inventory.
  3262. * @param player the player whose item to take
  3263. * @param itemId the ID of the item to take
  3264. * @param amount the amount to take
  3265. * @return {@code true} if any items were taken, {@code false} otherwise
  3266. */
  3267. public static boolean takeItems(L2PcInstance player, int itemId, long amount)
  3268. {
  3269. // Get object item from player's inventory list
  3270. final L2ItemInstance item = player.getInventory().getItemByItemId(itemId);
  3271. if (item == null)
  3272. {
  3273. return false;
  3274. }
  3275. // Tests on count value in order not to have negative value
  3276. if ((amount < 0) || (amount > item.getCount()))
  3277. {
  3278. amount = item.getCount();
  3279. }
  3280. // Destroy the quantity of items wanted
  3281. if (item.isEquipped())
  3282. {
  3283. final L2ItemInstance[] unequiped = player.getInventory().unEquipItemInBodySlotAndRecord(item.getItem().getBodyPart());
  3284. InventoryUpdate iu = new InventoryUpdate();
  3285. for (L2ItemInstance itm : unequiped)
  3286. {
  3287. iu.addModifiedItem(itm);
  3288. }
  3289. player.sendPacket(iu);
  3290. player.broadcastUserInfo();
  3291. }
  3292. return player.destroyItemByItemId("Quest", itemId, amount, player, true);
  3293. }
  3294. /**
  3295. * Take a set amount of a specified item from player's inventory.
  3296. * @param player the player whose item to take
  3297. * @param holder the {@link ItemHolder} object containing the ID and count of the item to take
  3298. * @return {@code true} if the item was taken, {@code false} otherwise
  3299. */
  3300. protected static boolean takeItem(L2PcInstance player, ItemHolder holder)
  3301. {
  3302. if (holder == null)
  3303. {
  3304. return false;
  3305. }
  3306. return takeItems(player, holder.getId(), holder.getCount());
  3307. }
  3308. /**
  3309. * Take a set amount of all specified items from player's inventory.
  3310. * @param player the player whose items to take
  3311. * @param itemList the list of {@link ItemHolder} objects containing the IDs and counts of the items to take
  3312. * @return {@code true} if all items were taken, {@code false} otherwise
  3313. */
  3314. protected static boolean takeAllItems(L2PcInstance player, ItemHolder... itemList)
  3315. {
  3316. if ((itemList == null) || (itemList.length == 0))
  3317. {
  3318. return false;
  3319. }
  3320. // first check if the player has all items to avoid taking half the items from the list
  3321. if (!hasAllItems(player, true, itemList))
  3322. {
  3323. return false;
  3324. }
  3325. for (ItemHolder item : itemList)
  3326. {
  3327. // this should never be false, but just in case
  3328. if (!takeItem(player, item))
  3329. {
  3330. return false;
  3331. }
  3332. }
  3333. return true;
  3334. }
  3335. /**
  3336. * Take an amount of all specified items from player's inventory.
  3337. * @param player the player whose items to take
  3338. * @param amount the amount to take of each item
  3339. * @param itemIds a list or an array of IDs of the items to take
  3340. * @return {@code true} if all items were taken, {@code false} otherwise
  3341. */
  3342. public static boolean takeItems(L2PcInstance player, int amount, int... itemIds)
  3343. {
  3344. boolean check = true;
  3345. if (itemIds != null)
  3346. {
  3347. for (int item : itemIds)
  3348. {
  3349. check &= takeItems(player, item, amount);
  3350. }
  3351. }
  3352. return check;
  3353. }
  3354. /**
  3355. * Remove all quest items associated with this quest from the specified player's inventory.
  3356. * @param player the player whose quest items to remove
  3357. */
  3358. public void removeRegisteredQuestItems(L2PcInstance player)
  3359. {
  3360. takeItems(player, -1, questItemIds);
  3361. }
  3362. /**
  3363. * Send a packet in order to play a sound to the player.
  3364. * @param player the player whom to send the packet
  3365. * @param sound the name of the sound to play
  3366. */
  3367. public static void playSound(L2PcInstance player, String sound)
  3368. {
  3369. player.sendPacket(QuestSound.getSound(sound));
  3370. }
  3371. /**
  3372. * Send a packet in order to play a sound to the player.
  3373. * @param player the player whom to send the packet
  3374. * @param sound the {@link QuestSound} object of the sound to play
  3375. */
  3376. public static void playSound(L2PcInstance player, QuestSound sound)
  3377. {
  3378. player.sendPacket(sound.getPacket());
  3379. }
  3380. /**
  3381. * Add EXP and SP as quest reward.
  3382. * @param player the player whom to reward with the EXP/SP
  3383. * @param exp the amount of EXP to give to the player
  3384. * @param sp the amount of SP to give to the player
  3385. */
  3386. public static void addExpAndSp(L2PcInstance player, long exp, int sp)
  3387. {
  3388. player.addExpAndSp((long) player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_QUEST_REWARD_XP, null, null), (int) player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_QUEST_REWARD_SP, null, null));
  3389. }
  3390. /**
  3391. * Get a random integer from 0 (inclusive) to {@code max} (exclusive).<br>
  3392. * Use this method instead of importing {@link com.l2jserver.util.Rnd} utility.
  3393. * @param max the maximum value for randomization
  3394. * @return a random integer number from 0 to {@code max - 1}
  3395. */
  3396. public static int getRandom(int max)
  3397. {
  3398. return Rnd.get(max);
  3399. }
  3400. /**
  3401. * Get a random integer from {@code min} (inclusive) to {@code max} (inclusive).<br>
  3402. * Use this method instead of importing {@link com.l2jserver.util.Rnd} utility.
  3403. * @param min the minimum value for randomization
  3404. * @param max the maximum value for randomization
  3405. * @return a random integer number from {@code min} to {@code max}
  3406. */
  3407. public static int getRandom(int min, int max)
  3408. {
  3409. return Rnd.get(min, max);
  3410. }
  3411. /**
  3412. * Get a random boolean.<br>
  3413. * Use this method instead of importing {@link com.l2jserver.util.Rnd} utility.
  3414. * @return {@code true} or {@code false} randomly
  3415. */
  3416. public static boolean getRandomBoolean()
  3417. {
  3418. return Rnd.nextBoolean();
  3419. }
  3420. /**
  3421. * Get the ID of the item equipped in the specified inventory slot of the player.
  3422. * @param player the player whose inventory to check
  3423. * @param slot the location in the player's inventory to check
  3424. * @return the ID of the item equipped in the specified inventory slot or 0 if the slot is empty or item is {@code null}.
  3425. */
  3426. public static int getItemEquipped(L2PcInstance player, int slot)
  3427. {
  3428. return player.getInventory().getPaperdollItemId(slot);
  3429. }
  3430. /**
  3431. * @return the number of ticks from the {@link com.l2jserver.gameserver.GameTimeController}.
  3432. */
  3433. public static int getGameTicks()
  3434. {
  3435. return GameTimeController.getInstance().getGameTicks();
  3436. }
  3437. /**
  3438. * Execute a procedure for each player depending on the parameters.
  3439. * @param player the player on which the procedure will be executed
  3440. * @param npc the related NPC
  3441. * @param isSummon {@code true} if the event that called this method was originated by the player's summon, {@code false} otherwise
  3442. * @param includeParty if {@code true}, #actionForEachPlayer(L2PcInstance, L2Npc, boolean) will be called with the player's party members
  3443. * @param includeCommandChannel if {@code true}, {@link #actionForEachPlayer(L2PcInstance, L2Npc, boolean)} will be called with the player's command channel members
  3444. * @see #actionForEachPlayer(L2PcInstance, L2Npc, boolean)
  3445. */
  3446. public final void executeForEachPlayer(L2PcInstance player, final L2Npc npc, final boolean isSummon, boolean includeParty, boolean includeCommandChannel)
  3447. {
  3448. if ((includeParty || includeCommandChannel) && player.isInParty())
  3449. {
  3450. if (includeCommandChannel && player.getParty().isInCommandChannel())
  3451. {
  3452. player.getParty().getCommandChannel().forEachMember(new IProcedure<L2PcInstance, Boolean>()
  3453. {
  3454. @Override
  3455. public Boolean execute(L2PcInstance member)
  3456. {
  3457. actionForEachPlayer(member, npc, isSummon);
  3458. return true;
  3459. }
  3460. });
  3461. }
  3462. else if (includeParty)
  3463. {
  3464. player.getParty().forEachMember(new IProcedure<L2PcInstance, Boolean>()
  3465. {
  3466. @Override
  3467. public Boolean execute(L2PcInstance member)
  3468. {
  3469. actionForEachPlayer(member, npc, isSummon);
  3470. return true;
  3471. }
  3472. });
  3473. }
  3474. }
  3475. else
  3476. {
  3477. actionForEachPlayer(player, npc, isSummon);
  3478. }
  3479. }
  3480. /**
  3481. * Overridable method called from {@link #executeForEachPlayer(L2PcInstance, L2Npc, boolean, boolean, boolean)}
  3482. * @param player the player on which the action will be run
  3483. * @param npc the NPC related to this action
  3484. * @param isSummon {@code true} if the event that called this method was originated by the player's summon
  3485. */
  3486. public void actionForEachPlayer(L2PcInstance player, L2Npc npc, boolean isSummon)
  3487. {
  3488. // To be overridden in quest scripts.
  3489. }
  3490. /**
  3491. * Open a door if it is present on the instance and its not open.
  3492. * @param doorId the ID of the door to open
  3493. * @param instanceId the ID of the instance the door is in (0 if the door is not not inside an instance)
  3494. */
  3495. public void openDoor(int doorId, int instanceId)
  3496. {
  3497. final L2DoorInstance door = getDoor(doorId, instanceId);
  3498. if (door == null)
  3499. {
  3500. _log.log(Level.WARNING, getClass().getSimpleName() + ": called openDoor(" + doorId + ", " + instanceId + "); but door wasnt found!", new NullPointerException());
  3501. }
  3502. else if (!door.getOpen())
  3503. {
  3504. door.openMe();
  3505. }
  3506. }
  3507. /**
  3508. * Close a door if it is present in a specified the instance and its open.
  3509. * @param doorId the ID of the door to close
  3510. * @param instanceId the ID of the instance the door is in (0 if the door is not not inside an instance)
  3511. */
  3512. public void closeDoor(int doorId, int instanceId)
  3513. {
  3514. final L2DoorInstance door = getDoor(doorId, instanceId);
  3515. if (door == null)
  3516. {
  3517. _log.log(Level.WARNING, getClass().getSimpleName() + ": called closeDoor(" + doorId + ", " + instanceId + "); but door wasnt found!", new NullPointerException());
  3518. }
  3519. else if (door.getOpen())
  3520. {
  3521. door.closeMe();
  3522. }
  3523. }
  3524. /**
  3525. * Retrieve a door from an instance or the real world.
  3526. * @param doorId the ID of the door to get
  3527. * @param instanceId the ID of the instance the door is in (0 if the door is not not inside an instance)
  3528. * @return the found door or {@code null} if no door with that ID and instance ID was found
  3529. */
  3530. public L2DoorInstance getDoor(int doorId, int instanceId)
  3531. {
  3532. L2DoorInstance door = null;
  3533. if (instanceId <= 0)
  3534. {
  3535. door = DoorTable.getInstance().getDoor(doorId);
  3536. }
  3537. else
  3538. {
  3539. final Instance inst = InstanceManager.getInstance().getInstance(instanceId);
  3540. if (inst != null)
  3541. {
  3542. door = inst.getDoor(doorId);
  3543. }
  3544. }
  3545. return door;
  3546. }
  3547. /**
  3548. * Teleport a player into/out of an instance.
  3549. * @param player the player to teleport
  3550. * @param loc the {@link Location} object containing the destination coordinates
  3551. * @param instanceId the ID of the instance to teleport the player to (0 to teleport out of an instance)
  3552. */
  3553. public void teleportPlayer(L2PcInstance player, Location loc, int instanceId)
  3554. {
  3555. teleportPlayer(player, loc, instanceId, true);
  3556. }
  3557. /**
  3558. * Teleport a player into/out of an instance.
  3559. * @param player the player to teleport
  3560. * @param loc the {@link Location} object containing the destination coordinates
  3561. * @param instanceId the ID of the instance to teleport the player to (0 to teleport out of an instance)
  3562. * @param allowRandomOffset if {@code true}, will randomize the teleport coordinates by +/-Config.MAX_OFFSET_ON_TELEPORT
  3563. */
  3564. public void teleportPlayer(L2PcInstance player, Location loc, int instanceId, boolean allowRandomOffset)
  3565. {
  3566. loc.setInstanceId(instanceId);
  3567. player.teleToLocation(loc, allowRandomOffset);
  3568. }
  3569. /**
  3570. * Sends the special camera packet to the player.
  3571. * @param player the player
  3572. * @param creature the watched creature
  3573. * @param force
  3574. * @param angle1
  3575. * @param angle2
  3576. * @param time
  3577. * @param range
  3578. * @param duration
  3579. * @param relYaw
  3580. * @param relPitch
  3581. * @param isWide
  3582. * @param relAngle
  3583. */
  3584. public static final void specialCamera(L2PcInstance player, L2Character creature, int force, int angle1, int angle2, int time, int range, int duration, int relYaw, int relPitch, int isWide, int relAngle)
  3585. {
  3586. player.sendPacket(new SpecialCamera(creature, force, angle1, angle2, time, range, duration, relYaw, relPitch, isWide, relAngle));
  3587. }
  3588. /**
  3589. * Sends the special camera packet to the player.
  3590. * @param player
  3591. * @param creature
  3592. * @param force
  3593. * @param angle1
  3594. * @param angle2
  3595. * @param time
  3596. * @param duration
  3597. * @param relYaw
  3598. * @param relPitch
  3599. * @param isWide
  3600. * @param relAngle
  3601. */
  3602. public static final void specialCameraEx(L2PcInstance player, L2Character creature, int force, int angle1, int angle2, int time, int duration, int relYaw, int relPitch, int isWide, int relAngle)
  3603. {
  3604. player.sendPacket(new SpecialCamera(creature, player, force, angle1, angle2, time, duration, relYaw, relPitch, isWide, relAngle));
  3605. }
  3606. /**
  3607. * Sends the special camera packet to the player.
  3608. * @param player
  3609. * @param creature
  3610. * @param force
  3611. * @param angle1
  3612. * @param angle2
  3613. * @param time
  3614. * @param range
  3615. * @param duration
  3616. * @param relYaw
  3617. * @param relPitch
  3618. * @param isWide
  3619. * @param relAngle
  3620. * @param unk
  3621. */
  3622. public static final void specialCamera3(L2PcInstance player, L2Character creature, int force, int angle1, int angle2, int time, int range, int duration, int relYaw, int relPitch, int isWide, int relAngle, int unk)
  3623. {
  3624. player.sendPacket(new SpecialCamera(creature, force, angle1, angle2, time, range, duration, relYaw, relPitch, isWide, relAngle, unk));
  3625. }
  3626. }