Quest.java 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200
  1. /*
  2. * This program is free software: you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation, either version 3 of the License, or (at your option) any later
  5. * version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but WITHOUT
  8. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10. * details.
  11. *
  12. * You should have received a copy of the GNU General Public License along with
  13. * this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.l2jserver.gameserver.model.quest;
  16. import java.sql.Connection;
  17. import java.sql.PreparedStatement;
  18. import java.sql.ResultSet;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.concurrent.locks.ReentrantReadWriteLock;
  24. import java.util.logging.Level;
  25. import java.util.logging.Logger;
  26. import javolution.util.FastList;
  27. import javolution.util.FastMap;
  28. import com.l2jserver.Config;
  29. import com.l2jserver.L2DatabaseFactory;
  30. import com.l2jserver.gameserver.GameTimeController;
  31. import com.l2jserver.gameserver.ThreadPoolManager;
  32. import com.l2jserver.gameserver.cache.HtmCache;
  33. import com.l2jserver.gameserver.datatables.ItemTable;
  34. import com.l2jserver.gameserver.datatables.NpcTable;
  35. import com.l2jserver.gameserver.idfactory.IdFactory;
  36. import com.l2jserver.gameserver.instancemanager.QuestManager;
  37. import com.l2jserver.gameserver.instancemanager.ZoneManager;
  38. import com.l2jserver.gameserver.model.L2DropData;
  39. import com.l2jserver.gameserver.model.L2Object;
  40. import com.l2jserver.gameserver.model.L2Party;
  41. import com.l2jserver.gameserver.model.L2Spawn;
  42. import com.l2jserver.gameserver.model.Location;
  43. import com.l2jserver.gameserver.model.actor.L2Character;
  44. import com.l2jserver.gameserver.model.actor.L2Npc;
  45. import com.l2jserver.gameserver.model.actor.L2Trap;
  46. import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
  47. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  48. import com.l2jserver.gameserver.model.actor.instance.L2TrapInstance;
  49. import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate;
  50. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  51. import com.l2jserver.gameserver.model.items.L2Item;
  52. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  53. import com.l2jserver.gameserver.model.olympiad.CompetitionType;
  54. import com.l2jserver.gameserver.model.skills.L2Skill;
  55. import com.l2jserver.gameserver.model.stats.Stats;
  56. import com.l2jserver.gameserver.model.zone.L2ZoneType;
  57. import com.l2jserver.gameserver.network.SystemMessageId;
  58. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  59. import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
  60. import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
  61. import com.l2jserver.gameserver.network.serverpackets.NpcQuestHtmlMessage;
  62. import com.l2jserver.gameserver.network.serverpackets.PlaySound;
  63. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  64. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  65. import com.l2jserver.gameserver.scripting.ManagedScript;
  66. import com.l2jserver.gameserver.scripting.ScriptManager;
  67. import com.l2jserver.gameserver.util.MinionList;
  68. import com.l2jserver.util.Rnd;
  69. import com.l2jserver.util.Util;
  70. /**
  71. * @author Luis Arias
  72. */
  73. public class Quest extends ManagedScript
  74. {
  75. protected static final Logger _log = Logger.getLogger(Quest.class.getName());
  76. /**
  77. * HashMap containing events from String value of the event.
  78. */
  79. private static Map<String, Quest> _allEventsS = new FastMap<String, Quest>();
  80. /**
  81. * HashMap containing lists of timers from the name of the timer.
  82. */
  83. private final Map<String, FastList<QuestTimer>> _allEventTimers = new FastMap<String, FastList<QuestTimer>>().shared();
  84. private final List<Integer> _questInvolvedNpcs = new ArrayList<>();
  85. private final ReentrantReadWriteLock _rwLock = new ReentrantReadWriteLock();
  86. private final int _questId;
  87. private final String _name;
  88. private final String _descr;
  89. private final byte _initialState = State.CREATED;
  90. protected boolean _onEnterWorld = false;
  91. private boolean _isCustom = false;
  92. private boolean _isOlympiadUse = false;
  93. /**
  94. * <b>Note: questItemIds will be overridden by child classes.</b><br>
  95. * Ideally, it should be protected instead of public.<br>
  96. * However, quest scripts written in Jython will have trouble with protected, as Jython only knows private and public...<br>
  97. * In fact, protected will typically be considered private thus breaking the scripts.<br>
  98. * Leave this as public as a workaround.
  99. */
  100. public int[] questItemIds = null;
  101. 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>";
  102. private static final String DEFAULT_ALREADY_COMPLETED_MSG = "<html><body>This quest has already been completed.</body></html>";
  103. private static final int RESET_HOUR = 6;
  104. private static final int RESET_MINUTES = 30;
  105. /**
  106. * @return the reset hour for a daily quest, could be overridden on a script.
  107. */
  108. public int getResetHour()
  109. {
  110. return RESET_HOUR;
  111. }
  112. /**
  113. * @return the reset minutes for a daily quest, could be overridden on a script.
  114. */
  115. public int getResetMinutes()
  116. {
  117. return RESET_MINUTES;
  118. }
  119. /**
  120. * @return a collection of the values contained in the {@link #_allEventsS}.
  121. */
  122. public static Collection<Quest> findAllEvents()
  123. {
  124. return _allEventsS.values();
  125. }
  126. /**
  127. * The Quest object constructor.<br>
  128. * Constructing a quest also calls the {@code init_LoadGlobalData} convenience method.
  129. * @param questId int pointing out the ID of the quest.
  130. * @param name String corresponding to the name of the quest.
  131. * @param descr String for the description of the quest.
  132. */
  133. public Quest(int questId, String name, String descr)
  134. {
  135. _questId = questId;
  136. _name = name;
  137. _descr = descr;
  138. if (questId != 0)
  139. {
  140. QuestManager.getInstance().addQuest(this);
  141. }
  142. else
  143. {
  144. _allEventsS.put(name, this);
  145. }
  146. init_LoadGlobalData();
  147. }
  148. /**
  149. * The function init_LoadGlobalData is, by default, called by the constructor of all quests.<br>
  150. * Children of this class can implement this function in order to define what variables to load and what structures to save them in.<br>
  151. * By default, nothing is loaded.<br>
  152. */
  153. protected void init_LoadGlobalData()
  154. {
  155. }
  156. /**
  157. * The function saveGlobalData is, by default, called at shutdown, for all quests, by the QuestManager.<br>
  158. * Children of this class can implement this function in order to convert their structures<br>
  159. * into <var, value> tuples and make calls to save them to the database, if needed.<br>
  160. * By default, nothing is saved.
  161. */
  162. public void saveGlobalData()
  163. {
  164. }
  165. /**
  166. * Trap actions:<br>
  167. * <ul>
  168. * <li>Triggered</li>
  169. * <li>Detected</li>
  170. * <li>Disarmed</li>
  171. * </ul>
  172. */
  173. public static enum TrapAction
  174. {
  175. TRAP_TRIGGERED,
  176. TRAP_DETECTED,
  177. TRAP_DISARMED
  178. }
  179. public static enum QuestEventType
  180. {
  181. ON_FIRST_TALK(false), // control the first dialog shown by NPCs when they are clicked (some quests must override the default npc action)
  182. QUEST_START(true), // onTalk action from start npcs
  183. ON_TALK(true), // onTalk action from npcs participating in a quest
  184. ON_ATTACK(true), // onAttack action triggered when a mob gets attacked by someone
  185. ON_KILL(true), // onKill action triggered when a mob gets killed.
  186. ON_SPAWN(true), // onSpawn action triggered when an NPC is spawned or respawned.
  187. ON_SKILL_SEE(true), // NPC or Mob saw a person casting a skill (regardless what the target is).
  188. ON_FACTION_CALL(true), // NPC or Mob saw a person casting a skill (regardless what the target is).
  189. ON_AGGRO_RANGE_ENTER(true), // a person came within the Npc/Mob's range
  190. ON_SPELL_FINISHED(true), // on spell finished action when npc finish casting skill
  191. ON_SKILL_LEARN(false), // control the AcquireSkill dialog from quest script
  192. ON_ENTER_ZONE(true), // on zone enter
  193. ON_EXIT_ZONE(true), // on zone exit
  194. ON_TRAP_ACTION(true), // on zone exit
  195. ON_ITEM_USE(true);
  196. // control whether this event type is allowed for the same npc template in multiple quests
  197. // or if the npc must be registered in at most one quest for the specified event
  198. private boolean _allowMultipleRegistration;
  199. QuestEventType(boolean allowMultipleRegistration)
  200. {
  201. _allowMultipleRegistration = allowMultipleRegistration;
  202. }
  203. public boolean isMultipleRegistrationAllowed()
  204. {
  205. return _allowMultipleRegistration;
  206. }
  207. }
  208. /**
  209. * @return the Id of the quest.
  210. */
  211. public int getQuestIntId()
  212. {
  213. return _questId;
  214. }
  215. /**
  216. * Add a new quest state of this quest to the database.
  217. * @param player the owner of the newly created quest state.
  218. * @return the newly created quest state object.
  219. */
  220. public QuestState newQuestState(L2PcInstance player)
  221. {
  222. return new QuestState(this, player, getInitialState());
  223. }
  224. /**
  225. * @return the initial state of the quest.
  226. */
  227. public byte getInitialState()
  228. {
  229. return _initialState;
  230. }
  231. /**
  232. * @return the name of the quest.
  233. */
  234. public String getName()
  235. {
  236. return _name;
  237. }
  238. /**
  239. * @return the description of the quest.
  240. */
  241. public String getDescr()
  242. {
  243. return _descr;
  244. }
  245. /**
  246. * Add a timer to the quest (if it doesn't exist already) and start it.
  247. * @param name the name of the timer (also passed back as "event" in {@link #onAdvEvent(String, L2Npc, L2PcInstance)}).
  248. * @param time the time in ms for when to fire the timer.
  249. * @param npc the npc associated with this timer (can be null).
  250. * @param player player associated with this timer (can be null).
  251. * @see #startQuestTimer(String, long, L2Npc, L2PcInstance, boolean)
  252. */
  253. public void startQuestTimer(String name, long time, L2Npc npc, L2PcInstance player)
  254. {
  255. startQuestTimer(name, time, npc, player, false);
  256. }
  257. /**
  258. * Add a timer to the quest (if it doesn't exist already) and start it.
  259. * @param name the name of the timer (also passed back as "event" in onAdvEvent)
  260. * @param time the time in ms for when to fire the timer
  261. * @param npc the npc associated with this timer (can be null)
  262. * @param player the player associated with this timer (can be null)
  263. * @param repeating indicates if the timer is repeatable or one-time.<br>
  264. * If {@code true}, it will auto-fire automatically, at a fixed rate, until explicitly canceled.
  265. */
  266. public void startQuestTimer(String name, long time, L2Npc npc, L2PcInstance player, boolean repeating)
  267. {
  268. FastList<QuestTimer> timers = getQuestTimers(name);
  269. // Add quest timer if timer doesn't already exist
  270. if (timers == null)
  271. {
  272. timers = new FastList<QuestTimer>();
  273. timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  274. _allEventTimers.put(name, timers);
  275. }
  276. // a timer with this name exists, but may not be for the same set of npc and player
  277. else
  278. {
  279. // if there exists a timer with this name, allow the timer only if the [npc, player] set is unique
  280. // nulls act as wildcards
  281. if (getQuestTimer(name, npc, player) == null)
  282. {
  283. try
  284. {
  285. _rwLock.writeLock().lock();
  286. timers.add(new QuestTimer(this, name, time, npc, player, repeating));
  287. }
  288. finally
  289. {
  290. _rwLock.writeLock().unlock();
  291. }
  292. }
  293. }
  294. }
  295. /**
  296. * Get a quest timer that matches the provided name and parameters.
  297. * @param name the name of the quest timer to get.
  298. * @param npc the NPC associated with the quest timer to get.
  299. * @param player the player associated with the quest timer to get.
  300. * @return the quest timer that matches the parameters of this function or {@code null} if nothing was found.
  301. */
  302. public QuestTimer getQuestTimer(String name, L2Npc npc, L2PcInstance player)
  303. {
  304. final FastList<QuestTimer> qt = getQuestTimers(name);
  305. if ((qt == null) || qt.isEmpty())
  306. {
  307. return null;
  308. }
  309. try
  310. {
  311. _rwLock.readLock().lock();
  312. for (QuestTimer timer : qt)
  313. {
  314. if (timer != null)
  315. {
  316. if (timer.isMatch(this, name, npc, player))
  317. {
  318. return timer;
  319. }
  320. }
  321. }
  322. }
  323. finally
  324. {
  325. _rwLock.readLock().unlock();
  326. }
  327. return null;
  328. }
  329. /**
  330. * Get all quest timers with the specified name.
  331. * @param name the name of the quest timers to get.
  332. * @return a list of all quest timers matching the given name or {@code null} if none was found.
  333. */
  334. private FastList<QuestTimer> getQuestTimers(String name)
  335. {
  336. return _allEventTimers.get(name);
  337. }
  338. /**
  339. * Cancel all quest timers with the specified name.
  340. * @param name the name of the quest timers to cancel.
  341. */
  342. public void cancelQuestTimers(String name)
  343. {
  344. FastList<QuestTimer> timers = getQuestTimers(name);
  345. if (timers == null)
  346. {
  347. return;
  348. }
  349. try
  350. {
  351. _rwLock.writeLock().lock();
  352. for (QuestTimer timer : timers)
  353. {
  354. if (timer != null)
  355. {
  356. timer.cancel();
  357. }
  358. }
  359. }
  360. finally
  361. {
  362. _rwLock.writeLock().unlock();
  363. }
  364. }
  365. /**
  366. * Cancel the quest timer that matches the specified name and parameters.
  367. * @param name the name of the quest timer to cancel.
  368. * @param npc the NPC associated with the quest timer to cancel.
  369. * @param player the player associated with the quest timer to cancel.
  370. */
  371. public void cancelQuestTimer(String name, L2Npc npc, L2PcInstance player)
  372. {
  373. QuestTimer timer = getQuestTimer(name, npc, player);
  374. if (timer != null)
  375. {
  376. timer.cancel();
  377. }
  378. }
  379. /**
  380. * Remove a quest timer from the list of all timers.<br>
  381. * Note: does not stop the timer itself!
  382. * @param timer the quest timer object to remove.
  383. */
  384. public void removeQuestTimer(QuestTimer timer)
  385. {
  386. if (timer == null)
  387. {
  388. return;
  389. }
  390. final FastList<QuestTimer> timers = getQuestTimers(timer.getName());
  391. if (timers == null)
  392. {
  393. return;
  394. }
  395. try
  396. {
  397. _rwLock.writeLock().lock();
  398. timers.remove(timer);
  399. }
  400. finally
  401. {
  402. _rwLock.writeLock().unlock();
  403. }
  404. }
  405. // These are methods to call within the core to call the quest events.
  406. /**
  407. * @param npc the NPC that was attacked.
  408. * @param attacker the attacking player.
  409. * @param damage the damage dealt to the NPC by the player.
  410. * @param isPet if {@code true}, the attack was actually made by the player's pet.
  411. * @param skill the skill used to attack the NPC (can be null).
  412. * @return
  413. */
  414. public final boolean notifyAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet, L2Skill skill)
  415. {
  416. String res = null;
  417. try
  418. {
  419. res = onAttack(npc, attacker, damage, isPet, skill);
  420. }
  421. catch (Exception e)
  422. {
  423. return showError(attacker, e);
  424. }
  425. return showResult(attacker, res);
  426. }
  427. /**
  428. * @param killer the character that killed the victim.
  429. * @param victim the character that was killed by the killer.
  430. * @param qs the quest state object of the player to be notified of this event.
  431. * @return {@code false} if there is an error or a message sent, {@code true} otherwise.
  432. */
  433. public final boolean notifyDeath(L2Character killer, L2Character victim, QuestState qs)
  434. {
  435. String res = null;
  436. try
  437. {
  438. res = onDeath(killer, victim, qs);
  439. }
  440. catch (Exception e)
  441. {
  442. return showError(qs.getPlayer(), e);
  443. }
  444. return showResult(qs.getPlayer(), res);
  445. }
  446. /**
  447. * @param item
  448. * @param player
  449. * @return
  450. */
  451. public final boolean notifyItemUse(L2Item item, L2PcInstance player)
  452. {
  453. String res = null;
  454. try
  455. {
  456. res = onItemUse(item, player);
  457. }
  458. catch (Exception e)
  459. {
  460. return showError(player, e);
  461. }
  462. return showResult(player, res);
  463. }
  464. /**
  465. * @param instance
  466. * @param player
  467. * @param skill
  468. * @return
  469. */
  470. public final boolean notifySpellFinished(L2Npc instance, L2PcInstance player, L2Skill skill)
  471. {
  472. String res = null;
  473. try
  474. {
  475. res = onSpellFinished(instance, player, skill);
  476. }
  477. catch (Exception e)
  478. {
  479. return showError(player, e);
  480. }
  481. return showResult(player, res);
  482. }
  483. /**
  484. * Notify quest script when something happens with a trap.
  485. * @param trap the trap instance which triggers the notification.
  486. * @param trigger the character which makes effect on the trap.
  487. * @param action 0: trap casting its skill. 1: trigger detects the trap. 2: trigger removes the trap.
  488. * @return {@code false} if the event was triggered successfully, {@code true} otherwise.
  489. */
  490. public final boolean notifyTrapAction(L2Trap trap, L2Character trigger, TrapAction action)
  491. {
  492. String res = null;
  493. try
  494. {
  495. res = onTrapAction(trap, trigger, action);
  496. }
  497. catch (Exception e)
  498. {
  499. if (trigger.getActingPlayer() != null)
  500. {
  501. return showError(trigger.getActingPlayer(), e);
  502. }
  503. _log.log(Level.WARNING, "Exception on onTrapAction() in notifyTrapAction(): " + e.getMessage(), e);
  504. return true;
  505. }
  506. if (trigger.getActingPlayer() != null)
  507. {
  508. return showResult(trigger.getActingPlayer(), res);
  509. }
  510. return false;
  511. }
  512. /**
  513. * @param npc
  514. * @return
  515. */
  516. public final boolean notifySpawn(L2Npc npc)
  517. {
  518. try
  519. {
  520. onSpawn(npc);
  521. }
  522. catch (Exception e)
  523. {
  524. _log.log(Level.WARNING, "Exception on onSpawn() in notifySpawn(): " + e.getMessage(), e);
  525. return true;
  526. }
  527. return false;
  528. }
  529. /**
  530. * @param event
  531. * @param npc
  532. * @param player
  533. * @return
  534. */
  535. public final boolean notifyEvent(String event, L2Npc npc, L2PcInstance player)
  536. {
  537. String res = null;
  538. try
  539. {
  540. res = onAdvEvent(event, npc, player);
  541. }
  542. catch (Exception e)
  543. {
  544. return showError(player, e);
  545. }
  546. return showResult(player, res);
  547. }
  548. /**
  549. * @param player
  550. * @return
  551. */
  552. public final boolean notifyEnterWorld(L2PcInstance player)
  553. {
  554. String res = null;
  555. try
  556. {
  557. res = onEnterWorld(player);
  558. }
  559. catch (Exception e)
  560. {
  561. return showError(player, e);
  562. }
  563. return showResult(player, res);
  564. }
  565. /**
  566. * @param npc
  567. * @param killer
  568. * @param isPet
  569. * @return
  570. */
  571. public final boolean notifyKill(L2Npc npc, L2PcInstance killer, boolean isPet)
  572. {
  573. String res = null;
  574. try
  575. {
  576. res = onKill(npc, killer, isPet);
  577. }
  578. catch (Exception e)
  579. {
  580. return showError(killer, e);
  581. }
  582. return showResult(killer, res);
  583. }
  584. /**
  585. * @param npc
  586. * @param qs
  587. * @return
  588. */
  589. public final boolean notifyTalk(L2Npc npc, QuestState qs)
  590. {
  591. String res = null;
  592. try
  593. {
  594. res = onTalk(npc, qs.getPlayer());
  595. }
  596. catch (Exception e)
  597. {
  598. return showError(qs.getPlayer(), e);
  599. }
  600. qs.getPlayer().setLastQuestNpcObject(npc.getObjectId());
  601. return showResult(qs.getPlayer(), res);
  602. }
  603. /**
  604. * Override the default NPC dialogs when a quest defines this for the given NPC.
  605. * @param npc the NPC whose dialogs to override.
  606. * @param player the player talking to the NPC.
  607. * @return {@code true} if the event was triggered successfully, {@code false} otherwise.
  608. */
  609. public final boolean notifyFirstTalk(L2Npc npc, L2PcInstance player)
  610. {
  611. String res = null;
  612. try
  613. {
  614. res = onFirstTalk(npc, player);
  615. }
  616. catch (Exception e)
  617. {
  618. return showError(player, e);
  619. }
  620. // if the quest returns text to display, display it.
  621. if ((res != null) && (res.length() > 0))
  622. {
  623. return showResult(player, res);
  624. }
  625. // else tell the player that
  626. player.sendPacket(ActionFailed.STATIC_PACKET);
  627. // note: if the default html for this npc needs to be shown, onFirstTalk should
  628. // call npc.showChatWindow(player) and then return null.
  629. return true;
  630. }
  631. /**
  632. * @param npc
  633. * @param player
  634. * @return
  635. */
  636. public final boolean notifyAcquireSkillList(L2Npc npc, L2PcInstance player)
  637. {
  638. String res = null;
  639. try
  640. {
  641. res = onAcquireSkillList(npc, player);
  642. }
  643. catch (Exception e)
  644. {
  645. return showError(player, e);
  646. }
  647. return showResult(player, res);
  648. }
  649. /**
  650. * @param npc
  651. * @param player
  652. * @param skill
  653. * @return
  654. */
  655. public final boolean notifyAcquireSkillInfo(L2Npc npc, L2PcInstance player, L2Skill skill)
  656. {
  657. String res = null;
  658. try
  659. {
  660. res = onAcquireSkillInfo(npc, player, skill);
  661. }
  662. catch (Exception e)
  663. {
  664. return showError(player, e);
  665. }
  666. return showResult(player, res);
  667. }
  668. /**
  669. * @param npc
  670. * @param player
  671. * @param skill
  672. * @return
  673. */
  674. public final boolean notifyAcquireSkill(L2Npc npc, L2PcInstance player, L2Skill skill)
  675. {
  676. String res = null;
  677. try
  678. {
  679. res = onAcquireSkill(npc, player, skill);
  680. if (res == "true")
  681. {
  682. return true;
  683. }
  684. else if (res == "false")
  685. {
  686. return false;
  687. }
  688. }
  689. catch (Exception e)
  690. {
  691. return showError(player, e);
  692. }
  693. return showResult(player, res);
  694. }
  695. public class TmpOnSkillSee implements Runnable
  696. {
  697. private final L2Npc _npc;
  698. private final L2PcInstance _caster;
  699. private final L2Skill _skill;
  700. private final L2Object[] _targets;
  701. private final boolean _isPet;
  702. public TmpOnSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
  703. {
  704. _npc = npc;
  705. _caster = caster;
  706. _skill = skill;
  707. _targets = targets;
  708. _isPet = isPet;
  709. }
  710. @Override
  711. public void run()
  712. {
  713. String res = null;
  714. try
  715. {
  716. res = onSkillSee(_npc, _caster, _skill, _targets, _isPet);
  717. }
  718. catch (Exception e)
  719. {
  720. showError(_caster, e);
  721. }
  722. showResult(_caster, res);
  723. }
  724. }
  725. /**
  726. * @param npc
  727. * @param caster
  728. * @param skill
  729. * @param targets
  730. * @param isPet
  731. * @return
  732. */
  733. public final boolean notifySkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
  734. {
  735. ThreadPoolManager.getInstance().executeAi(new TmpOnSkillSee(npc, caster, skill, targets, isPet));
  736. return true;
  737. }
  738. /**
  739. * @param npc
  740. * @param caller
  741. * @param attacker
  742. * @param isPet
  743. * @return
  744. */
  745. public final boolean notifyFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet)
  746. {
  747. String res = null;
  748. try
  749. {
  750. res = onFactionCall(npc, caller, attacker, isPet);
  751. }
  752. catch (Exception e)
  753. {
  754. return showError(attacker, e);
  755. }
  756. return showResult(attacker, res);
  757. }
  758. public class TmpOnAggroEnter implements Runnable
  759. {
  760. private final L2Npc _npc;
  761. private final L2PcInstance _pc;
  762. private final boolean _isPet;
  763. public TmpOnAggroEnter(L2Npc npc, L2PcInstance pc, boolean isPet)
  764. {
  765. _npc = npc;
  766. _pc = pc;
  767. _isPet = isPet;
  768. }
  769. @Override
  770. public void run()
  771. {
  772. String res = null;
  773. try
  774. {
  775. res = onAggroRangeEnter(_npc, _pc, _isPet);
  776. }
  777. catch (Exception e)
  778. {
  779. showError(_pc, e);
  780. }
  781. showResult(_pc, res);
  782. }
  783. }
  784. /**
  785. * @param npc
  786. * @param player
  787. * @param isPet
  788. * @return
  789. */
  790. public final boolean notifyAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isPet)
  791. {
  792. ThreadPoolManager.getInstance().executeAi(new TmpOnAggroEnter(npc, player, isPet));
  793. return true;
  794. }
  795. /**
  796. * @param character
  797. * @param zone
  798. * @return
  799. */
  800. public final boolean notifyEnterZone(L2Character character, L2ZoneType zone)
  801. {
  802. L2PcInstance player = character.getActingPlayer();
  803. String res = null;
  804. try
  805. {
  806. res = onEnterZone(character, zone);
  807. }
  808. catch (Exception e)
  809. {
  810. if (player != null)
  811. {
  812. return showError(player, e);
  813. }
  814. }
  815. if (player != null)
  816. {
  817. return showResult(player, res);
  818. }
  819. return true;
  820. }
  821. /**
  822. * @param character
  823. * @param zone
  824. * @return
  825. */
  826. public final boolean notifyExitZone(L2Character character, L2ZoneType zone)
  827. {
  828. L2PcInstance player = character.getActingPlayer();
  829. String res = null;
  830. try
  831. {
  832. res = onExitZone(character, zone);
  833. }
  834. catch (Exception e)
  835. {
  836. if (player != null)
  837. {
  838. return showError(player, e);
  839. }
  840. }
  841. if (player != null)
  842. {
  843. return showResult(player, res);
  844. }
  845. return true;
  846. }
  847. /**
  848. * @param winner
  849. * @param type
  850. */
  851. public final void notifyOlympiadWin(L2PcInstance winner, CompetitionType type)
  852. {
  853. try
  854. {
  855. onOlympiadWin(winner, type);
  856. }
  857. catch (Exception e)
  858. {
  859. showError(winner, e);
  860. }
  861. }
  862. /**
  863. * @param loser
  864. * @param type
  865. */
  866. public final void notifyOlympiadLose(L2PcInstance loser, CompetitionType type)
  867. {
  868. try
  869. {
  870. onOlympiadLose(loser, type);
  871. }
  872. catch (Exception e)
  873. {
  874. showError(loser, e);
  875. }
  876. }
  877. // These are methods that java calls to invoke scripts.
  878. /**
  879. * This function is called in place of {@link #onAttack(L2Npc, L2PcInstance, int, boolean, L2Skill)} if the former is not implemented.<br>
  880. * 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.
  881. * @param npc this parameter contains a reference to the exact instance of the NPC that got attacked the NPC.
  882. * @param attacker this parameter contains a reference to the exact instance of the player who attacked.
  883. * @param damage this parameter represents the total damage that this attack has inflicted to the NPC.
  884. * @param isPet 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.
  885. * @return
  886. */
  887. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet)
  888. {
  889. return null;
  890. }
  891. /**
  892. * This function is called whenever a player attacks an NPC that is registered for the quest.<br>
  893. * 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>
  894. * @param npc this parameter contains a reference to the exact instance of the NPC that got attacked.
  895. * @param attacker this parameter contains a reference to the exact instance of the player who attacked the NPC.
  896. * @param damage this parameter represents the total damage that this attack has inflicted to the NPC.
  897. * @param isPet 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.
  898. * @param skill parameter is the skill that player used to attack NPC.
  899. * @return
  900. */
  901. public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isPet, L2Skill skill)
  902. {
  903. return onAttack(npc, attacker, damage, isPet);
  904. }
  905. /**
  906. * This function is called whenever an <b>exact instance</b> of a character who was previously registered for this event dies.<br>
  907. * 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.
  908. * @param killer this parameter contains a reference to the exact instance of the NPC that <b>killed</b> the character.
  909. * @param victim this parameter contains a reference to the exact instance of the character that got killed.
  910. * @param qs this parameter contains a reference to the QuestState of whomever was interested (waiting) for this kill.
  911. * @return
  912. */
  913. public String onDeath(L2Character killer, L2Character victim, QuestState qs)
  914. {
  915. if (killer instanceof L2Npc)
  916. {
  917. return onAdvEvent("", (L2Npc) killer, qs.getPlayer());
  918. }
  919. return onAdvEvent("", null, qs.getPlayer());
  920. }
  921. /**
  922. * This function is called whenever a player clicks on a link in a quest dialog and whenever a timer fires.<br>
  923. * If is not overridden by a subclass, then default to the returned value of the simpler (and older) {@link #onEvent(String, QuestState)} override.<br>
  924. * If the player has a quest state, use it as parameter in the next call, otherwise return null.
  925. * @param event this parameter contains a string identifier for the event.<br>
  926. * Generally, this string is passed directly via the link.<br>
  927. * For example:<br>
  928. * <code>
  929. * <a action="bypass -h Quest 626_ADarkTwilight 31517-01.htm">hello</a>
  930. * </code><br>
  931. * The above link sets the event variable to "31517-01.htm" for the quest 626_ADarkTwilight.<br>
  932. * In the case of timers, this will be the name of the timer.<br>
  933. * This parameter serves as a sort of identifier.
  934. * @param npc this parameter contains a reference to the instance of NPC associated with this event.<br>
  935. * This may be the NPC registered in a timer, or the NPC with whom a player is speaking, etc.<br>
  936. * This parameter may be <b>null</b> in certain circumstances.
  937. * @param player this parameter contains a reference to the player participating in this function.<br>
  938. * It may be the player speaking to the NPC, or the player who caused a timer to start (and owns that timer).<br>
  939. * This parameter may be <b>null</b> in certain circumstances.
  940. * @return the text returned by the event (may be {@code null}, a filename or just text).
  941. */
  942. public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
  943. {
  944. final QuestState qs = player.getQuestState(getName());
  945. if (qs != null)
  946. {
  947. return onEvent(event, qs);
  948. }
  949. return null;
  950. }
  951. /**
  952. * This function is called in place of {@link #onAdvEvent(String, L2Npc, L2PcInstance)} if the former is not implemented.<br>
  953. * 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.
  954. * @param event this parameter contains a string identifier for the event.<br>
  955. * Generally, this string is passed directly via the link.<br>
  956. * For example:<br>
  957. * <code>
  958. * <a action="bypass -h Quest 626_ADarkTwilight 31517-01.htm">hello</a>
  959. * </code><br>
  960. * The above link sets the event variable to "31517-01.htm" for the quest 626_ADarkTwilight.<br>
  961. * In the case of timers, this will be the name of the timer.<br>
  962. * This parameter serves as a sort of identifier.
  963. * @param qs this parameter contains a reference to the quest state of the player who used the link or started the timer.
  964. * @return the text returned by the event (may be {@code null}, a filename or just text).
  965. */
  966. public String onEvent(String event, QuestState qs)
  967. {
  968. return null;
  969. }
  970. /**
  971. * This function is called whenever a player kills a NPC that is registered for the quest.
  972. * @param npc this parameter contains a reference to the exact instance of the NPC that got killed.
  973. * @param killer this parameter contains a reference to the exact instance of the player who killed the NPC.
  974. * @param isPet 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.
  975. * @return the text returned by the event (may be {@code null}, a filename or just text).
  976. */
  977. public String onKill(L2Npc npc, L2PcInstance killer, boolean isPet)
  978. {
  979. return null;
  980. }
  981. /**
  982. * This function is called whenever a player clicks to the "Quest" link of an NPC that is registered for the quest.
  983. * @param npc this parameter contains a reference to the exact instance of the NPC that the player is talking with.
  984. * @param talker this parameter contains a reference to the exact instance of the player who is talking to the NPC.
  985. * @return the text returned by the event (may be {@code null}, a filename or just text).
  986. */
  987. public String onTalk(L2Npc npc, L2PcInstance talker)
  988. {
  989. return null;
  990. }
  991. /**
  992. * This function is called whenever a player talks to an NPC that is registered for the quest.<br>
  993. * That is, it is triggered from the very first click on the NPC, not via another dialog.<br>
  994. * <b>Note 1:</b><br>
  995. * Each NPC can be registered to at most one quest for triggering this function.<br>
  996. * In other words, the same one NPC cannot respond to an "onFirstTalk" request from two different quests.<br>
  997. * Attempting to register an NPC in two different quests for this function will result in one of the two registration being ignored.<br>
  998. * <b>Note 2:</b><br>
  999. * Since a Quest link isn't clicked in order to reach this, a quest state can be invalid within this function.<br>
  1000. * The coder of the script may need to create a new quest state (if necessary).<br>
  1001. * <b>Note 3:</b><br>
  1002. * 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>
  1003. * If you wish to show the default HTML, within onFirstTalk do npc.showChatWindow(player) and then return ""<br>
  1004. * @param npc this parameter contains a reference to the exact instance of the NPC that the player is talking with.
  1005. * @param player this parameter contains a reference to the exact instance of the player who is talking to the NPC.
  1006. * @return the text returned by the event (may be {@code null}, a filename or just text).
  1007. * @since <a href="http://trac.l2jserver.com/changeset/771">Jython AI support for "onFirstTalk"</a>
  1008. */
  1009. public String onFirstTalk(L2Npc npc, L2PcInstance player)
  1010. {
  1011. return null;
  1012. }
  1013. /**
  1014. * This function is called whenever a player request a skill list.<br>
  1015. * TODO: Cleanup or re-implement, since Skill Trees rework it's support was removed.
  1016. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill list.
  1017. * @param player this parameter contains a reference to the exact instance of the player who requested the skill list.
  1018. * @return
  1019. */
  1020. public String onAcquireSkillList(L2Npc npc, L2PcInstance player)
  1021. {
  1022. return null;
  1023. }
  1024. /**
  1025. * This function is called whenever a player request a skill info.<br>
  1026. * TODO: Cleanup or re-implement, since Skill Trees rework it's support was removed.
  1027. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill info.
  1028. * @param player this parameter contains a reference to the exact instance of the player who requested the skill info.
  1029. * @param skill this parameter contains a reference to the skill that the player requested its info.
  1030. * @return
  1031. */
  1032. public String onAcquireSkillInfo(L2Npc npc, L2PcInstance player, L2Skill skill)
  1033. {
  1034. return null;
  1035. }
  1036. /**
  1037. * This function is called whenever a player acquire a skill.<br>
  1038. * TODO: Cleanup or re-implement, since Skill Trees rework it's support was removed.
  1039. * @param npc this parameter contains a reference to the exact instance of the NPC that the player requested the skill.
  1040. * @param player this parameter contains a reference to the exact instance of the player who requested the skill.
  1041. * @param skill this parameter contains a reference to the skill that the player requested.
  1042. * @return
  1043. */
  1044. public String onAcquireSkill(L2Npc npc, L2PcInstance player, L2Skill skill)
  1045. {
  1046. return null;
  1047. }
  1048. /**
  1049. * This function is called whenever a player uses a quest item that has a quest events list<br>
  1050. * TODO: complete this documentation and unhardcode it to work with all item uses not with those listed.
  1051. * @param item this parameter contains a reference to the instance of the quest item that the player used.
  1052. * @param player this parameter contains a reference to the exact instance of the player who used the quest item.
  1053. * @return
  1054. */
  1055. public String onItemUse(L2Item item, L2PcInstance player)
  1056. {
  1057. return null;
  1058. }
  1059. /**
  1060. * This function is called whenever a player casts a skill near a registered NPC (1000 distance).<br>
  1061. * <b>Note:</b><br>
  1062. * If a skill does damage, both onSkillSee(..) and onAttack(..) will be triggered for the damaged NPC!<br>
  1063. * However, only onSkillSee(..) will be triggered if the skill does no damage,<br>
  1064. * or if it damages an NPC who has no onAttack(..) registration while near another NPC who has an onSkillSee registration.<br>
  1065. * TODO: confirm if the distance is 1000 and unhardcode.
  1066. * @param npc this parameter contains a reference to the exact instance of the NPC that saw the skill.
  1067. * @param caster this parameter references the actual instance of the player who cast the skill.
  1068. * @param skill this parameter is a reference to the actual skill that was used (from which info about the id and level of the skill can be obtained).
  1069. * @param targets this parameter is an array of all objects (can be any type of object, including mobs and players) that are affected by the skill.
  1070. * @param isPet this parameter if it's {@code false} it denotes that the caster was indeed the player, else it specifies that the caster was the player's pet.
  1071. * @return
  1072. */
  1073. public String onSkillSee(L2Npc npc, L2PcInstance caster, L2Skill skill, L2Object[] targets, boolean isPet)
  1074. {
  1075. return null;
  1076. }
  1077. /**
  1078. * This function is called whenever an NPC finishes casting a skill.
  1079. * @param npc this parameter contains a reference to the exact instance of the NPC that casted the skill.
  1080. * @param player this parameter references the actual instance of the player who is target of the skill. This parameter may be <b>null</b> in certain circumstances.
  1081. * @param skill this parameter is a reference to the actual skill that was used by the NPC.
  1082. * @return
  1083. */
  1084. public String onSpellFinished(L2Npc npc, L2PcInstance player, L2Skill skill)
  1085. {
  1086. return null;
  1087. }
  1088. /**
  1089. * This function is called whenever a trap action is performed.
  1090. * @param trap this parameter contains a reference to the exact instance of the trap that was activated.
  1091. * @param trigger this parameter contains a reference to the exact instance of the character that triggered the action.
  1092. * @param action this parameter contains a reference to the action that was triggered.
  1093. * @return
  1094. */
  1095. public String onTrapAction(L2Trap trap, L2Character trigger, TrapAction action)
  1096. {
  1097. return null;
  1098. }
  1099. /**
  1100. * This function is called whenever an NPC spawns or re-spawns and passes a reference to the newly (re)spawned NPC.<br>
  1101. * Currently the only function that has no reference to a player.<br>
  1102. * It is useful for initializations, starting quest timers, displaying chat (NpcSay), and more.
  1103. * @param npc this parameter contains a reference to the exact instance of the NPC who just (re)spawned.
  1104. * @return
  1105. */
  1106. public String onSpawn(L2Npc npc)
  1107. {
  1108. return null;
  1109. }
  1110. /**
  1111. * This function is called whenever an NPC is called by another NPC in the same faction.
  1112. * @param npc this parameter contains a reference to the exact instance of the NPC who is being asked for help.
  1113. * @param caller this parameter contains a reference to the exact instance of the NPC who is asking for help.<br>
  1114. * @param attacker this parameter contains a reference to the exact instance of the player who attacked.
  1115. * @param isPet 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 pet.
  1116. * @return
  1117. */
  1118. public String onFactionCall(L2Npc npc, L2Npc caller, L2PcInstance attacker, boolean isPet)
  1119. {
  1120. return null;
  1121. }
  1122. /**
  1123. * This function is called whenever a player enters an NPC aggression range.
  1124. * @param npc this parameter contains a reference to the exact instance of the NPC whose aggression range is being transgressed.
  1125. * @param player this parameter contains a reference to the exact instance of the player who is entering the NPC's aggression range.
  1126. * @param isPet 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 pet.
  1127. * @return
  1128. */
  1129. public String onAggroRangeEnter(L2Npc npc, L2PcInstance player, boolean isPet)
  1130. {
  1131. return null;
  1132. }
  1133. /**
  1134. * This function is called whenever a player enters the game.
  1135. * @param player this parameter contains a reference to the exact instance of the player who is entering to the world.
  1136. * @return
  1137. */
  1138. public String onEnterWorld(L2PcInstance player)
  1139. {
  1140. return null;
  1141. }
  1142. /**
  1143. * This function is called whenever a character enters a registered zone.
  1144. * @param character this parameter contains a reference to the exact instance of the character who is entering the zone.
  1145. * @param zone this parameter contains a reference to the zone.
  1146. * @return
  1147. */
  1148. public String onEnterZone(L2Character character, L2ZoneType zone)
  1149. {
  1150. return null;
  1151. }
  1152. /**
  1153. * This function is called whenever a character exits a registered zone.
  1154. * @param character this parameter contains a reference to the exact instance of the character who is exiting the zone.
  1155. * @param zone this parameter contains a reference to the zone.
  1156. * @return
  1157. */
  1158. public String onExitZone(L2Character character, L2ZoneType zone)
  1159. {
  1160. return null;
  1161. }
  1162. /**
  1163. * This function is called whenever a player wins an Olympiad Game.
  1164. * @param winner this parameter contains a reference to the exact instance of the player who won the competition.
  1165. * @param type this parameter contains a reference to the competition type.
  1166. */
  1167. public void onOlympiadWin(L2PcInstance winner, CompetitionType type)
  1168. {
  1169. }
  1170. /**
  1171. * This function is called whenever a player looses an Olympiad Game.
  1172. * @param loser this parameter contains a reference to the exact instance of the player who lose the competition.
  1173. * @param type this parameter contains a reference to the competition type.
  1174. */
  1175. public void onOlympiadLose(L2PcInstance loser, CompetitionType type)
  1176. {
  1177. }
  1178. /**
  1179. * Show message error to player who has an access level greater than 0.
  1180. * @param player the player to whom to send the error (must be a GM).
  1181. * @param t the throwable to get the message/stacktrace from.
  1182. * @return {@code false}
  1183. */
  1184. public boolean showError(L2PcInstance player, Throwable t)
  1185. {
  1186. _log.log(Level.WARNING, getScriptFile().getAbsolutePath(), t);
  1187. if (t.getMessage() == null)
  1188. {
  1189. _log.warning(getClass().getSimpleName() + ": " + t.getMessage());
  1190. }
  1191. if ((player != null) && player.getAccessLevel().isGm())
  1192. {
  1193. String res = "<html><body><title>Script error</title>" + Util.getStackTrace(t) + "</body></html>";
  1194. return showResult(player, res);
  1195. }
  1196. return false;
  1197. }
  1198. /**
  1199. * Show a message to the specified player.<br>
  1200. * <u><i>Concept:</i></u><br>
  1201. * Three cases are managed according to the value of the parameter "res":<br>
  1202. * <ul>
  1203. * <li>"res" ends with string ".html": an HTML is opened in order to be shown in a dialog box.</li>
  1204. * <li>"res" starts with "<html>": the message hold in "res" is shown in a dialog box.</li>
  1205. * <li>otherwise: the message held in "res" is shown in chat box.</li>
  1206. * </ul>
  1207. * @param player the player to whom to show the result.
  1208. * @param res the message to show to the player.
  1209. * @return {@code false} if the message was sent, {@code true} otherwise.
  1210. */
  1211. public boolean showResult(L2PcInstance player, String res)
  1212. {
  1213. if ((res == null) || res.isEmpty() || (player == null))
  1214. {
  1215. return true;
  1216. }
  1217. if (res.endsWith(".htm") || res.endsWith(".html"))
  1218. {
  1219. showHtmlFile(player, res);
  1220. }
  1221. else if (res.startsWith("<html>"))
  1222. {
  1223. NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
  1224. npcReply.setHtml(res);
  1225. npcReply.replace("%playername%", player.getName());
  1226. player.sendPacket(npcReply);
  1227. player.sendPacket(ActionFailed.STATIC_PACKET);
  1228. }
  1229. else
  1230. {
  1231. player.sendMessage(res);
  1232. }
  1233. return false;
  1234. }
  1235. /**
  1236. * Loads all quest states and variables for the specified player.
  1237. * @param player the player who is entering the world.
  1238. */
  1239. public final static void playerEnter(L2PcInstance player)
  1240. {
  1241. Connection con = null;
  1242. try
  1243. {
  1244. // Get list of quests owned by the player from database
  1245. con = L2DatabaseFactory.getInstance().getConnection();
  1246. PreparedStatement invalidQuestData = con.prepareStatement("DELETE FROM character_quests WHERE charId=? and name=?");
  1247. PreparedStatement invalidQuestDataVar = con.prepareStatement("delete FROM character_quests WHERE charId=? and name=? and var=?");
  1248. PreparedStatement statement = con.prepareStatement("SELECT name,value FROM character_quests WHERE charId=? AND var=?");
  1249. statement.setInt(1, player.getObjectId());
  1250. statement.setString(2, "<state>");
  1251. ResultSet rs = statement.executeQuery();
  1252. while (rs.next())
  1253. {
  1254. // Get ID of the quest and ID of its state
  1255. String questId = rs.getString("name");
  1256. String statename = rs.getString("value");
  1257. // Search quest associated with the ID
  1258. Quest q = QuestManager.getInstance().getQuest(questId);
  1259. if (q == null)
  1260. {
  1261. _log.finer("Unknown quest " + questId + " for player " + player.getName());
  1262. if (Config.AUTODELETE_INVALID_QUEST_DATA)
  1263. {
  1264. invalidQuestData.setInt(1, player.getObjectId());
  1265. invalidQuestData.setString(2, questId);
  1266. invalidQuestData.executeUpdate();
  1267. }
  1268. continue;
  1269. }
  1270. // Create a new QuestState for the player that will be added to the player's list of quests
  1271. new QuestState(q, player, State.getStateId(statename));
  1272. }
  1273. rs.close();
  1274. invalidQuestData.close();
  1275. statement.close();
  1276. // Get list of quests owned by the player from the DB in order to add variables used in the quest.
  1277. statement = con.prepareStatement("SELECT name,var,value FROM character_quests WHERE charId=? AND var<>?");
  1278. statement.setInt(1, player.getObjectId());
  1279. statement.setString(2, "<state>");
  1280. rs = statement.executeQuery();
  1281. while (rs.next())
  1282. {
  1283. String questId = rs.getString("name");
  1284. String var = rs.getString("var");
  1285. String value = rs.getString("value");
  1286. // Get the QuestState saved in the loop before
  1287. QuestState qs = player.getQuestState(questId);
  1288. if (qs == null)
  1289. {
  1290. _log.finer("Lost variable " + var + " in quest " + questId + " for player " + player.getName());
  1291. if (Config.AUTODELETE_INVALID_QUEST_DATA)
  1292. {
  1293. invalidQuestDataVar.setInt(1, player.getObjectId());
  1294. invalidQuestDataVar.setString(2, questId);
  1295. invalidQuestDataVar.setString(3, var);
  1296. invalidQuestDataVar.executeUpdate();
  1297. }
  1298. continue;
  1299. }
  1300. // Add parameter to the quest
  1301. qs.setInternal(var, value);
  1302. }
  1303. rs.close();
  1304. invalidQuestDataVar.close();
  1305. statement.close();
  1306. }
  1307. catch (Exception e)
  1308. {
  1309. _log.log(Level.WARNING, "could not insert char quest:", e);
  1310. }
  1311. finally
  1312. {
  1313. L2DatabaseFactory.close(con);
  1314. }
  1315. // events
  1316. for (String name : _allEventsS.keySet())
  1317. {
  1318. player.processQuestEvent(name, "enter");
  1319. }
  1320. }
  1321. /**
  1322. * Insert (or update) in the database variables that need to stay persistent for this quest after a reboot.<br>
  1323. * This function is for storage of values that do not related to a specific player but are global for all characters.<br>
  1324. * 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.
  1325. * @param var the name of the variable to save.
  1326. * @param value the value of the variable.
  1327. */
  1328. public final void saveGlobalQuestVar(String var, String value)
  1329. {
  1330. Connection con = null;
  1331. try
  1332. {
  1333. con = L2DatabaseFactory.getInstance().getConnection();
  1334. PreparedStatement statement = con.prepareStatement("REPLACE INTO quest_global_data (quest_name,var,value) VALUES (?,?,?)");
  1335. statement.setString(1, getName());
  1336. statement.setString(2, var);
  1337. statement.setString(3, value);
  1338. statement.executeUpdate();
  1339. statement.close();
  1340. }
  1341. catch (Exception e)
  1342. {
  1343. _log.log(Level.WARNING, "could not insert global quest variable:", e);
  1344. }
  1345. finally
  1346. {
  1347. L2DatabaseFactory.close(con);
  1348. }
  1349. }
  1350. /**
  1351. * Read from the database a previously saved variable for this quest.<br>
  1352. * Due to performance considerations, this function should best be used only when the quest is first loaded.<br>
  1353. * Subclasses of this class can define structures into which these loaded values can be saved.<br>
  1354. * However, on-demand usage of this function throughout the script is not prohibited, only not recommended.<br>
  1355. * Values read from this function were entered by calls to "saveGlobalQuestVar".
  1356. * @param var the name of the variable to load.
  1357. * @return the current value of the specified variable, or an empty string if the variable does not exist.
  1358. */
  1359. public final String loadGlobalQuestVar(String var)
  1360. {
  1361. String result = "";
  1362. Connection con = null;
  1363. try
  1364. {
  1365. con = L2DatabaseFactory.getInstance().getConnection();
  1366. PreparedStatement statement;
  1367. statement = con.prepareStatement("SELECT value FROM quest_global_data WHERE quest_name = ? AND var = ?");
  1368. statement.setString(1, getName());
  1369. statement.setString(2, var);
  1370. ResultSet rs = statement.executeQuery();
  1371. if (rs.first())
  1372. {
  1373. result = rs.getString(1);
  1374. }
  1375. rs.close();
  1376. statement.close();
  1377. }
  1378. catch (Exception e)
  1379. {
  1380. _log.log(Level.WARNING, "could not load global quest variable:", e);
  1381. }
  1382. finally
  1383. {
  1384. L2DatabaseFactory.close(con);
  1385. }
  1386. return result;
  1387. }
  1388. /**
  1389. * Permanently delete from the database a global quest variable that was previously saved for this quest.
  1390. * @param var the name of the variable to delete.
  1391. */
  1392. public final void deleteGlobalQuestVar(String var)
  1393. {
  1394. Connection con = null;
  1395. try
  1396. {
  1397. con = L2DatabaseFactory.getInstance().getConnection();
  1398. PreparedStatement statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ? AND var = ?");
  1399. statement.setString(1, getName());
  1400. statement.setString(2, var);
  1401. statement.executeUpdate();
  1402. statement.close();
  1403. }
  1404. catch (Exception e)
  1405. {
  1406. _log.log(Level.WARNING, "could not delete global quest variable:", e);
  1407. }
  1408. finally
  1409. {
  1410. L2DatabaseFactory.close(con);
  1411. }
  1412. }
  1413. /**
  1414. * Permanently delete from the database all global quest variables that were previously saved for this quest.
  1415. */
  1416. public final void deleteAllGlobalQuestVars()
  1417. {
  1418. Connection con = null;
  1419. try
  1420. {
  1421. con = L2DatabaseFactory.getInstance().getConnection();
  1422. PreparedStatement statement;
  1423. statement = con.prepareStatement("DELETE FROM quest_global_data WHERE quest_name = ?");
  1424. statement.setString(1, getName());
  1425. statement.executeUpdate();
  1426. statement.close();
  1427. }
  1428. catch (Exception e)
  1429. {
  1430. _log.log(Level.WARNING, "could not delete global quest variables:", e);
  1431. }
  1432. finally
  1433. {
  1434. L2DatabaseFactory.close(con);
  1435. }
  1436. }
  1437. /**
  1438. * Insert in the database the quest for the player.
  1439. * @param qs the quest state whose variable to insert.
  1440. * @param var the name of the variable.
  1441. * @param value the value of the variable.
  1442. */
  1443. public static void createQuestVarInDb(QuestState qs, String var, String value)
  1444. {
  1445. Connection con = null;
  1446. try
  1447. {
  1448. con = L2DatabaseFactory.getInstance().getConnection();
  1449. PreparedStatement statement = con.prepareStatement("INSERT INTO character_quests (charId,name,var,value) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE value=?");
  1450. statement.setInt(1, qs.getPlayer().getObjectId());
  1451. statement.setString(2, qs.getQuestName());
  1452. statement.setString(3, var);
  1453. statement.setString(4, value);
  1454. statement.setString(5, value);
  1455. statement.executeUpdate();
  1456. statement.close();
  1457. }
  1458. catch (Exception e)
  1459. {
  1460. _log.log(Level.WARNING, "could not insert char quest:", e);
  1461. }
  1462. finally
  1463. {
  1464. L2DatabaseFactory.close(con);
  1465. }
  1466. }
  1467. /**
  1468. * Update the value of the variable "var" for the specified quest in database.
  1469. * @param qs the quest state of the quest whose variable to update.
  1470. * @param var the name of the variable.
  1471. * @param value the value of the variable.
  1472. */
  1473. public static void updateQuestVarInDb(QuestState qs, String var, String value)
  1474. {
  1475. Connection con = null;
  1476. try
  1477. {
  1478. con = L2DatabaseFactory.getInstance().getConnection();
  1479. PreparedStatement statement = con.prepareStatement("UPDATE character_quests SET value=? WHERE charId=? AND name=? AND var = ?");
  1480. statement.setString(1, value);
  1481. statement.setInt(2, qs.getPlayer().getObjectId());
  1482. statement.setString(3, qs.getQuestName());
  1483. statement.setString(4, var);
  1484. statement.executeUpdate();
  1485. statement.close();
  1486. }
  1487. catch (Exception e)
  1488. {
  1489. _log.log(Level.WARNING, "could not update char quest:", e);
  1490. }
  1491. finally
  1492. {
  1493. L2DatabaseFactory.close(con);
  1494. }
  1495. }
  1496. /**
  1497. * Delete from the database all variables and states of the specified quest state.
  1498. * @param qs : object QuestState pointing out the player's quest
  1499. * @param var : String designating the variable characterizing the quest
  1500. */
  1501. public static void deleteQuestVarInDb(QuestState qs, String var)
  1502. {
  1503. Connection con = null;
  1504. try
  1505. {
  1506. con = L2DatabaseFactory.getInstance().getConnection();
  1507. PreparedStatement statement;
  1508. statement = con.prepareStatement("DELETE FROM character_quests WHERE charId=? AND name=? AND var=?");
  1509. statement.setInt(1, qs.getPlayer().getObjectId());
  1510. statement.setString(2, qs.getQuestName());
  1511. statement.setString(3, var);
  1512. statement.executeUpdate();
  1513. statement.close();
  1514. }
  1515. catch (Exception e)
  1516. {
  1517. _log.log(Level.WARNING, "could not delete char quest:", e);
  1518. }
  1519. finally
  1520. {
  1521. L2DatabaseFactory.close(con);
  1522. }
  1523. }
  1524. /**
  1525. * Delete the player's quest from database.
  1526. * @param qs : QuestState pointing out the player's quest
  1527. */
  1528. public static void deleteQuestInDb(QuestState qs)
  1529. {
  1530. Connection con = null;
  1531. try
  1532. {
  1533. con = L2DatabaseFactory.getInstance().getConnection();
  1534. PreparedStatement statement = con.prepareStatement("DELETE FROM character_quests WHERE charId=? AND name=?");
  1535. statement.setInt(1, qs.getPlayer().getObjectId());
  1536. statement.setString(2, qs.getQuestName());
  1537. statement.executeUpdate();
  1538. statement.close();
  1539. }
  1540. catch (Exception e)
  1541. {
  1542. _log.log(Level.WARNING, "could not delete char quest:", e);
  1543. }
  1544. finally
  1545. {
  1546. L2DatabaseFactory.close(con);
  1547. }
  1548. }
  1549. /**
  1550. * Create a record in database for quest.<br>
  1551. * Actions:<br>
  1552. * Use function createQuestVarInDb() with following parameters:<br>
  1553. * <ul>
  1554. * <li>QuestState : parameter qs that puts in fields of database:
  1555. * <ul type="square">
  1556. * <li>charId : ID of the player</li>
  1557. * <li>name : name of the quest</li>
  1558. * </ul>
  1559. * </li>
  1560. * <li>var : string "&lt;state&gt;" as the name of the variable for the quest</li>
  1561. * <li>val : string corresponding at the ID of the state (in fact, initial state)</li>
  1562. * </ul>
  1563. * @param qs : QuestState
  1564. */
  1565. public static void createQuestInDb(QuestState qs)
  1566. {
  1567. createQuestVarInDb(qs, "<state>", State.getStateName(qs.getState()));
  1568. }
  1569. /**
  1570. * Update informations regarding quest in database.<br>
  1571. * Actions:<br>
  1572. * <ul>
  1573. * <li>Get ID state of the quest recorded in object qs</li>
  1574. * <li>Test if quest is completed. If true, add a star (*) before the ID state</li>
  1575. * <li>Save in database the ID state (with or without the star) for the variable called "&lt;state&gt;" of the quest</li>
  1576. * </ul>
  1577. * @param qs : QuestState
  1578. */
  1579. public static void updateQuestInDb(QuestState qs)
  1580. {
  1581. String val = State.getStateName(qs.getState());
  1582. updateQuestVarInDb(qs, "<state>", val);
  1583. }
  1584. /**
  1585. * @param player the player whose language settings to use in finding the html of the right language.
  1586. * @return the default html for when no quest is available: "You are either not on a quest that involves this NPC..".
  1587. */
  1588. public static String getNoQuestMsg(L2PcInstance player)
  1589. {
  1590. final String result = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), "data/html/noquest.htm");
  1591. if ((result != null) && (result.length() > 0))
  1592. {
  1593. return result;
  1594. }
  1595. return DEFAULT_NO_QUEST_MSG;
  1596. }
  1597. /**
  1598. * @param player the player whose language settings to use in finding the html of the right language.
  1599. * @return the default html for when no quest is already completed: "This quest has already been completed.".
  1600. */
  1601. public static String getAlreadyCompletedMsg(L2PcInstance player)
  1602. {
  1603. final String result = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), "data/html/alreadycompleted.htm");
  1604. if ((result != null) && (result.length() > 0))
  1605. {
  1606. return result;
  1607. }
  1608. return DEFAULT_ALREADY_COMPLETED_MSG;
  1609. }
  1610. /**
  1611. * Add this quest to the list of quests that the passed mob will respond to for the specified Event type.
  1612. * @param npcId : id of the NPC to register
  1613. * @param eventType : type of event being registered
  1614. * @return L2NpcTemplate : Npc Template corresponding to the npcId, or null if the id is invalid
  1615. */
  1616. public L2NpcTemplate addEventId(int npcId, QuestEventType eventType)
  1617. {
  1618. try
  1619. {
  1620. L2NpcTemplate t = NpcTable.getInstance().getTemplate(npcId);
  1621. if (t != null)
  1622. {
  1623. t.addQuestEvent(eventType, this);
  1624. }
  1625. if (!_questInvolvedNpcs.contains(Integer.valueOf(npcId)))
  1626. {
  1627. _questInvolvedNpcs.add(npcId);
  1628. }
  1629. return t;
  1630. }
  1631. catch (Exception e)
  1632. {
  1633. _log.log(Level.WARNING, "Exception on addEventId(): " + e.getMessage(), e);
  1634. return null;
  1635. }
  1636. }
  1637. /**
  1638. * Add the quest to the NPC's startQuest
  1639. * @param npcIds
  1640. * @return L2NpcTemplate : Start NPC
  1641. */
  1642. public L2NpcTemplate[] addStartNpc(int... npcIds)
  1643. {
  1644. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1645. int i = 0;
  1646. for (int npcId : npcIds)
  1647. {
  1648. value[i++] = addEventId(npcId, QuestEventType.QUEST_START);
  1649. }
  1650. return value;
  1651. }
  1652. public L2NpcTemplate addStartNpc(int npcId)
  1653. {
  1654. return addEventId(npcId, QuestEventType.QUEST_START);
  1655. }
  1656. /**
  1657. * Add the quest to the NPC's first-talk (default action dialog)
  1658. * @param npcIds
  1659. * @return L2NpcTemplate : Start NPC
  1660. */
  1661. public L2NpcTemplate[] addFirstTalkId(int... npcIds)
  1662. {
  1663. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1664. int i = 0;
  1665. for (int npcId : npcIds)
  1666. {
  1667. value[i++] = addEventId(npcId, QuestEventType.ON_FIRST_TALK);
  1668. }
  1669. return value;
  1670. }
  1671. /**
  1672. * @param npcId
  1673. * @return
  1674. */
  1675. public L2NpcTemplate addFirstTalkId(int npcId)
  1676. {
  1677. return addEventId(npcId, QuestEventType.ON_FIRST_TALK);
  1678. }
  1679. /**
  1680. * Add the NPC to the AcquireSkill dialog
  1681. * @param npcIds
  1682. * @return L2NpcTemplate : NPC
  1683. */
  1684. public L2NpcTemplate[] addAcquireSkillId(int... npcIds)
  1685. {
  1686. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1687. int i = 0;
  1688. for (int npcId : npcIds)
  1689. {
  1690. value[i++] = addEventId(npcId, QuestEventType.ON_SKILL_LEARN);
  1691. }
  1692. return value;
  1693. }
  1694. /**
  1695. * @param npcId
  1696. * @return
  1697. */
  1698. public L2NpcTemplate addAcquireSkillId(int npcId)
  1699. {
  1700. return addEventId(npcId, QuestEventType.ON_SKILL_LEARN);
  1701. }
  1702. /**
  1703. * Add this quest to the list of quests that the passed mob will respond to for Attack Events.
  1704. * @param npcIds
  1705. * @return int : attackId
  1706. */
  1707. public L2NpcTemplate[] addAttackId(int... npcIds)
  1708. {
  1709. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1710. int i = 0;
  1711. for (int npcId : npcIds)
  1712. {
  1713. value[i++] = addEventId(npcId, QuestEventType.ON_ATTACK);
  1714. }
  1715. return value;
  1716. }
  1717. /**
  1718. * @param npcId
  1719. * @return
  1720. */
  1721. public L2NpcTemplate addAttackId(int npcId)
  1722. {
  1723. return addEventId(npcId, QuestEventType.ON_ATTACK);
  1724. }
  1725. /**
  1726. * Add this quest to the list of quests that the passed mob will respond to for Kill Events.
  1727. * @param killIds
  1728. * @return int : killId
  1729. */
  1730. public L2NpcTemplate[] addKillId(int... killIds)
  1731. {
  1732. L2NpcTemplate[] value = new L2NpcTemplate[killIds.length];
  1733. int i = 0;
  1734. for (int killId : killIds)
  1735. {
  1736. value[i++] = addEventId(killId, QuestEventType.ON_KILL);
  1737. }
  1738. return value;
  1739. }
  1740. /**
  1741. * @param npcId
  1742. * @return
  1743. */
  1744. public L2NpcTemplate addKillId(int npcId)
  1745. {
  1746. return addEventId(npcId, QuestEventType.ON_KILL);
  1747. }
  1748. /**
  1749. * Add this quest to the list of quests that the passed npc will respond to for Talk Events.
  1750. * @param talkIds : ID of the NPC
  1751. * @return int : ID of the NPC
  1752. */
  1753. public L2NpcTemplate[] addTalkId(int... talkIds)
  1754. {
  1755. L2NpcTemplate[] value = new L2NpcTemplate[talkIds.length];
  1756. int i = 0;
  1757. for (int talkId : talkIds)
  1758. {
  1759. value[i++] = addEventId(talkId, QuestEventType.ON_TALK);
  1760. }
  1761. return value;
  1762. }
  1763. /**
  1764. * @param npcId
  1765. * @return
  1766. */
  1767. public L2NpcTemplate addTalkId(int npcId)
  1768. {
  1769. return addEventId(npcId, QuestEventType.ON_TALK);
  1770. }
  1771. /**
  1772. * Add this quest to the list of quests that the passed npc will respond to for Spawn Events.
  1773. * @param npcIds : ID of the NPC
  1774. * @return int : ID of the NPC
  1775. */
  1776. public L2NpcTemplate[] addSpawnId(int... npcIds)
  1777. {
  1778. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1779. int i = 0;
  1780. for (int npcId : npcIds)
  1781. {
  1782. value[i++] = addEventId(npcId, QuestEventType.ON_SPAWN);
  1783. }
  1784. return value;
  1785. }
  1786. /**
  1787. * @param npcId
  1788. * @return
  1789. */
  1790. public L2NpcTemplate addSpawnId(int npcId)
  1791. {
  1792. return addEventId(npcId, QuestEventType.ON_SPAWN);
  1793. }
  1794. /**
  1795. * Add this quest to the list of quests that the passed npc will respond to for Skill-See Events.
  1796. * @param npcIds : ID of the NPC
  1797. * @return int : ID of the NPC
  1798. */
  1799. public L2NpcTemplate[] addSkillSeeId(int... npcIds)
  1800. {
  1801. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1802. int i = 0;
  1803. for (int npcId : npcIds)
  1804. {
  1805. value[i++] = addEventId(npcId, QuestEventType.ON_SKILL_SEE);
  1806. }
  1807. return value;
  1808. }
  1809. /**
  1810. * @param npcId
  1811. * @return
  1812. */
  1813. public L2NpcTemplate addSkillSeeId(int npcId)
  1814. {
  1815. return addEventId(npcId, QuestEventType.ON_SKILL_SEE);
  1816. }
  1817. /**
  1818. * @param npcIds
  1819. * @return
  1820. */
  1821. public L2NpcTemplate[] addSpellFinishedId(int... npcIds)
  1822. {
  1823. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1824. int i = 0;
  1825. for (int npcId : npcIds)
  1826. {
  1827. value[i++] = addEventId(npcId, QuestEventType.ON_SPELL_FINISHED);
  1828. }
  1829. return value;
  1830. }
  1831. /**
  1832. * @param npcId
  1833. * @return
  1834. */
  1835. public L2NpcTemplate addSpellFinishedId(int npcId)
  1836. {
  1837. return addEventId(npcId, QuestEventType.ON_SPELL_FINISHED);
  1838. }
  1839. /**
  1840. * @param npcIds
  1841. * @return
  1842. */
  1843. public L2NpcTemplate[] addTrapActionId(int... npcIds)
  1844. {
  1845. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1846. int i = 0;
  1847. for (int npcId : npcIds)
  1848. {
  1849. value[i++] = addEventId(npcId, QuestEventType.ON_TRAP_ACTION);
  1850. }
  1851. return value;
  1852. }
  1853. /**
  1854. * @param npcId
  1855. * @return
  1856. */
  1857. public L2NpcTemplate addTrapActionId(int npcId)
  1858. {
  1859. return addEventId(npcId, QuestEventType.ON_TRAP_ACTION);
  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 : ID of the NPC
  1864. * @return int : ID of the NPC
  1865. */
  1866. public L2NpcTemplate[] addFactionCallId(int... npcIds)
  1867. {
  1868. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1869. int i = 0;
  1870. for (int npcId : npcIds)
  1871. {
  1872. value[i++] = addEventId(npcId, QuestEventType.ON_FACTION_CALL);
  1873. }
  1874. return value;
  1875. }
  1876. /**
  1877. * @param npcId
  1878. * @return
  1879. */
  1880. public L2NpcTemplate addFactionCallId(int npcId)
  1881. {
  1882. return addEventId(npcId, QuestEventType.ON_FACTION_CALL);
  1883. }
  1884. /**
  1885. * Add this quest to the list of quests that the passed npc will respond to for Character See Events.
  1886. * @param npcIds : ID of the NPC
  1887. * @return int : ID of the NPC
  1888. */
  1889. public L2NpcTemplate[] addAggroRangeEnterId(int... npcIds)
  1890. {
  1891. L2NpcTemplate[] value = new L2NpcTemplate[npcIds.length];
  1892. int i = 0;
  1893. for (int npcId : npcIds)
  1894. {
  1895. value[i++] = addEventId(npcId, QuestEventType.ON_AGGRO_RANGE_ENTER);
  1896. }
  1897. return value;
  1898. }
  1899. /**
  1900. * @param npcId
  1901. * @return
  1902. */
  1903. public L2NpcTemplate addAggroRangeEnterId(int npcId)
  1904. {
  1905. return addEventId(npcId, QuestEventType.ON_AGGRO_RANGE_ENTER);
  1906. }
  1907. /**
  1908. * @param zoneIds
  1909. * @return
  1910. */
  1911. public L2ZoneType[] addEnterZoneId(int... zoneIds)
  1912. {
  1913. L2ZoneType[] value = new L2ZoneType[zoneIds.length];
  1914. int i = 0;
  1915. for (int zoneId : zoneIds)
  1916. {
  1917. try
  1918. {
  1919. L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1920. if (zone != null)
  1921. {
  1922. zone.addQuestEvent(QuestEventType.ON_ENTER_ZONE, this);
  1923. }
  1924. value[i++] = zone;
  1925. }
  1926. catch (Exception e)
  1927. {
  1928. _log.log(Level.WARNING, "Exception on addEnterZoneId(): " + e.getMessage(), e);
  1929. continue;
  1930. }
  1931. }
  1932. return value;
  1933. }
  1934. /**
  1935. * @param zoneId
  1936. * @return
  1937. */
  1938. public L2ZoneType addEnterZoneId(int zoneId)
  1939. {
  1940. try
  1941. {
  1942. L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1943. if (zone != null)
  1944. {
  1945. zone.addQuestEvent(QuestEventType.ON_ENTER_ZONE, this);
  1946. }
  1947. return zone;
  1948. }
  1949. catch (Exception e)
  1950. {
  1951. _log.log(Level.WARNING, "Exception on addEnterZoneId(): " + e.getMessage(), e);
  1952. return null;
  1953. }
  1954. }
  1955. /**
  1956. * @param zoneIds
  1957. * @return
  1958. */
  1959. public L2ZoneType[] addExitZoneId(int... zoneIds)
  1960. {
  1961. L2ZoneType[] value = new L2ZoneType[zoneIds.length];
  1962. int i = 0;
  1963. for (int zoneId : zoneIds)
  1964. {
  1965. try
  1966. {
  1967. L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1968. if (zone != null)
  1969. {
  1970. zone.addQuestEvent(QuestEventType.ON_EXIT_ZONE, this);
  1971. }
  1972. value[i++] = zone;
  1973. }
  1974. catch (Exception e)
  1975. {
  1976. _log.log(Level.WARNING, "Exception on addEnterZoneId(): " + e.getMessage(), e);
  1977. continue;
  1978. }
  1979. }
  1980. return value;
  1981. }
  1982. /**
  1983. * @param zoneId
  1984. * @return
  1985. */
  1986. public L2ZoneType addExitZoneId(int zoneId)
  1987. {
  1988. try
  1989. {
  1990. L2ZoneType zone = ZoneManager.getInstance().getZoneById(zoneId);
  1991. if (zone != null)
  1992. {
  1993. zone.addQuestEvent(QuestEventType.ON_EXIT_ZONE, this);
  1994. }
  1995. return zone;
  1996. }
  1997. catch (Exception e)
  1998. {
  1999. _log.log(Level.WARNING, "Exception on addExitZoneId(): " + e.getMessage(), e);
  2000. return null;
  2001. }
  2002. }
  2003. /**
  2004. * Use this method to get a random party member from a player's party.<br>
  2005. * Useful when distributing rewards after killing an NPC.
  2006. * @param player this parameter represents the player whom the party will taken.
  2007. * @return if {@code player} is null returns null, if the {@code player} does not have a party returns {@code player}, other wise select a random party member.
  2008. */
  2009. public L2PcInstance getRandomPartyMember(L2PcInstance player)
  2010. {
  2011. if (player == null)
  2012. {
  2013. return null;
  2014. }
  2015. final L2Party party = player.getParty();
  2016. if ((party == null) || (party.getMembers().isEmpty()))
  2017. {
  2018. return player;
  2019. }
  2020. return party.getMembers().get(Rnd.get(party.getMembers().size()));
  2021. }
  2022. /**
  2023. * Auxiliary function for party quests.<br>
  2024. * Note: This function is only here because of how commonly it may be used by quest developers.<br>
  2025. * For any variations on this function, the quest script can always handle things on its own.
  2026. * @param player the instance of a player whose party is to be searched
  2027. * @param value the value of the "cond" variable that must be matched
  2028. * @return L2PcInstance: L2PcInstance for a random party member that matches the specified condition, or null if no match.
  2029. */
  2030. public L2PcInstance getRandomPartyMember(L2PcInstance player, String value)
  2031. {
  2032. return getRandomPartyMember(player, "cond", value);
  2033. }
  2034. /**
  2035. * Auxiliary function for party quests.<br>
  2036. * Note: This function is only here because of how commonly it may be used by quest developers.<br>
  2037. * For any variations on this function, the quest script can always handle things on its own.
  2038. * @param player the instance of a player whose party is to be searched
  2039. * @param var
  2040. * @param value a tuple specifying a quest condition that must be satisfied for a party member to be considered.
  2041. * @return L2PcInstance: L2PcInstance for a random party member that matches the specified condition, or null if no match. If the var is null, any random party member is returned (i.e. no condition is applied). The party member must be within 1500 distance from the target of the reference
  2042. * player, or if no target exists, 1500 distance from the player itself.
  2043. */
  2044. public L2PcInstance getRandomPartyMember(L2PcInstance player, String var, String value)
  2045. {
  2046. // if no valid player instance is passed, there is nothing to check...
  2047. if (player == null)
  2048. {
  2049. return null;
  2050. }
  2051. // for null var condition, return any random party member.
  2052. if (var == null)
  2053. {
  2054. return getRandomPartyMember(player);
  2055. }
  2056. // normal cases...if the player is not in a party, check the player's state
  2057. QuestState temp = null;
  2058. L2Party party = player.getParty();
  2059. // if this player is not in a party, just check if this player instance matches the conditions itself
  2060. if ((party == null) || (party.getMembers().isEmpty()))
  2061. {
  2062. temp = player.getQuestState(getName());
  2063. if ((temp != null) && (temp.get(var) != null) && (temp.get(var)).equalsIgnoreCase(value))
  2064. {
  2065. return player; // match
  2066. }
  2067. return null; // no match
  2068. }
  2069. // if the player is in a party, gather a list of all matching party members (possibly
  2070. // including this player)
  2071. FastList<L2PcInstance> candidates = new FastList<L2PcInstance>();
  2072. // get the target for enforcing distance limitations.
  2073. L2Object target = player.getTarget();
  2074. if (target == null)
  2075. {
  2076. target = player;
  2077. }
  2078. for (L2PcInstance partyMember : party.getMembers())
  2079. {
  2080. if (partyMember == null)
  2081. {
  2082. continue;
  2083. }
  2084. temp = partyMember.getQuestState(getName());
  2085. if ((temp != null) && (temp.get(var) != null) && (temp.get(var)).equalsIgnoreCase(value) && partyMember.isInsideRadius(target, 1500, true, false))
  2086. {
  2087. candidates.add(partyMember);
  2088. }
  2089. }
  2090. // if there was no match, return null...
  2091. if (candidates.isEmpty())
  2092. {
  2093. return null;
  2094. }
  2095. // if a match was found from the party, return one of them at random.
  2096. return candidates.get(Rnd.get(candidates.size()));
  2097. }
  2098. /**
  2099. * Auxiliary function for party quests.<br>
  2100. * Note: This function is only here because of how commonly it may be used by quest developers.<br>
  2101. * For any variations on this function, the quest script can always handle things on its own.
  2102. * @param player the instance of a player whose party is to be searched
  2103. * @param state the state in which the party member's queststate must be in order to be considered.
  2104. * @return L2PcInstance: L2PcInstance for a random party member that matches the specified condition, or null if no match. If the var is null, any random party member is returned (i.e. no condition is applied).
  2105. */
  2106. public L2PcInstance getRandomPartyMemberState(L2PcInstance player, byte state)
  2107. {
  2108. // if no valid player instance is passed, there is nothing to check...
  2109. if (player == null)
  2110. {
  2111. return null;
  2112. }
  2113. // normal cases...if the player is not in a partym check the player's state
  2114. QuestState temp = null;
  2115. L2Party party = player.getParty();
  2116. // if this player is not in a party, just check if this player instance matches the conditions itself
  2117. if ((party == null) || (party.getMembers().isEmpty()))
  2118. {
  2119. temp = player.getQuestState(getName());
  2120. if ((temp != null) && (temp.getState() == state))
  2121. {
  2122. return player; // match
  2123. }
  2124. return null; // no match
  2125. }
  2126. // if the player is in a party, gather a list of all matching party members (possibly
  2127. // including this player)
  2128. FastList<L2PcInstance> candidates = new FastList<L2PcInstance>();
  2129. // get the target for enforcing distance limitations.
  2130. L2Object target = player.getTarget();
  2131. if (target == null)
  2132. {
  2133. target = player;
  2134. }
  2135. for (L2PcInstance partyMember : party.getMembers())
  2136. {
  2137. if (partyMember == null)
  2138. {
  2139. continue;
  2140. }
  2141. temp = partyMember.getQuestState(getName());
  2142. if ((temp != null) && (temp.getState() == state) && partyMember.isInsideRadius(target, 1500, true, false))
  2143. {
  2144. candidates.add(partyMember);
  2145. }
  2146. }
  2147. // if there was no match, return null...
  2148. if (candidates.isEmpty())
  2149. {
  2150. return null;
  2151. }
  2152. // if a match was found from the party, return one of them at random.
  2153. return candidates.get(Rnd.get(candidates.size()));
  2154. }
  2155. /**
  2156. * Show HTML file to client
  2157. * @param player
  2158. * @param fileName
  2159. * @return String : message sent to client
  2160. */
  2161. public String showHtmlFile(L2PcInstance player, String fileName)
  2162. {
  2163. boolean questwindow = true;
  2164. if (fileName.endsWith(".html"))
  2165. {
  2166. questwindow = false;
  2167. }
  2168. int questId = getQuestIntId();
  2169. // Create handler to file linked to the quest
  2170. String content = getHtm(player.getHtmlPrefix(), fileName);
  2171. if (player.getTarget() != null)
  2172. {
  2173. content = content.replaceAll("%objectId%", String.valueOf(player.getTarget().getObjectId()));
  2174. }
  2175. // Send message to client if message not empty
  2176. if (content != null)
  2177. {
  2178. if (questwindow && (questId > 0) && (questId < 20000) && (questId != 999))
  2179. {
  2180. NpcQuestHtmlMessage npcReply = new NpcQuestHtmlMessage(5, questId);
  2181. npcReply.setHtml(content);
  2182. npcReply.replace("%playername%", player.getName());
  2183. player.sendPacket(npcReply);
  2184. }
  2185. else
  2186. {
  2187. NpcHtmlMessage npcReply = new NpcHtmlMessage(5);
  2188. npcReply.setHtml(content);
  2189. npcReply.replace("%playername%", player.getName());
  2190. player.sendPacket(npcReply);
  2191. }
  2192. player.sendPacket(ActionFailed.STATIC_PACKET);
  2193. }
  2194. return content;
  2195. }
  2196. /**
  2197. * Return HTML file contents
  2198. * @param prefix player's language prefix.
  2199. * @param fileName the html file to be get.
  2200. * @return
  2201. */
  2202. public String getHtm(String prefix, String fileName)
  2203. {
  2204. String content = HtmCache.getInstance().getHtm(prefix, "data/scripts/" + getDescr().toLowerCase() + "/" + getName() + "/" + fileName);
  2205. if (content == null)
  2206. {
  2207. content = HtmCache.getInstance().getHtm(prefix, "data/scripts/quests/Q" + getName() + "/" + fileName);
  2208. if (content == null)
  2209. {
  2210. content = HtmCache.getInstance().getHtmForce(prefix, "data/scripts/quests/" + getName() + "/" + fileName);
  2211. }
  2212. }
  2213. return content;
  2214. }
  2215. /**
  2216. * Add a temporary (quest) spawn
  2217. * @param npcId
  2218. * @param cha
  2219. * @return instance of newly spawned npc
  2220. */
  2221. public L2Npc addSpawn(int npcId, L2Character cha)
  2222. {
  2223. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), false, 0, false);
  2224. }
  2225. /**
  2226. * Add a temporary (quest) spawn
  2227. * @param npcId
  2228. * @param cha
  2229. * @param isSummonSpawn
  2230. * @return instance of newly spawned npc with summon animation
  2231. */
  2232. public L2Npc addSpawn(int npcId, L2Character cha, boolean isSummonSpawn)
  2233. {
  2234. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), false, 0, isSummonSpawn);
  2235. }
  2236. /**
  2237. * @param npcId
  2238. * @param x
  2239. * @param y
  2240. * @param z
  2241. * @param heading
  2242. * @param randomOffSet
  2243. * @param despawnDelay
  2244. * @return
  2245. */
  2246. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffSet, long despawnDelay)
  2247. {
  2248. return addSpawn(npcId, x, y, z, heading, randomOffSet, despawnDelay, false);
  2249. }
  2250. /**
  2251. * @param npcId
  2252. * @param loc
  2253. * @param randomOffSet
  2254. * @param despawnDelay
  2255. * @return
  2256. */
  2257. public L2Npc addSpawn(int npcId, Location loc, boolean randomOffSet, long despawnDelay)
  2258. {
  2259. return addSpawn(npcId, loc.getX(), loc.getY(), loc.getZ(), loc.getHeading(), randomOffSet, despawnDelay, false);
  2260. }
  2261. /**
  2262. * @param npcId
  2263. * @param x
  2264. * @param y
  2265. * @param z
  2266. * @param heading
  2267. * @param randomOffset
  2268. * @param despawnDelay
  2269. * @param isSummonSpawn
  2270. * @return
  2271. */
  2272. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay, boolean isSummonSpawn)
  2273. {
  2274. return addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn, 0);
  2275. }
  2276. /**
  2277. * @param npcId
  2278. * @param loc
  2279. * @param randomOffset
  2280. * @param despawnDelay
  2281. * @param isSummonSpawn
  2282. * @return
  2283. */
  2284. public L2Npc addSpawn(int npcId, Location loc, boolean randomOffset, long despawnDelay, boolean isSummonSpawn)
  2285. {
  2286. return addSpawn(npcId, loc.getX(), loc.getY(), loc.getZ(), loc.getHeading(), randomOffset, despawnDelay, isSummonSpawn, 0);
  2287. }
  2288. /**
  2289. * @param npcId
  2290. * @param x
  2291. * @param y
  2292. * @param z
  2293. * @param heading
  2294. * @param randomOffset
  2295. * @param despawnDelay
  2296. * @param isSummonSpawn
  2297. * @param instanceId
  2298. * @return
  2299. */
  2300. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, long despawnDelay, boolean isSummonSpawn, int instanceId)
  2301. {
  2302. L2Npc result = null;
  2303. try
  2304. {
  2305. L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
  2306. if (template != null)
  2307. {
  2308. // Sometimes, even if the quest script specifies some xyz (for example npc.getX() etc) by the time the code
  2309. // reaches here, xyz have become 0! Also, a questdev might have purposely set xy to 0,0...however,
  2310. // the spawn code is coded such that if x=y=0, it looks into location for the spawn loc! This will NOT work
  2311. // with quest spawns! For both of the above cases, we need a fail-safe spawn. For this, we use the
  2312. // default spawn location, which is at the player's loc.
  2313. if ((x == 0) && (y == 0))
  2314. {
  2315. _log.log(Level.SEVERE, "Failed to adjust bad locks for quest spawn! Spawn aborted!");
  2316. return null;
  2317. }
  2318. if (randomOffset)
  2319. {
  2320. int offset;
  2321. offset = Rnd.get(2); // Get the direction of the offset
  2322. if (offset == 0)
  2323. {
  2324. offset = -1;
  2325. } // make offset negative
  2326. offset *= Rnd.get(50, 100);
  2327. x += offset;
  2328. offset = Rnd.get(2); // Get the direction of the offset
  2329. if (offset == 0)
  2330. {
  2331. offset = -1;
  2332. } // make offset negative
  2333. offset *= Rnd.get(50, 100);
  2334. y += offset;
  2335. }
  2336. L2Spawn spawn = new L2Spawn(template);
  2337. spawn.setInstanceId(instanceId);
  2338. spawn.setHeading(heading);
  2339. spawn.setLocx(x);
  2340. spawn.setLocy(y);
  2341. spawn.setLocz(z + 20);
  2342. spawn.stopRespawn();
  2343. result = spawn.spawnOne(isSummonSpawn);
  2344. if (despawnDelay > 0)
  2345. {
  2346. result.scheduleDespawn(despawnDelay);
  2347. }
  2348. return result;
  2349. }
  2350. }
  2351. catch (Exception e1)
  2352. {
  2353. _log.warning("Could not spawn Npc " + npcId);
  2354. }
  2355. return null;
  2356. }
  2357. /**
  2358. * @param trapId
  2359. * @param x
  2360. * @param y
  2361. * @param z
  2362. * @param heading
  2363. * @param skill
  2364. * @param instanceId
  2365. * @return
  2366. */
  2367. public L2Trap addTrap(int trapId, int x, int y, int z, int heading, L2Skill skill, int instanceId)
  2368. {
  2369. L2NpcTemplate TrapTemplate = NpcTable.getInstance().getTemplate(trapId);
  2370. L2Trap trap = new L2TrapInstance(IdFactory.getInstance().getNextId(), TrapTemplate, instanceId, -1, skill);
  2371. trap.setCurrentHp(trap.getMaxHp());
  2372. trap.setCurrentMp(trap.getMaxMp());
  2373. trap.setIsInvul(true);
  2374. trap.setHeading(heading);
  2375. // L2World.getInstance().storeObject(trap);
  2376. trap.spawnMe(x, y, z);
  2377. return trap;
  2378. }
  2379. /**
  2380. * @param master
  2381. * @param minionId
  2382. * @return
  2383. */
  2384. public L2Npc addMinion(L2MonsterInstance master, int minionId)
  2385. {
  2386. return MinionList.spawnMinion(master, minionId);
  2387. }
  2388. /**
  2389. * @return the registered quest items Ids.
  2390. */
  2391. public int[] getRegisteredItemIds()
  2392. {
  2393. return questItemIds;
  2394. }
  2395. @Override
  2396. public String getScriptName()
  2397. {
  2398. return getName();
  2399. }
  2400. @Override
  2401. public void setActive(boolean status)
  2402. {
  2403. // TODO implement me
  2404. }
  2405. @Override
  2406. public boolean reload()
  2407. {
  2408. unload();
  2409. return super.reload();
  2410. }
  2411. @Override
  2412. public boolean unload()
  2413. {
  2414. return unload(true);
  2415. }
  2416. /**
  2417. * @param removeFromList
  2418. * @return
  2419. */
  2420. public boolean unload(boolean removeFromList)
  2421. {
  2422. saveGlobalData();
  2423. // cancel all pending timers before reloading.
  2424. // if timers ought to be restarted, the quest can take care of it
  2425. // with its code (example: save global data indicating what timer must
  2426. // be restarted).
  2427. for (FastList<QuestTimer> timers : _allEventTimers.values())
  2428. {
  2429. for (QuestTimer timer : timers)
  2430. {
  2431. timer.cancel();
  2432. }
  2433. }
  2434. _allEventTimers.clear();
  2435. for (Integer npcId : _questInvolvedNpcs)
  2436. {
  2437. L2NpcTemplate template = NpcTable.getInstance().getTemplate(npcId);
  2438. if (template != null)
  2439. template.removeQuest(this);
  2440. }
  2441. _questInvolvedNpcs.clear();
  2442. if (removeFromList)
  2443. {
  2444. return QuestManager.getInstance().removeQuest(this);
  2445. }
  2446. return true;
  2447. }
  2448. @Override
  2449. public ScriptManager<?> getScriptManager()
  2450. {
  2451. return QuestManager.getInstance();
  2452. }
  2453. /**
  2454. * @param val
  2455. */
  2456. public void setOnEnterWorld(boolean val)
  2457. {
  2458. _onEnterWorld = val;
  2459. }
  2460. /**
  2461. * @return
  2462. */
  2463. public boolean getOnEnterWorld()
  2464. {
  2465. return _onEnterWorld;
  2466. }
  2467. /**
  2468. * If a quest is set as custom, it will display it's name in the NPC Quest List.<br>
  2469. * Retail quests are unhardcoded to display the name using a client string.
  2470. * @param val if {@code true} the quest script will be set as custom quest.
  2471. */
  2472. public void setIsCustom(boolean val)
  2473. {
  2474. _isCustom = val;
  2475. }
  2476. /**
  2477. * @return {@code true} if the quest script is a custom quest, {@code false} otherwise.
  2478. */
  2479. public boolean isCustomQuest()
  2480. {
  2481. return _isCustom;
  2482. }
  2483. /**
  2484. * @param val
  2485. */
  2486. public void setOlympiadUse(boolean val)
  2487. {
  2488. _isOlympiadUse = val;
  2489. }
  2490. /**
  2491. * @return {@code true} if the quest script is used for Olympiad quests, {@code false} otherwise.
  2492. */
  2493. public boolean isOlympiadUse()
  2494. {
  2495. return _isOlympiadUse;
  2496. }
  2497. /**
  2498. * @param player this parameter contains a reference to the player to check.
  2499. * @param itemId the item wanted to be count.
  2500. * @return the quantity of one sort of item hold by the player.
  2501. */
  2502. public long getQuestItemsCount(L2PcInstance player, int itemId)
  2503. {
  2504. long count = 0;
  2505. for (L2ItemInstance item : player.getInventory().getItems())
  2506. {
  2507. if ((item != null) && (item.getItemId() == itemId))
  2508. {
  2509. count += item.getCount();
  2510. }
  2511. }
  2512. return count;
  2513. }
  2514. /**
  2515. * @param player this parameter contains a reference to the player to check.
  2516. * @param itemId the item Id of the item to verify.
  2517. * @return {code true} if the item exists in player's inventory, otherwise {@code false}.
  2518. */
  2519. public boolean hasQuestItems(L2PcInstance player, int itemId)
  2520. {
  2521. return player.getInventory().getItemByItemId(itemId) != null;
  2522. }
  2523. /**
  2524. * @param player this parameter contains a reference to the player to check.
  2525. * @param itemIds the item Ids of the items to verify.
  2526. * @return {code true} if all the items exists in player's inventory, otherwise {@code false}.
  2527. */
  2528. public boolean hasQuestItems(L2PcInstance player, int... itemIds)
  2529. {
  2530. final PcInventory inv = player.getInventory();
  2531. for (int itemId : itemIds)
  2532. {
  2533. if (inv.getItemByItemId(itemId) == null)
  2534. {
  2535. return false;
  2536. }
  2537. }
  2538. return true;
  2539. }
  2540. /**
  2541. * @param player this parameter contains a reference to the player to check.
  2542. * @param itemId : ID of the item to check enchantment
  2543. * @return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
  2544. */
  2545. public int getEnchantLevel(L2PcInstance player, int itemId)
  2546. {
  2547. L2ItemInstance enchanteditem = player.getInventory().getItemByItemId(itemId);
  2548. if (enchanteditem == null)
  2549. {
  2550. return 0;
  2551. }
  2552. return enchanteditem.getEnchantLevel();
  2553. }
  2554. /**
  2555. * Give Adena to the player
  2556. * @param player this parameter contains a reference to the player that receives the Adena.
  2557. * @param count this parameter represent the Adena count to give to the player.
  2558. * @param applyRates if {@code true} quest rates will be applied.
  2559. */
  2560. public void giveAdena(L2PcInstance player, long count, boolean applyRates)
  2561. {
  2562. giveItems(player, PcInventory.ADENA_ID, count, applyRates ? 0 : 1);
  2563. }
  2564. /**
  2565. * Give reward to player using multipliers.
  2566. * @param player
  2567. * @param itemId
  2568. * @param count
  2569. */
  2570. public void rewardItems(L2PcInstance player, int itemId, long count)
  2571. {
  2572. if (count <= 0)
  2573. {
  2574. return;
  2575. }
  2576. L2ItemInstance _tmpItem = ItemTable.getInstance().createDummyItem(itemId);
  2577. if (_tmpItem == null)
  2578. {
  2579. return;
  2580. }
  2581. if (itemId == PcInventory.ADENA_ID)
  2582. {
  2583. count = (long) (count * Config.RATE_QUEST_REWARD_ADENA);
  2584. }
  2585. else if (Config.RATE_QUEST_REWARD_USE_MULTIPLIERS)
  2586. {
  2587. if (_tmpItem.isEtcItem())
  2588. {
  2589. switch (_tmpItem.getEtcItem().getItemType())
  2590. {
  2591. case POTION:
  2592. count = (long) (count * Config.RATE_QUEST_REWARD_POTION);
  2593. break;
  2594. case SCRL_ENCHANT_WP:
  2595. case SCRL_ENCHANT_AM:
  2596. case SCROLL:
  2597. count = (long) (count * Config.RATE_QUEST_REWARD_SCROLL);
  2598. break;
  2599. case RECIPE:
  2600. count = (long) (count * Config.RATE_QUEST_REWARD_RECIPE);
  2601. break;
  2602. case MATERIAL:
  2603. count = (long) (count * Config.RATE_QUEST_REWARD_MATERIAL);
  2604. break;
  2605. default:
  2606. count = (long) (count * Config.RATE_QUEST_REWARD);
  2607. }
  2608. }
  2609. }
  2610. else
  2611. {
  2612. count = (long) (count * Config.RATE_QUEST_REWARD);
  2613. }
  2614. // Add items to player's inventory
  2615. L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  2616. if (item == null)
  2617. {
  2618. return;
  2619. }
  2620. // If item for reward is gold, send message of gold reward to client
  2621. if (itemId == PcInventory.ADENA_ID)
  2622. {
  2623. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA);
  2624. smsg.addItemNumber(count);
  2625. player.sendPacket(smsg);
  2626. }
  2627. // Otherwise, send message of object reward to client
  2628. else
  2629. {
  2630. if (count > 1)
  2631. {
  2632. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
  2633. smsg.addItemName(item);
  2634. smsg.addItemNumber(count);
  2635. player.sendPacket(smsg);
  2636. }
  2637. else
  2638. {
  2639. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
  2640. smsg.addItemName(item);
  2641. player.sendPacket(smsg);
  2642. }
  2643. }
  2644. // send packets
  2645. StatusUpdate su = new StatusUpdate(player);
  2646. su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  2647. player.sendPacket(su);
  2648. }
  2649. /**
  2650. * Give item/reward to the player
  2651. * @param player
  2652. * @param itemId
  2653. * @param count
  2654. */
  2655. public void giveItems(L2PcInstance player, int itemId, long count)
  2656. {
  2657. giveItems(player, itemId, count, 0);
  2658. }
  2659. /**
  2660. * @param player
  2661. * @param itemId
  2662. * @param count
  2663. * @param enchantlevel
  2664. */
  2665. public void giveItems(L2PcInstance player, int itemId, long count, int enchantlevel)
  2666. {
  2667. if (count <= 0)
  2668. {
  2669. return;
  2670. }
  2671. // If item for reward is adena (ID=57), modify count with rate for quest reward if rates available
  2672. if ((itemId == PcInventory.ADENA_ID) && !(enchantlevel > 0))
  2673. {
  2674. count = (long) (count * Config.RATE_QUEST_REWARD_ADENA);
  2675. }
  2676. // Add items to player's inventory
  2677. L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  2678. if (item == null)
  2679. {
  2680. return;
  2681. }
  2682. // set enchant level for item if that item is not adena
  2683. if ((enchantlevel > 0) && (itemId != PcInventory.ADENA_ID))
  2684. {
  2685. item.setEnchantLevel(enchantlevel);
  2686. }
  2687. // If item for reward is gold, send message of gold reward to client
  2688. if (itemId == PcInventory.ADENA_ID)
  2689. {
  2690. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA);
  2691. smsg.addItemNumber(count);
  2692. player.sendPacket(smsg);
  2693. }
  2694. // Otherwise, send message of object reward to client
  2695. else
  2696. {
  2697. if (count > 1)
  2698. {
  2699. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
  2700. smsg.addItemName(item);
  2701. smsg.addItemNumber(count);
  2702. player.sendPacket(smsg);
  2703. }
  2704. else
  2705. {
  2706. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
  2707. smsg.addItemName(item);
  2708. player.sendPacket(smsg);
  2709. }
  2710. }
  2711. // send packets
  2712. StatusUpdate su = new StatusUpdate(player);
  2713. su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  2714. player.sendPacket(su);
  2715. }
  2716. /**
  2717. * @param player
  2718. * @param itemId
  2719. * @param count
  2720. * @param attributeId
  2721. * @param attributeLevel
  2722. */
  2723. public void giveItems(L2PcInstance player, int itemId, long count, byte attributeId, int attributeLevel)
  2724. {
  2725. if (count <= 0)
  2726. {
  2727. return;
  2728. }
  2729. // Add items to player's inventory
  2730. L2ItemInstance item = player.getInventory().addItem("Quest", itemId, count, player, player.getTarget());
  2731. if (item == null)
  2732. {
  2733. return;
  2734. }
  2735. // set enchant level for item if that item is not adena
  2736. if ((attributeId >= 0) && (attributeLevel > 0))
  2737. {
  2738. item.setElementAttr(attributeId, attributeLevel);
  2739. if (item.isEquipped())
  2740. {
  2741. item.updateElementAttrBonus(player);
  2742. }
  2743. InventoryUpdate iu = new InventoryUpdate();
  2744. iu.addModifiedItem(item);
  2745. player.sendPacket(iu);
  2746. }
  2747. // If item for reward is gold, send message of gold reward to client
  2748. if (itemId == PcInventory.ADENA_ID)
  2749. {
  2750. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_ADENA);
  2751. smsg.addItemNumber(count);
  2752. player.sendPacket(smsg);
  2753. }
  2754. // Otherwise, send message of object reward to client
  2755. else
  2756. {
  2757. if (count > 1)
  2758. {
  2759. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
  2760. smsg.addItemName(item);
  2761. smsg.addItemNumber(count);
  2762. player.sendPacket(smsg);
  2763. }
  2764. else
  2765. {
  2766. SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
  2767. smsg.addItemName(item);
  2768. player.sendPacket(smsg);
  2769. }
  2770. }
  2771. // send packets
  2772. StatusUpdate su = new StatusUpdate(player);
  2773. su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  2774. player.sendPacket(su);
  2775. }
  2776. /**
  2777. * Drop Quest item using Config.RATE_QUEST_DROP
  2778. * @param player
  2779. * @param itemId int Item Identifier of the item to be dropped
  2780. * @param count (minCount, maxCount) long Quantity of items to be dropped
  2781. * @param neededCount Quantity of items needed for quest
  2782. * @param dropChance int Base chance of drop, same as in droplist
  2783. * @param sound boolean indicating whether to play sound
  2784. * @return boolean indicating whether player has requested number of items
  2785. */
  2786. public boolean dropQuestItems(L2PcInstance player, int itemId, int count, long neededCount, int dropChance, boolean sound)
  2787. {
  2788. return dropQuestItems(player, itemId, count, count, neededCount, dropChance, sound);
  2789. }
  2790. /**
  2791. * @param player
  2792. * @param itemId
  2793. * @param minCount
  2794. * @param maxCount
  2795. * @param neededCount
  2796. * @param dropChance
  2797. * @param sound
  2798. * @return
  2799. */
  2800. public boolean dropQuestItems(L2PcInstance player, int itemId, int minCount, int maxCount, long neededCount, int dropChance, boolean sound)
  2801. {
  2802. dropChance *= Config.RATE_QUEST_DROP / ((player.getParty() != null) ? player.getParty().getMemberCount() : 1);
  2803. long currentCount = getQuestItemsCount(player, itemId);
  2804. if ((neededCount > 0) && (currentCount >= neededCount))
  2805. {
  2806. return true;
  2807. }
  2808. if (currentCount >= neededCount)
  2809. {
  2810. return true;
  2811. }
  2812. long itemCount = 0;
  2813. int random = Rnd.get(L2DropData.MAX_CHANCE);
  2814. while (random < dropChance)
  2815. {
  2816. // Get the item quantity dropped
  2817. if (minCount < maxCount)
  2818. {
  2819. itemCount += Rnd.get(minCount, maxCount);
  2820. }
  2821. else if (minCount == maxCount)
  2822. {
  2823. itemCount += minCount;
  2824. }
  2825. else
  2826. {
  2827. itemCount++;
  2828. }
  2829. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  2830. dropChance -= L2DropData.MAX_CHANCE;
  2831. }
  2832. if (itemCount > 0)
  2833. {
  2834. // if over neededCount, just fill the gap
  2835. if ((neededCount > 0) && ((currentCount + itemCount) > neededCount))
  2836. {
  2837. itemCount = neededCount - currentCount;
  2838. }
  2839. // Inventory slot check
  2840. if (!player.getInventory().validateCapacityByItemId(itemId))
  2841. {
  2842. return false;
  2843. }
  2844. // Give the item to Player
  2845. player.addItem("Quest", itemId, itemCount, player.getTarget(), true);
  2846. if (sound)
  2847. {
  2848. playSound(player, ((currentCount + itemCount) < neededCount) ? "Itemsound.quest_itemget" : "Itemsound.quest_middle");
  2849. }
  2850. }
  2851. return ((neededCount > 0) && ((currentCount + itemCount) >= neededCount));
  2852. }
  2853. /**
  2854. * Remove items from player's inventory when talking to NPC in order to have rewards.<br>
  2855. * Actions:<br>
  2856. * <ul>
  2857. * <li>Destroy quantity of items wanted</li>
  2858. * <li>Send new inventory list to player</li>
  2859. * </ul>
  2860. * @param player
  2861. * @param itemId : Identifier of the item
  2862. * @param count : Quantity of items to destroy
  2863. */
  2864. public void takeItems(L2PcInstance player, int itemId, long count)
  2865. {
  2866. // Get object item from player's inventory list
  2867. L2ItemInstance item = player.getInventory().getItemByItemId(itemId);
  2868. if (item == null)
  2869. {
  2870. return;
  2871. }
  2872. // Tests on count value in order not to have negative value
  2873. if ((count < 0) || (count > item.getCount()))
  2874. {
  2875. count = item.getCount();
  2876. }
  2877. // Destroy the quantity of items wanted
  2878. if (item.isEquipped())
  2879. {
  2880. L2ItemInstance[] unequiped = player.getInventory().unEquipItemInBodySlotAndRecord(item.getItem().getBodyPart());
  2881. InventoryUpdate iu = new InventoryUpdate();
  2882. for (L2ItemInstance itm : unequiped)
  2883. {
  2884. iu.addModifiedItem(itm);
  2885. }
  2886. player.sendPacket(iu);
  2887. player.broadcastUserInfo();
  2888. }
  2889. player.destroyItemByItemId("Quest", itemId, count, player, true);
  2890. }
  2891. /**
  2892. * Send a packet in order to play sound at client terminal
  2893. * @param player
  2894. * @param sound
  2895. */
  2896. public void playSound(L2PcInstance player, String sound)
  2897. {
  2898. player.sendPacket(new PlaySound(sound));
  2899. }
  2900. /**
  2901. * Add XP and SP as quest reward
  2902. * @param player
  2903. * @param exp
  2904. * @param sp
  2905. */
  2906. public void addExpAndSp(L2PcInstance player, int exp, int sp)
  2907. {
  2908. player.addExpAndSp((int) 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));
  2909. }
  2910. /**
  2911. * Gets a random integer number from 0 (inclusive) to {@code max} (exclusive).<br>
  2912. * Use this method instead importing {@link com.l2jserver.util.Rnd} utility.
  2913. * @param max this parameter represents the maximum value for randomization.
  2914. * @return a random integer number from 0 to {@code max} - 1.
  2915. */
  2916. public static int getRandom(int max)
  2917. {
  2918. return Rnd.get(max);
  2919. }
  2920. /**
  2921. * Gets a random integer number from {@code min} (inclusive) to {@code max} (inclusive).<br>
  2922. * Use this method instead importing {@link com.l2jserver.util.Rnd} utility.
  2923. * @param min this parameter represents the minimum value for randomization.
  2924. * @param max this parameter represents the maximum value for randomization.
  2925. * @return a random integer number from {@code min} to {@code max} .
  2926. */
  2927. public static int getRandom(int min, int max)
  2928. {
  2929. return Rnd.get(min, max);
  2930. }
  2931. /**
  2932. * @param player this parameter is a reference to the player.
  2933. * @param slot this parameter represents the location in the player's inventory.
  2934. * @return the item Id of the item present in the inventory slot {@code slot} if it's not null, 0 otherwise.
  2935. */
  2936. public int getItemEquipped(L2PcInstance player, int slot)
  2937. {
  2938. return player.getInventory().getPaperdollItemId(slot);
  2939. }
  2940. /**
  2941. * @return the number of ticks from the {@link com.l2jserver.gameserver.GameTimeController}.
  2942. */
  2943. public int getGameTicks()
  2944. {
  2945. return GameTimeController.getGameTicks();
  2946. }
  2947. }