QuestState.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  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 net.sf.l2j.gameserver.model.quest;
  16. import java.util.Map;
  17. import java.util.logging.Logger;
  18. import javolution.util.FastMap;
  19. import net.sf.l2j.Config;
  20. import net.sf.l2j.gameserver.GameTimeController;
  21. import net.sf.l2j.gameserver.cache.HtmCache;
  22. import net.sf.l2j.gameserver.instancemanager.QuestManager;
  23. import net.sf.l2j.gameserver.model.L2Character;
  24. import net.sf.l2j.gameserver.model.L2DropData;
  25. import net.sf.l2j.gameserver.model.L2ItemInstance;
  26. import net.sf.l2j.gameserver.model.actor.instance.L2MonsterInstance;
  27. import net.sf.l2j.gameserver.model.actor.instance.L2NpcInstance;
  28. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  29. import net.sf.l2j.gameserver.network.SystemMessageId;
  30. import net.sf.l2j.gameserver.network.serverpackets.ExShowQuestMark;
  31. import net.sf.l2j.gameserver.network.serverpackets.ItemList;
  32. import net.sf.l2j.gameserver.network.serverpackets.PlaySound;
  33. import net.sf.l2j.gameserver.network.serverpackets.QuestList;
  34. import net.sf.l2j.gameserver.network.serverpackets.StatusUpdate;
  35. import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
  36. import net.sf.l2j.gameserver.network.serverpackets.TutorialCloseHtml;
  37. import net.sf.l2j.gameserver.network.serverpackets.TutorialEnableClientEvent;
  38. import net.sf.l2j.gameserver.network.serverpackets.TutorialShowHtml;
  39. import net.sf.l2j.gameserver.network.serverpackets.TutorialShowQuestionMark;
  40. import net.sf.l2j.gameserver.skills.Stats;
  41. import net.sf.l2j.util.Rnd;
  42. /**
  43. * @author Luis Arias
  44. */
  45. public final class QuestState
  46. {
  47. protected static final Logger _log = Logger.getLogger(Quest.class.getName());
  48. /** Quest associated to the QuestState */
  49. private final String _questName;
  50. /** Player who engaged the quest */
  51. private final L2PcInstance _player;
  52. /** State of the quest */
  53. private byte _state;
  54. /** List of couples (variable for quest,value of the variable for quest) */
  55. private Map<String, String> _vars;
  56. /** Boolean flag letting QuestStateManager know to exit quest when cleaning up */
  57. private boolean _isExitQuestOnCleanUp = false;
  58. /**
  59. * Constructor of the QuestState : save the quest in the list of quests of the player.<BR/><BR/>
  60. *
  61. * <U><I>Actions :</U></I><BR/>
  62. * <LI>Save informations in the object QuestState created (Quest, Player, Completion, State)</LI>
  63. * <LI>Add the QuestState in the player's list of quests by using setQuestState()</LI>
  64. * <LI>Add drops gotten by the quest</LI>
  65. * <BR/>
  66. * @param quest : quest associated with the QuestState
  67. * @param player : L2PcInstance pointing out the player
  68. * @param state : state of the quest
  69. * @param completed : boolean for completion of the quest
  70. */
  71. QuestState(Quest quest, L2PcInstance player, byte state)
  72. {
  73. _questName = quest.getName();
  74. _player = player;
  75. // Save the state of the quest for the player in the player's list of quest onwed
  76. getPlayer().setQuestState(this);
  77. // set the state of the quest
  78. _state = state;
  79. }
  80. public String getQuestName()
  81. {
  82. return _questName;
  83. }
  84. /**
  85. * Return the quest
  86. * @return Quest
  87. */
  88. public Quest getQuest()
  89. {
  90. return QuestManager.getInstance().getQuest(_questName);
  91. }
  92. /**
  93. * Return the L2PcInstance
  94. * @return L2PcInstance
  95. */
  96. public L2PcInstance getPlayer()
  97. {
  98. return _player;
  99. }
  100. /**
  101. * Return the state of the quest
  102. * @return State
  103. */
  104. public byte getState()
  105. {
  106. return _state;
  107. }
  108. /**
  109. * Return true if quest completed, false otherwise
  110. * @return boolean
  111. */
  112. public boolean isCompleted()
  113. {
  114. return (getState() == State.COMPLETED);
  115. }
  116. /**
  117. * Return true if quest started, false otherwise
  118. * @return boolean
  119. */
  120. public boolean isStarted()
  121. {
  122. return (getState() == State.STARTED);
  123. }
  124. /**
  125. * Return state of the quest after its initialization.<BR><BR>
  126. * <U><I>Actions :</I></U>
  127. * <LI>Remove drops from previous state</LI>
  128. * <LI>Set new state of the quest</LI>
  129. * <LI>Add drop for new state</LI>
  130. * <LI>Update information in database</LI>
  131. * <LI>Send packet QuestList to client</LI>
  132. * @param state
  133. * @return object
  134. */
  135. public Object setState(byte state)
  136. {
  137. // set new state if it is not already in that state
  138. if (_state != state)
  139. {
  140. _state = state;
  141. Quest.updateQuestInDb(this);
  142. QuestList ql = new QuestList();
  143. getPlayer().sendPacket(ql);
  144. }
  145. return state;
  146. }
  147. /**
  148. * Add parameter used in quests.
  149. * @param var : String pointing out the name of the variable for quest
  150. * @param val : String pointing out the value of the variable for quest
  151. * @return String (equal to parameter "val")
  152. */
  153. String setInternal(String var, String val)
  154. {
  155. if (_vars == null)
  156. _vars = new FastMap<String, String>();
  157. if (val == null)
  158. val = "";
  159. _vars.put(var, val);
  160. return val;
  161. }
  162. /**
  163. * Return value of parameter "val" after adding the couple (var,val) in class variable "vars".<BR><BR>
  164. * <U><I>Actions :</I></U><BR>
  165. * <LI>Initialize class variable "vars" if is null</LI>
  166. * <LI>Initialize parameter "val" if is null</LI>
  167. * <LI>Add/Update couple (var,val) in class variable FastMap "vars"</LI>
  168. * <LI>If the key represented by "var" exists in FastMap "vars", the couple (var,val) is updated in the database. The key is known as
  169. * existing if the preceding value of the key (given as result of function put()) is not null.<BR>
  170. * If the key doesn't exist, the couple is added/created in the database</LI>
  171. * @param var : String indicating the name of the variable for quest
  172. * @param val : String indicating the value of the variable for quest
  173. * @return String (equal to parameter "val")
  174. */
  175. public String set(String var, String val)
  176. {
  177. if (_vars == null)
  178. _vars = new FastMap<String, String>();
  179. if (val == null)
  180. val = "";
  181. // FastMap.put() returns previous value associated with specified key, or null if there was no mapping for key.
  182. String old = _vars.put(var, val);
  183. if (old != null)
  184. Quest.updateQuestVarInDb(this, var, val);
  185. else
  186. Quest.createQuestVarInDb(this, var, val);
  187. if (var == "cond") {
  188. try
  189. {
  190. int previousVal = 0;
  191. try
  192. {
  193. previousVal = Integer.parseInt(old);
  194. }
  195. catch(Exception ex)
  196. {
  197. previousVal = 0;
  198. }
  199. setCond(Integer.parseInt(val), previousVal);
  200. }
  201. catch (Exception e)
  202. {
  203. _log.finer(getPlayer().getName()+", "+getQuestName()+" cond ["+val+"] is not an integer. Value stored, but no packet was sent: " + e);
  204. }
  205. }
  206. return val;
  207. }
  208. /**
  209. * Internally handles the progression of the quest so that it is ready for sending
  210. * appropriate packets to the client<BR><BR>
  211. * <U><I>Actions :</I></U><BR>
  212. * <LI>Check if the new progress number resets the quest to a previous (smaller) step</LI>
  213. * <LI>If not, check if quest progress steps have been skipped</LI>
  214. * <LI>If skipped, prepare the variable completedStateFlags appropriately to be ready for sending to clients</LI>
  215. * <LI>If no steps were skipped, flags do not need to be prepared...</LI>
  216. * <LI>If the passed step resets the quest to a previous step, reset such that steps after the parameter are not
  217. * considered, while skipped steps before the parameter, if any, maintain their info</LI>
  218. * @param cond : int indicating the step number for the current quest progress (as will be shown to the client)
  219. * @param old : int indicating the previously noted step
  220. *
  221. * For more info on the variable communicating the progress steps to the client, please see
  222. * @link net.sf.l2j.loginserver.serverpacket.QuestList
  223. */
  224. private void setCond(int cond, int old)
  225. {
  226. int completedStateFlags = 0; // initializing...
  227. // if there is no change since last setting, there is nothing to do here
  228. if (cond == old)
  229. return;
  230. // cond 0 and 1 do not need completedStateFlags. Also, if cond > 1, the 1st step must
  231. // always exist (i.e. it can never be skipped). So if cond is 2, we can still safely
  232. // assume no steps have been skipped.
  233. // Finally, more than 31 steps CANNOT be supported in any way with skipping.
  234. if (cond < 3 || cond > 31)
  235. {
  236. unset("__compltdStateFlags");
  237. }
  238. else
  239. completedStateFlags = getInt("__compltdStateFlags");
  240. // case 1: No steps have been skipped so far...
  241. if(completedStateFlags == 0)
  242. {
  243. // check if this step also doesn't skip anything. If so, no further work is needed
  244. // also, in this case, no work is needed if the state is being reset to a smaller value
  245. // in those cases, skip forward to informing the client about the change...
  246. // ELSE, if we just now skipped for the first time...prepare the flags!!!
  247. if (cond > (old+1))
  248. {
  249. // set the most significant bit to 1 (indicates that there exist skipped states)
  250. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  251. // what the cond says)
  252. completedStateFlags = 0x80000001;
  253. // since no flag had been skipped until now, the least significant bits must all
  254. // be set to 1, up until "old" number of bits.
  255. completedStateFlags |= ((1<<old)-1);
  256. // now, just set the bit corresponding to the passed cond to 1 (current step)
  257. completedStateFlags |= (1<<(cond-1));
  258. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  259. }
  260. }
  261. // case 2: There were exist previously skipped steps
  262. else
  263. {
  264. // if this is a push back to a previous step, clear all completion flags ahead
  265. if (cond < old)
  266. {
  267. completedStateFlags &= ((1<<cond)-1); // note, this also unsets the flag indicating that there exist skips
  268. //now, check if this resulted in no steps being skipped any more
  269. if ( completedStateFlags == ((1<<cond)-1) )
  270. unset("__compltdStateFlags");
  271. else
  272. {
  273. // set the most significant bit back to 1 again, to correctly indicate that this skips states.
  274. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  275. // what the cond says)
  276. completedStateFlags |= 0x80000001;
  277. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  278. }
  279. }
  280. // if this moves forward, it changes nothing on previously skipped steps...so just mark this
  281. // state and we are done
  282. else
  283. {
  284. completedStateFlags |= (1<<(cond-1));
  285. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  286. }
  287. }
  288. // send a packet to the client to inform it of the quest progress (step change)
  289. QuestList ql = new QuestList();
  290. getPlayer().sendPacket(ql);
  291. int questId = getQuest().getQuestIntId();
  292. if (questId > 0 && questId < 999 && cond > 0)
  293. getPlayer().sendPacket(new ExShowQuestMark(questId));
  294. }
  295. /**
  296. * Remove the variable of quest from the list of variables for the quest.<BR><BR>
  297. * <U><I>Concept : </I></U>
  298. * Remove the variable of quest represented by "var" from the class variable FastMap "vars" and from the database.
  299. * @param var : String designating the variable for the quest to be deleted
  300. * @return String pointing out the previous value associated with the variable "var"
  301. */
  302. public String unset(String var)
  303. {
  304. if (_vars == null)
  305. return null;
  306. String old = _vars.remove(var);
  307. if (old != null)
  308. Quest.deleteQuestVarInDb(this, var);
  309. return old;
  310. }
  311. /**
  312. * Return the value of the variable of quest represented by "var"
  313. * @param var : name of the variable of quest
  314. * @return Object
  315. */
  316. public Object get(String var)
  317. {
  318. if (_vars == null)
  319. return null;
  320. return _vars.get(var);
  321. }
  322. /**
  323. * Return the value of the variable of quest represented by "var"
  324. * @param var : String designating the variable for the quest
  325. * @return int
  326. */
  327. public int getInt(String var)
  328. {
  329. int varint = 0;
  330. try
  331. {
  332. varint = Integer.parseInt(_vars.get(var));
  333. }
  334. catch (Exception e)
  335. {
  336. _log.finer(getPlayer().getName()+": variable "+var+" isn't an integer: " + varint + e);
  337. // if (Config.AUTODELETE_INVALID_QUEST_DATA)
  338. // exitQuest(true);
  339. }
  340. return varint;
  341. }
  342. /**
  343. * Add player to get notification of characters death
  344. * @param character : L2Character of the character to get notification of death
  345. */
  346. public void addNotifyOfDeath(L2Character character)
  347. {
  348. if (character == null)
  349. return;
  350. character.addNotifyQuestOfDeath(this);
  351. }
  352. /**
  353. * Return the quantity of one sort of item hold by the player
  354. * @param itemId : ID of the item wanted to be count
  355. * @return int
  356. */
  357. public int getQuestItemsCount(int itemId)
  358. {
  359. int count = 0;
  360. for (L2ItemInstance item: getPlayer().getInventory().getItems())
  361. if (item.getItemId() == itemId)
  362. count += item.getCount();
  363. return count;
  364. }
  365. /**
  366. * Return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
  367. * @param itemId : ID of the item to check enchantment
  368. * @return int
  369. */
  370. public int getEnchantLevel(int itemId)
  371. {
  372. L2ItemInstance enchanteditem = getPlayer().getInventory().getItemByItemId(itemId);
  373. if (enchanteditem == null)
  374. return 0;
  375. return enchanteditem.getEnchantLevel();
  376. }
  377. /**
  378. * Give item/reward to the player
  379. * @param itemId
  380. * @param count
  381. */
  382. public void giveItems(int itemId, int count)
  383. {
  384. giveItems(itemId, count, 0);
  385. }
  386. public void giveItems(int itemId, int count, int enchantlevel)
  387. {
  388. if (count <= 0)
  389. return;
  390. int questId = getQuest().getQuestIntId();
  391. // If item for reward is gold (ID=57), modify count with rate for quest reward
  392. if (itemId == 57 && !(questId>=217 && questId<=233) && !(questId>=401 && questId<=418) )
  393. count=(int)(count*Config.RATE_QUESTS_REWARD);
  394. // Set quantity of item
  395. // Add items to player's inventory
  396. L2ItemInstance item = getPlayer().getInventory().addItem("Quest", itemId, count, getPlayer(), getPlayer().getTarget());
  397. if (item == null)
  398. return;
  399. if (enchantlevel > 0)
  400. item.setEnchantLevel(enchantlevel);
  401. // If item for reward is gold, send message of gold reward to client
  402. if (itemId == 57)
  403. {
  404. SystemMessage smsg = new SystemMessage(SystemMessageId.EARNED_ADENA);
  405. smsg.addNumber(count);
  406. getPlayer().sendPacket(smsg);
  407. }
  408. // Otherwise, send message of object reward to client
  409. else
  410. {
  411. if (count > 1)
  412. {
  413. SystemMessage smsg = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
  414. smsg.addItemName(item);
  415. smsg.addNumber(count);
  416. getPlayer().sendPacket(smsg);
  417. } else
  418. {
  419. SystemMessage smsg = new SystemMessage(SystemMessageId.EARNED_ITEM);
  420. smsg.addItemName(item);
  421. getPlayer().sendPacket(smsg);
  422. }
  423. }
  424. getPlayer().sendPacket(new ItemList(getPlayer(), false));
  425. StatusUpdate su = new StatusUpdate(getPlayer().getObjectId());
  426. su.addAttribute(StatusUpdate.CUR_LOAD, getPlayer().getCurrentLoad());
  427. getPlayer().sendPacket(su);
  428. }
  429. /**
  430. * Drop Quest item using Config.RATE_DROP_QUEST
  431. * @param itemId : int Item Identifier of the item to be dropped
  432. * @param count(minCount, maxCount) : int Quantity of items to be dropped
  433. * @param neededCount : Quantity of items needed for quest
  434. * @param dropChance : int Base chance of drop, same as in droplist
  435. * @param sound : boolean indicating whether to play sound
  436. * @return boolean indicating whether player has requested number of items
  437. */
  438. public boolean dropQuestItems(int itemId, int count, int neededCount, int dropChance, boolean sound)
  439. {
  440. return dropQuestItems(itemId, count, count, neededCount, dropChance, sound);
  441. }
  442. public boolean dropQuestItems(int itemId, int minCount, int maxCount, int neededCount, int dropChance, boolean sound)
  443. {
  444. dropChance *= Config.RATE_DROP_QUEST / ((getPlayer().getParty() != null) ? getPlayer().getParty().getMemberCount() : 1);
  445. int currentCount = getQuestItemsCount(itemId);
  446. if (neededCount > 0 && currentCount >= neededCount)
  447. return true;
  448. if (currentCount >= neededCount)
  449. return true;
  450. int itemCount = 0;
  451. int random = Rnd.get(L2DropData.MAX_CHANCE);
  452. while (random < dropChance)
  453. {
  454. // Get the item quantity dropped
  455. if (minCount < maxCount)
  456. itemCount += Rnd.get(minCount, maxCount);
  457. else if (minCount == maxCount)
  458. itemCount += minCount;
  459. else
  460. itemCount++;
  461. // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE
  462. dropChance -= L2DropData.MAX_CHANCE;
  463. }
  464. if (itemCount > 0)
  465. {
  466. // if over neededCount, just fill the gap
  467. if (neededCount > 0 && currentCount + itemCount > neededCount)
  468. itemCount = neededCount - currentCount;
  469. // Inventory slot check
  470. if (!getPlayer().getInventory().validateCapacityByItemId(itemId))
  471. return false;
  472. // Give the item to Player
  473. getPlayer().addItem("Quest", itemId, itemCount, getPlayer().getTarget(), true);
  474. if (sound)
  475. playSound((currentCount + itemCount < neededCount) ? "Itemsound.quest_itemget" : "Itemsound.quest_middle");
  476. }
  477. return (neededCount > 0 && currentCount + itemCount >= neededCount);
  478. }
  479. //TODO: More radar functions need to be added when the radar class is complete.
  480. // BEGIN STUFF THAT WILL PROBABLY BE CHANGED
  481. public void addRadar(int x, int y, int z)
  482. {
  483. getPlayer().getRadar().addMarker(x, y, z);
  484. }
  485. public void removeRadar(int x, int y, int z)
  486. {
  487. getPlayer().getRadar().removeMarker(x, y, z);
  488. }
  489. public void clearRadar()
  490. {
  491. getPlayer().getRadar().removeAllMarkers();
  492. }
  493. // END STUFF THAT WILL PROBABLY BE CHANGED
  494. /**
  495. * Remove items from player's inventory when talking to NPC in order to have rewards.<BR><BR>
  496. * <U><I>Actions :</I></U>
  497. * <LI>Destroy quantity of items wanted</LI>
  498. * <LI>Send new inventory list to player</LI>
  499. * @param itemId : Identifier of the item
  500. * @param count : Quantity of items to destroy
  501. */
  502. public void takeItems(int itemId, int count)
  503. {
  504. // Get object item from player's inventory list
  505. L2ItemInstance item = getPlayer().getInventory().getItemByItemId(itemId);
  506. if (item == null)
  507. return;
  508. // Tests on count value in order not to have negative value
  509. if (count < 0 || count > item.getCount())
  510. count = item.getCount();
  511. // Destroy the quantity of items wanted
  512. if (itemId == 57)
  513. getPlayer().reduceAdena("Quest", count, getPlayer(), true);
  514. else
  515. getPlayer().destroyItemByItemId("Quest", itemId, count, getPlayer(), true);
  516. }
  517. /**
  518. * Send a packet in order to play sound at client terminal
  519. * @param sound
  520. */
  521. public void playSound(String sound)
  522. {
  523. getPlayer().sendPacket(new PlaySound(sound));
  524. }
  525. /**
  526. * Add XP and SP as quest reward
  527. * @param exp
  528. * @param sp
  529. */
  530. public void addExpAndSp(int exp, int sp)
  531. {
  532. getPlayer().addExpAndSp((int)getPlayer().calcStat(Stats.EXPSP_RATE, exp * Config.RATE_QUESTS_REWARD, null, null),
  533. (int)getPlayer().calcStat(Stats.EXPSP_RATE, sp * Config.RATE_QUESTS_REWARD, null, null));
  534. }
  535. /**
  536. * Return random value
  537. * @param max : max value for randomisation
  538. * @return int
  539. */
  540. public int getRandom(int max)
  541. {
  542. return Rnd.get(max);
  543. }
  544. /**
  545. * Return number of ticks from GameTimeController
  546. * @return int
  547. */
  548. public int getItemEquipped(int loc)
  549. {
  550. return getPlayer().getInventory().getPaperdollItemId(loc);
  551. }
  552. /**
  553. * Return the number of ticks from the GameTimeController
  554. * @return int
  555. */
  556. public int getGameTicks()
  557. {
  558. return GameTimeController.getGameTicks();
  559. }
  560. /**
  561. * Return true if quest is to exited on clean up by QuestStateManager
  562. * @return boolean
  563. */
  564. public final boolean isExitQuestOnCleanUp()
  565. {
  566. return _isExitQuestOnCleanUp;
  567. }
  568. /**
  569. * Return the QuestTimer object with the specified name
  570. * @return QuestTimer<BR> Return null if name does not exist
  571. */
  572. public void setIsExitQuestOnCleanUp(boolean isExitQuestOnCleanUp)
  573. {
  574. _isExitQuestOnCleanUp = isExitQuestOnCleanUp;
  575. }
  576. /**
  577. * Start a timer for quest.<BR><BR>
  578. * @param name<BR> The name of the timer. Will also be the value for event of onEvent
  579. * @param time<BR> The milisecond value the timer will elapse
  580. */
  581. public void startQuestTimer(String name, long time)
  582. {
  583. getQuest().startQuestTimer(name, time, null, getPlayer(), false);
  584. }
  585. public void startQuestTimer(String name, long time, L2NpcInstance npc)
  586. {
  587. getQuest().startQuestTimer(name, time, npc, getPlayer(), false);
  588. }
  589. public void startRepeatingQuestTimer(String name, long time)
  590. {
  591. getQuest().startQuestTimer(name, time, null, getPlayer(), true);
  592. }
  593. public void startRepeatingQuestTimer(String name, long time, L2NpcInstance npc)
  594. {
  595. getQuest().startQuestTimer(name, time, npc, getPlayer(), true);
  596. }
  597. /**
  598. * Return the QuestTimer object with the specified name
  599. * @return QuestTimer<BR> Return null if name does not exist
  600. */
  601. public final QuestTimer getQuestTimer(String name)
  602. {
  603. return getQuest().getQuestTimer(name, null, getPlayer());
  604. }
  605. /**
  606. * Add spawn for player instance
  607. * Return object id of newly spawned npc
  608. */
  609. public L2NpcInstance addSpawn(int npcId)
  610. {
  611. return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, false, 0);
  612. }
  613. public L2NpcInstance addSpawn(int npcId, int despawnDelay)
  614. {
  615. return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, false, despawnDelay);
  616. }
  617. public L2NpcInstance addSpawn(int npcId, int x, int y, int z)
  618. {
  619. return addSpawn(npcId, x, y, z, 0, false, 0);
  620. }
  621. /**
  622. * Add spawn for player instance
  623. * Will despawn after the spawn length expires
  624. * Uses player's coords and heading.
  625. * Adds a little randomization in the x y coords
  626. * Return object id of newly spawned npc
  627. */
  628. public L2NpcInstance addSpawn(int npcId, L2Character cha)
  629. {
  630. return addSpawn(npcId, cha, true,0);
  631. }
  632. public L2NpcInstance addSpawn(int npcId, L2Character cha, int despawnDelay)
  633. {
  634. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, despawnDelay);
  635. }
  636. /**
  637. * Add spawn for player instance
  638. * Will despawn after the spawn length expires
  639. * Return object id of newly spawned npc
  640. */
  641. public L2NpcInstance addSpawn(int npcId, int x, int y, int z, int despawnDelay)
  642. {
  643. return addSpawn(npcId, x, y, z, 0, false, despawnDelay);
  644. }
  645. /**
  646. * Add spawn for player instance
  647. * Inherits coords and heading from specified L2Character instance.
  648. * It could be either the player, or any killed/attacked mob
  649. * Return object id of newly spawned npc
  650. */
  651. public L2NpcInstance addSpawn(int npcId, L2Character cha, boolean randomOffset, int despawnDelay)
  652. {
  653. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), randomOffset, despawnDelay);
  654. }
  655. /**
  656. * Add spawn for player instance
  657. * Return object id of newly spawned npc
  658. */
  659. public L2NpcInstance addSpawn(int npcId, int x, int y, int z,int heading, boolean randomOffset, int despawnDelay)
  660. {
  661. return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, false);
  662. }
  663. /**
  664. * Add spawn for player instance
  665. * Return object id of newly spawned npc
  666. */
  667. public L2NpcInstance addSpawn(int npcId, int x, int y, int z,int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  668. {
  669. return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn);
  670. }
  671. public String showHtmlFile(String fileName)
  672. {
  673. return getQuest().showHtmlFile(getPlayer(), fileName);
  674. }
  675. /**
  676. * Destroy element used by quest when quest is exited
  677. * @param repeatable
  678. * @return QuestState
  679. */
  680. public QuestState exitQuest(boolean repeatable)
  681. {
  682. if (isCompleted())
  683. return this;
  684. // Say quest is completed
  685. setState(State.COMPLETED);
  686. // Clean registered quest items
  687. int[] itemIdList = getQuest().getRegisteredItemIds();
  688. if (itemIdList != null)
  689. {
  690. for (int i=0; i<itemIdList.length; i++)
  691. {
  692. takeItems(itemIdList[i], -1);
  693. }
  694. }
  695. // If quest is repeatable, delete quest from list of quest of the player and from database (quest CAN be created again => repeatable)
  696. if (repeatable)
  697. {
  698. getPlayer().delQuestState(getQuestName());
  699. Quest.deleteQuestInDb(this);
  700. _vars = null;
  701. }
  702. else
  703. {
  704. // Otherwise, delete variables for quest and update database (quest CANNOT be created again => not repeatable)
  705. if (_vars != null)
  706. for (String var : _vars.keySet())
  707. unset(var);
  708. Quest.updateQuestInDb(this);
  709. }
  710. return this;
  711. }
  712. public void showQuestionMark(int number)
  713. {
  714. getPlayer().sendPacket(new TutorialShowQuestionMark(number));
  715. }
  716. public void playTutorialVoice(String voice)
  717. {
  718. getPlayer().sendPacket(new PlaySound(2, voice, 0, 0, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ()));
  719. }
  720. public void showTutorialHTML(String html)
  721. {
  722. String text = HtmCache.getInstance().getHtm("data/scripts/quests/255_Tutorial/"+ html);
  723. if(text == null)
  724. {
  725. _log.warning("missing html page data/scripts/quests/255_Tutorial/"+html);
  726. text = "<html><body>File data/scripts/quests/255_Tutorial/" + html + " not found or file is empty.</body></html>";
  727. }
  728. getPlayer().sendPacket(new TutorialShowHtml(text));
  729. }
  730. public void closeTutorialHtml()
  731. {
  732. getPlayer().sendPacket(new TutorialCloseHtml());
  733. }
  734. public void onTutorialClientEvent(int number)
  735. {
  736. getPlayer().sendPacket(new TutorialEnableClientEvent(number));
  737. }
  738. public void dropItem(L2MonsterInstance npc, L2PcInstance player, int itemId, int count)
  739. {
  740. npc.dropItem(player, itemId, count);
  741. }
  742. }