QuestState.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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.Calendar;
  20. import java.util.Map;
  21. import java.util.logging.Level;
  22. import java.util.logging.Logger;
  23. import javolution.util.FastMap;
  24. import com.l2jserver.L2DatabaseFactory;
  25. import com.l2jserver.gameserver.cache.HtmCache;
  26. import com.l2jserver.gameserver.instancemanager.QuestManager;
  27. import com.l2jserver.gameserver.model.actor.L2Character;
  28. import com.l2jserver.gameserver.model.actor.L2Npc;
  29. import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
  30. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  31. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  32. import com.l2jserver.gameserver.network.serverpackets.ExShowQuestMark;
  33. import com.l2jserver.gameserver.network.serverpackets.PlaySound;
  34. import com.l2jserver.gameserver.network.serverpackets.QuestList;
  35. import com.l2jserver.gameserver.network.serverpackets.TutorialCloseHtml;
  36. import com.l2jserver.gameserver.network.serverpackets.TutorialEnableClientEvent;
  37. import com.l2jserver.gameserver.network.serverpackets.TutorialShowHtml;
  38. import com.l2jserver.gameserver.network.serverpackets.TutorialShowQuestionMark;
  39. import com.l2jserver.gameserver.util.Util;
  40. /**
  41. * @author Luis Arias
  42. */
  43. public final class QuestState
  44. {
  45. protected static final Logger _log = Logger.getLogger(Quest.class.getName());
  46. /** Quest associated to the QuestState */
  47. private final String _questName;
  48. /** Player who engaged the quest */
  49. private final L2PcInstance _player;
  50. /** State of the quest */
  51. private byte _state;
  52. /** List of couples (variable for quest,value of the variable for quest) */
  53. private Map<String, String> _vars;
  54. /** boolean flag letting QuestStateManager know to exit quest when cleaning up */
  55. private boolean _isExitQuestOnCleanUp = false;
  56. /**
  57. * This enumerate represent the different quest types.
  58. */
  59. public static enum QuestType
  60. {
  61. REPEATABLE,
  62. ONE_TIME,
  63. DAILY
  64. }
  65. /**
  66. * Constructor of the QuestState : save the quest in the list of quests of the player.<BR/><BR/>
  67. *
  68. * <U><I>Actions :</U></I><BR/>
  69. * <LI>Save informations in the object QuestState created (Quest, Player, Completion, State)</LI>
  70. * <LI>Add the QuestState in the player's list of quests by using setQuestState()</LI>
  71. * <LI>Add drops gotten by the quest</LI>
  72. * <BR/>
  73. * @param quest : quest associated with the QuestState
  74. * @param player : L2PcInstance pointing out the player
  75. * @param state : state of the quest
  76. */
  77. QuestState(Quest quest, L2PcInstance player, byte state)
  78. {
  79. _questName = quest.getName();
  80. _player = player;
  81. // Save the state of the quest for the player in the player's list of quest onwed
  82. getPlayer().setQuestState(this);
  83. // set the state of the quest
  84. _state = state;
  85. }
  86. public String getQuestName()
  87. {
  88. return _questName;
  89. }
  90. /**
  91. * Return the quest
  92. * @return Quest
  93. */
  94. public Quest getQuest()
  95. {
  96. return QuestManager.getInstance().getQuest(_questName);
  97. }
  98. /**
  99. * Return the L2PcInstance
  100. * @return L2PcInstance
  101. */
  102. public L2PcInstance getPlayer()
  103. {
  104. return _player;
  105. }
  106. /**
  107. * Return the state of the quest
  108. * @return State
  109. */
  110. public byte getState()
  111. {
  112. return _state;
  113. }
  114. /**
  115. * Return true if quest just created, false otherwise
  116. * @return
  117. */
  118. public boolean isCreated()
  119. {
  120. return (getState() == State.CREATED);
  121. }
  122. /**
  123. * Return true if quest completed, false otherwise
  124. * @return boolean
  125. */
  126. public boolean isCompleted()
  127. {
  128. return (getState() == State.COMPLETED);
  129. }
  130. /**
  131. * Return true if quest started, false otherwise
  132. * @return boolean
  133. */
  134. public boolean isStarted()
  135. {
  136. return (getState() == State.STARTED);
  137. }
  138. /**
  139. * Return state of the quest after its initialization.<BR><BR>
  140. * <U><I>Actions :</I></U>
  141. * <LI>Remove drops from previous state</LI>
  142. * <LI>Set new state of the quest</LI>
  143. * <LI>Add drop for new state</LI>
  144. * <LI>Update information in database</LI>
  145. * <LI>Send packet QuestList to client</LI>
  146. * @param state
  147. * @return object
  148. */
  149. public Object setState(byte state)
  150. {
  151. // set new state if it is not already in that state
  152. if (_state != state)
  153. {
  154. final boolean newQuest = isCreated();
  155. _state = state;
  156. if (newQuest)
  157. Quest.createQuestInDb(this);
  158. else
  159. Quest.updateQuestInDb(this);
  160. getPlayer().sendPacket(new QuestList());
  161. }
  162. return state;
  163. }
  164. public Object setStateAndNotSave(byte state)
  165. {
  166. // set new state if it is not already in that state
  167. if (_state != state)
  168. {
  169. _state = state;
  170. getPlayer().sendPacket(new QuestList());
  171. }
  172. return state;
  173. }
  174. /**
  175. * Add parameter used in quests.
  176. * @param var : String pointing out the name of the variable for quest
  177. * @param val : String pointing out the value of the variable for quest
  178. * @return String (equal to parameter "val")
  179. */
  180. public String setInternal(String var, String val)
  181. {
  182. if (_vars == null)
  183. _vars = new FastMap<String, String>();
  184. if (val == null)
  185. val = "";
  186. _vars.put(var, val);
  187. return val;
  188. }
  189. /**
  190. * Return value of parameter "val" after adding the couple (var,val) in class variable "vars".<BR><BR>
  191. * <U><I>Actions :</I></U><BR>
  192. * <LI>Initialize class variable "vars" if is null</LI>
  193. * <LI>Initialize parameter "val" if is null</LI>
  194. * <LI>Add/Update couple (var,val) in class variable FastMap "vars"</LI>
  195. * <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
  196. * existing if the preceding value of the key (given as result of function put()) is not null.<BR>
  197. * If the key doesn't exist, the couple is added/created in the database</LI>
  198. * @param var : String indicating the name of the variable for quest
  199. * @param val : String indicating the value of the variable for quest
  200. * @return String (equal to parameter "val")
  201. */
  202. public String set(String var, String val)
  203. {
  204. if (_vars == null)
  205. _vars = new FastMap<String, String>();
  206. if (val == null)
  207. val = "";
  208. // FastMap.put() returns previous value associated with specified key, or null if there was no mapping for key.
  209. String old = _vars.put(var, val);
  210. if (old != null)
  211. Quest.updateQuestVarInDb(this, var, val);
  212. else
  213. Quest.createQuestVarInDb(this, var, val);
  214. if ("cond".equals(var))
  215. {
  216. try
  217. {
  218. int previousVal = 0;
  219. try
  220. {
  221. previousVal = Integer.parseInt(old);
  222. }
  223. catch (Exception ex)
  224. {
  225. previousVal = 0;
  226. }
  227. setCond(Integer.parseInt(val), previousVal);
  228. }
  229. catch (Exception e)
  230. {
  231. _log.log(Level.WARNING, getPlayer().getName() + ", " + getQuestName() + " cond [" + val + "] is not an integer. Value stored, but no packet was sent: " + e.getMessage(), e);
  232. }
  233. }
  234. return val;
  235. }
  236. /**
  237. * Internally handles the progression of the quest so that it is ready for sending
  238. * appropriate packets to the client<BR><BR>
  239. * <U><I>Actions :</I></U><BR>
  240. * <LI>Check if the new progress number resets the quest to a previous (smaller) step</LI>
  241. * <LI>If not, check if quest progress steps have been skipped</LI>
  242. * <LI>If skipped, prepare the variable completedStateFlags appropriately to be ready for sending to clients</LI>
  243. * <LI>If no steps were skipped, flags do not need to be prepared...</LI>
  244. * <LI>If the passed step resets the quest to a previous step, reset such that steps after the parameter are not
  245. * considered, while skipped steps before the parameter, if any, maintain their info</LI>
  246. * @param cond : int indicating the step number for the current quest progress (as will be shown to the client)
  247. * @param old : int indicating the previously noted step
  248. *
  249. * For more info on the variable communicating the progress steps to the client, please see
  250. */
  251. private void setCond(int cond, int old)
  252. {
  253. int completedStateFlags = 0; // initializing...
  254. // if there is no change since last setting, there is nothing to do here
  255. if (cond == old)
  256. return;
  257. // cond 0 and 1 do not need completedStateFlags. Also, if cond > 1, the 1st step must
  258. // always exist (i.e. it can never be skipped). So if cond is 2, we can still safely
  259. // assume no steps have been skipped.
  260. // Finally, more than 31 steps CANNOT be supported in any way with skipping.
  261. if (cond < 3 || cond > 31)
  262. {
  263. unset("__compltdStateFlags");
  264. }
  265. else
  266. completedStateFlags = getInt("__compltdStateFlags");
  267. // case 1: No steps have been skipped so far...
  268. if (completedStateFlags == 0)
  269. {
  270. // check if this step also doesn't skip anything. If so, no further work is needed
  271. // also, in this case, no work is needed if the state is being reset to a smaller value
  272. // in those cases, skip forward to informing the client about the change...
  273. // ELSE, if we just now skipped for the first time...prepare the flags!!!
  274. if (cond > (old + 1))
  275. {
  276. // set the most significant bit to 1 (indicates that there exist skipped states)
  277. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  278. // what the cond says)
  279. completedStateFlags = 0x80000001;
  280. // since no flag had been skipped until now, the least significant bits must all
  281. // be set to 1, up until "old" number of bits.
  282. completedStateFlags |= ((1 << old) - 1);
  283. // now, just set the bit corresponding to the passed cond to 1 (current step)
  284. completedStateFlags |= (1 << (cond - 1));
  285. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  286. }
  287. }
  288. // case 2: There were exist previously skipped steps
  289. else
  290. {
  291. // if this is a push back to a previous step, clear all completion flags ahead
  292. if (cond < old)
  293. {
  294. completedStateFlags &= ((1 << cond) - 1); // note, this also unsets the flag indicating that there exist skips
  295. //now, check if this resulted in no steps being skipped any more
  296. if (completedStateFlags == ((1 << cond) - 1))
  297. unset("__compltdStateFlags");
  298. else
  299. {
  300. // set the most significant bit back to 1 again, to correctly indicate that this skips states.
  301. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  302. // what the cond says)
  303. completedStateFlags |= 0x80000001;
  304. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  305. }
  306. }
  307. // if this moves forward, it changes nothing on previously skipped steps...so just mark this
  308. // state and we are done
  309. else
  310. {
  311. completedStateFlags |= (1 << (cond - 1));
  312. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  313. }
  314. }
  315. // send a packet to the client to inform it of the quest progress (step change)
  316. QuestList ql = new QuestList();
  317. getPlayer().sendPacket(ql);
  318. int questId = getQuest().getQuestIntId();
  319. if (questId > 0 && questId < 19999 && cond > 0)
  320. getPlayer().sendPacket(new ExShowQuestMark(questId));
  321. }
  322. /**
  323. * Remove the variable of quest from the list of variables for the quest.<BR><BR>
  324. * <U><I>Concept : </I></U>
  325. * Remove the variable of quest represented by "var" from the class variable FastMap "vars" and from the database.
  326. * @param var : String designating the variable for the quest to be deleted
  327. * @return String pointing out the previous value associated with the variable "var"
  328. */
  329. public String unset(String var)
  330. {
  331. if (_vars == null)
  332. return null;
  333. String old = _vars.remove(var);
  334. if (old != null)
  335. Quest.deleteQuestVarInDb(this, var);
  336. return old;
  337. }
  338. /**
  339. * Insert (or Update) in the database variables that need to stay persistant for this player after a reboot.
  340. * This function is for storage of values that do not related to a specific quest but are
  341. * global for all quests. For example, player's can get only once the adena and XP reward for
  342. * the first class quests, but they can make more than one first class quest.
  343. * @param var : String designating the name of the variable for the quest
  344. * @param value : String designating the value of the variable for the quest
  345. */
  346. public final void saveGlobalQuestVar(String var, String value)
  347. {
  348. Connection con = null;
  349. try
  350. {
  351. con = L2DatabaseFactory.getInstance().getConnection();
  352. PreparedStatement statement;
  353. statement = con.prepareStatement("REPLACE INTO character_quest_global_data (charId,var,value) VALUES (?,?,?)");
  354. statement.setInt(1, _player.getObjectId());
  355. statement.setString(2, var);
  356. statement.setString(3, value);
  357. statement.executeUpdate();
  358. statement.close();
  359. }
  360. catch (Exception e)
  361. {
  362. _log.log(Level.WARNING, "Could not insert player's global quest variable: " + e.getMessage(), e);
  363. }
  364. finally
  365. {
  366. L2DatabaseFactory.close(con);
  367. }
  368. }
  369. /**
  370. * Read from the database a previously saved variable for this quest.
  371. * Due to performance considerations, this function should best be used only when the quest is first loaded.
  372. * Subclasses of this class can define structures into which these loaded values can be saved.
  373. * However, on-demand usage of this function throughout the script is not prohibited, only not recommended.
  374. * Values read from this function were entered by calls to "saveGlobalQuestVar"
  375. * @param var : String designating the name of the variable for the quest
  376. * @return String : String representing the loaded value for the passed var, or an empty string if the var was invalid
  377. */
  378. public final String getGlobalQuestVar(String var)
  379. {
  380. String result = "";
  381. Connection con = null;
  382. try
  383. {
  384. con = L2DatabaseFactory.getInstance().getConnection();
  385. PreparedStatement statement;
  386. statement = con.prepareStatement("SELECT value FROM character_quest_global_data WHERE charId = ? AND var = ?");
  387. statement.setInt(1, _player.getObjectId());
  388. statement.setString(2, var);
  389. ResultSet rs = statement.executeQuery();
  390. if (rs.first())
  391. result = rs.getString(1);
  392. rs.close();
  393. statement.close();
  394. }
  395. catch (Exception e)
  396. {
  397. _log.log(Level.WARNING, "Could not load player's global quest variable: " + e.getMessage(), e);
  398. }
  399. finally
  400. {
  401. L2DatabaseFactory.close(con);
  402. }
  403. return result;
  404. }
  405. /**
  406. * Permanently delete from the database one of the player's global quest variable that was previously saved.
  407. * @param var : String designating the name of the variable
  408. */
  409. public final void deleteGlobalQuestVar(String var)
  410. {
  411. Connection con = null;
  412. try
  413. {
  414. con = L2DatabaseFactory.getInstance().getConnection();
  415. PreparedStatement statement;
  416. statement = con.prepareStatement("DELETE FROM character_quest_global_data WHERE charId = ? AND var = ?");
  417. statement.setInt(1, _player.getObjectId());
  418. statement.setString(2, var);
  419. statement.executeUpdate();
  420. statement.close();
  421. }
  422. catch (Exception e)
  423. {
  424. _log.log(Level.WARNING, "could not delete player's global quest variable: " + e.getMessage(), e);
  425. }
  426. finally
  427. {
  428. L2DatabaseFactory.close(con);
  429. }
  430. }
  431. /**
  432. * Return the value of the variable of quest represented by "var"
  433. * @param var : name of the variable of quest
  434. * @return String
  435. */
  436. public String get(String var)
  437. {
  438. if (_vars == null)
  439. return null;
  440. return _vars.get(var);
  441. }
  442. /**
  443. * Return the value of the variable of quest represented by "var"
  444. * @param var : String designating the variable for the quest
  445. * @return int
  446. */
  447. public int getInt(String var)
  448. {
  449. if (_vars == null)
  450. return 0;
  451. final String variable = _vars.get(var);
  452. if (variable == null || variable.length() == 0)
  453. return 0;
  454. int varint = 0;
  455. try
  456. {
  457. varint = Integer.parseInt(variable);
  458. }
  459. catch (Exception e)
  460. {
  461. _log.log(Level.FINER, getPlayer().getName() + ": variable " + var + " isn't an integer: " + varint + " ! " + e.getMessage(), e);
  462. // if (Config.AUTODELETE_INVALID_QUEST_DATA)
  463. // exitQuest(true);
  464. }
  465. return varint;
  466. }
  467. /**
  468. * Add player to get notification of characters death
  469. * @param character : L2Character of the character to get notification of death
  470. */
  471. public void addNotifyOfDeath(L2Character character)
  472. {
  473. if (character == null || !(character instanceof L2PcInstance))
  474. return;
  475. ((L2PcInstance)character).addNotifyQuestOfDeath(this);
  476. }
  477. // TODO: This all remains because of backward compatibility should be cleared when all scripts been re-writen in java!
  478. /**
  479. * Return the quantity of one sort of item hold by the player
  480. * @param itemId : ID of the item wanted to be count
  481. * @return long
  482. */
  483. public long getQuestItemsCount(int itemId)
  484. {
  485. return getQuest().getQuestItemsCount(getPlayer(), itemId);
  486. }
  487. /**
  488. * @param itemId the item Id of the item you're looking for
  489. * @return true if item exists in player's inventory, false - if not
  490. */
  491. public boolean hasQuestItems(int itemId)
  492. {
  493. return getQuest().hasQuestItems(getPlayer(), itemId);
  494. }
  495. /**
  496. * Return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
  497. * @param itemId : ID of the item to check enchantment
  498. * @return int
  499. */
  500. public int getEnchantLevel(int itemId)
  501. {
  502. return getQuest().getEnchantLevel(getPlayer(), itemId);
  503. }
  504. /**
  505. * Give adena to the player
  506. * @param count
  507. * @param applyRates
  508. */
  509. public void giveAdena(long count, boolean applyRates)
  510. {
  511. giveItems(PcInventory.ADENA_ID, count, applyRates ? 0 : 1);
  512. }
  513. /**
  514. * Give reward to player using multiplier's
  515. * @param itemId
  516. * @param count
  517. */
  518. public void rewardItems(int itemId, long count)
  519. {
  520. getQuest().rewardItems(getPlayer(), itemId, count);
  521. }
  522. /**
  523. * Give item/reward to the player
  524. * @param itemId
  525. * @param count
  526. */
  527. public void giveItems(int itemId, long count)
  528. {
  529. giveItems(itemId, count, 0);
  530. }
  531. public void giveItems(int itemId, long count, int enchantlevel)
  532. {
  533. getQuest().giveItems(getPlayer(), itemId, count, enchantlevel);
  534. }
  535. public void giveItems(int itemId, long count, byte attributeId, int attributeLevel)
  536. {
  537. getQuest().giveItems(getPlayer(), itemId, count, attributeId, attributeLevel);
  538. }
  539. /**
  540. * Drop Quest item using Config.RATE_QUEST_DROP
  541. * @param itemId int Item Identifier of the item to be dropped
  542. * @param count (minCount, maxCount) long Quantity of items to be dropped
  543. * @param neededCount Quantity of items needed for quest
  544. * @param dropChance int Base chance of drop, same as in droplist
  545. * @param sound boolean indicating whether to play sound
  546. * @return boolean indicating whether player has requested number of items
  547. */
  548. public boolean dropQuestItems(int itemId, int count, long neededCount, int dropChance, boolean sound)
  549. {
  550. return dropQuestItems(itemId, count, count, neededCount, dropChance, sound);
  551. }
  552. public boolean dropQuestItems(int itemId, int minCount, int maxCount, long neededCount, int dropChance, boolean sound)
  553. {
  554. return getQuest().dropQuestItems(getPlayer(), itemId, minCount, maxCount, neededCount, dropChance, sound);
  555. }
  556. //TODO: More radar functions need to be added when the radar class is complete.
  557. // BEGIN STUFF THAT WILL PROBABLY BE CHANGED
  558. public void addRadar(int x, int y, int z)
  559. {
  560. getPlayer().getRadar().addMarker(x, y, z);
  561. }
  562. public void removeRadar(int x, int y, int z)
  563. {
  564. getPlayer().getRadar().removeMarker(x, y, z);
  565. }
  566. public void clearRadar()
  567. {
  568. getPlayer().getRadar().removeAllMarkers();
  569. }
  570. // END STUFF THAT WILL PROBABLY BE CHANGED
  571. /**
  572. * Remove items from player's inventory when talking to NPC in order to have rewards.<BR><BR>
  573. * <U><I>Actions :</I></U>
  574. * <LI>Destroy quantity of items wanted</LI>
  575. * <LI>Send new inventory list to player</LI>
  576. * @param itemId : Identifier of the item
  577. * @param count : Quantity of items to destroy
  578. */
  579. public void takeItems(int itemId, long count)
  580. {
  581. getQuest().takeItems(getPlayer(), itemId, count);
  582. }
  583. /**
  584. * Send a packet in order to play sound at client terminal
  585. * @param sound
  586. */
  587. public void playSound(String sound)
  588. {
  589. getQuest().playSound(getPlayer(), sound);
  590. }
  591. /**
  592. * Add XP and SP as quest reward
  593. * @param exp
  594. * @param sp
  595. */
  596. public void addExpAndSp(int exp, int sp)
  597. {
  598. getQuest().addExpAndSp(getPlayer(), exp, sp);
  599. }
  600. /**
  601. * @param loc
  602. * @return number of ticks from GameTimeController
  603. */
  604. public int getItemEquipped(int loc)
  605. {
  606. return getQuest().getItemEquipped(getPlayer(), loc);
  607. }
  608. /**
  609. * Return the number of ticks from the GameTimeController
  610. * @return int
  611. */
  612. public int getGameTicks()
  613. {
  614. return getQuest().getGameTicks();
  615. }
  616. /**
  617. * Return true if quest is to exited on clean up by QuestStateManager
  618. * @return boolean
  619. */
  620. public final boolean isExitQuestOnCleanUp()
  621. {
  622. return _isExitQuestOnCleanUp;
  623. }
  624. public void setIsExitQuestOnCleanUp(boolean isExitQuestOnCleanUp)
  625. {
  626. _isExitQuestOnCleanUp = isExitQuestOnCleanUp;
  627. }
  628. /**
  629. * Start a timer for quest.<BR><BR>
  630. * @param name The name of the timer. Will also be the value for event of onEvent
  631. * @param time The milisecond value the timer will elapse
  632. */
  633. public void startQuestTimer(String name, long time)
  634. {
  635. getQuest().startQuestTimer(name, time, null, getPlayer(), false);
  636. }
  637. public void startQuestTimer(String name, long time, L2Npc npc)
  638. {
  639. getQuest().startQuestTimer(name, time, npc, getPlayer(), false);
  640. }
  641. public void startRepeatingQuestTimer(String name, long time)
  642. {
  643. getQuest().startQuestTimer(name, time, null, getPlayer(), true);
  644. }
  645. public void startRepeatingQuestTimer(String name, long time, L2Npc npc)
  646. {
  647. getQuest().startQuestTimer(name, time, npc, getPlayer(), true);
  648. }
  649. /**
  650. * Return the QuestTimer object with the specified name
  651. * @param name
  652. * @return QuestTimer<BR> Return null if name does not exist
  653. */
  654. public final QuestTimer getQuestTimer(String name)
  655. {
  656. return getQuest().getQuestTimer(name, null, getPlayer());
  657. }
  658. /**
  659. * Add spawn for player instance
  660. * @param npcId
  661. * @return object id of newly spawned npc
  662. */
  663. public L2Npc addSpawn(int npcId)
  664. {
  665. return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, false, 0);
  666. }
  667. public L2Npc addSpawn(int npcId, int despawnDelay)
  668. {
  669. return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, false, despawnDelay);
  670. }
  671. public L2Npc addSpawn(int npcId, int x, int y, int z)
  672. {
  673. return addSpawn(npcId, x, y, z, 0, false, 0);
  674. }
  675. /**
  676. * Add spawn for player instance
  677. * Will despawn after the spawn length expires
  678. * Uses player's coords and heading.
  679. * Adds a little randomization in the x y coords
  680. * @param npcId
  681. * @param cha
  682. * @return object id of newly spawned npc
  683. */
  684. public L2Npc addSpawn(int npcId, L2Character cha)
  685. {
  686. return addSpawn(npcId, cha, true, 0);
  687. }
  688. public L2Npc addSpawn(int npcId, L2Character cha, int despawnDelay)
  689. {
  690. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, despawnDelay);
  691. }
  692. /**
  693. * Add spawn for player instance
  694. * Will despawn after the spawn length expires
  695. * @param npcId
  696. * @param x
  697. * @param y
  698. * @param z
  699. * @param despawnDelay
  700. * @return object id of newly spawned npc
  701. */
  702. public L2Npc addSpawn(int npcId, int x, int y, int z, int despawnDelay)
  703. {
  704. return addSpawn(npcId, x, y, z, 0, false, despawnDelay);
  705. }
  706. /**
  707. * Add spawn for player instance
  708. * Inherits coords and heading from specified L2Character instance.
  709. * It could be either the player, or any killed/attacked mob
  710. * @param npcId
  711. * @param cha
  712. * @param randomOffset
  713. * @param despawnDelay
  714. * @return object id of newly spawned npc
  715. */
  716. public L2Npc addSpawn(int npcId, L2Character cha, boolean randomOffset, int despawnDelay)
  717. {
  718. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), randomOffset, despawnDelay);
  719. }
  720. /**
  721. * Add spawn for player instance
  722. * @param npcId
  723. * @param x
  724. * @param y
  725. * @param z
  726. * @param heading
  727. * @param randomOffset
  728. * @param despawnDelay
  729. * @return object id of newly spawned npc
  730. */
  731. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay)
  732. {
  733. return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, false);
  734. }
  735. /**
  736. * Add spawn for player instance
  737. * @param npcId
  738. * @param x
  739. * @param y
  740. * @param z
  741. * @param heading
  742. * @param randomOffset
  743. * @param despawnDelay
  744. * @param isSummonSpawn
  745. * @return object id of newly spawned npc
  746. */
  747. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  748. {
  749. return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn);
  750. }
  751. public String showHtmlFile(String fileName)
  752. {
  753. return getQuest().showHtmlFile(getPlayer(), fileName);
  754. }
  755. /**
  756. * @param type the type of the quest, {@link com.l2jserver.gameserver.model.quest.QuestState.QuestType}.
  757. * @return this quest state.
  758. */
  759. public QuestState exitQuest(QuestType type)
  760. {
  761. switch (type)
  762. {
  763. case REPEATABLE:
  764. case ONE_TIME:
  765. {
  766. exitQuest(type == QuestType.REPEATABLE);
  767. break;
  768. }
  769. case DAILY:
  770. {
  771. exitQuest(false);
  772. setRestartTime();
  773. break;
  774. }
  775. }
  776. return this;
  777. }
  778. /**
  779. * Destroy element used by quest when quest is exited
  780. * @param repeatable
  781. * @return QuestState
  782. */
  783. public QuestState exitQuest(boolean repeatable)
  784. {
  785. // remove this quest from the notifyDeath list of this character if its on this list
  786. _player.removeNotifyQuestOfDeath(this);
  787. if (isCompleted() || isCreated())
  788. return this;
  789. // Say quest is completed
  790. setState(State.COMPLETED);
  791. // Clean registered quest items
  792. int[] itemIdList = getQuest().getRegisteredItemIds();
  793. if (itemIdList != null)
  794. {
  795. for (int i = 0; i < itemIdList.length; i++)
  796. takeItems(itemIdList[i], -1);
  797. }
  798. // If quest is repeatable, delete quest from list of quest of the player and from database (quest CAN be created again => repeatable)
  799. if (repeatable)
  800. {
  801. getPlayer().delQuestState(getQuestName());
  802. Quest.deleteQuestInDb(this);
  803. _vars = null;
  804. }
  805. else
  806. {
  807. // Otherwise, delete variables for quest and update database (quest CANNOT be created again => not repeatable)
  808. if (_vars != null)
  809. {
  810. for (String var : _vars.keySet())
  811. unset(var);
  812. }
  813. Quest.updateQuestInDb(this);
  814. }
  815. return this;
  816. }
  817. public void showQuestionMark(int number)
  818. {
  819. getPlayer().sendPacket(new TutorialShowQuestionMark(number));
  820. }
  821. public void playTutorialVoice(String voice)
  822. {
  823. getPlayer().sendPacket(new PlaySound(2, voice, 0, 0, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ()));
  824. }
  825. public void showTutorialHTML(String html)
  826. {
  827. String text = HtmCache.getInstance().getHtm(getPlayer().getHtmlPrefix(), "data/scripts/quests/255_Tutorial/" + html);
  828. if (text == null)
  829. {
  830. _log.warning("missing html page data/scripts/quests/255_Tutorial/" + html);
  831. text = "<html><body>File data/scripts/quests/255_Tutorial/" + html + " not found or file is empty.</body></html>";
  832. }
  833. getPlayer().sendPacket(new TutorialShowHtml(text));
  834. }
  835. public void closeTutorialHtml()
  836. {
  837. getPlayer().sendPacket(new TutorialCloseHtml());
  838. }
  839. public void onTutorialClientEvent(int number)
  840. {
  841. getPlayer().sendPacket(new TutorialEnableClientEvent(number));
  842. }
  843. public void dropItem(L2MonsterInstance npc, L2PcInstance player, int itemId, int count)
  844. {
  845. npc.dropItem(player, itemId, count);
  846. }
  847. /**
  848. * Set the restart time for the daily quests.<br>
  849. * The time is hardcoded at {@link Quest#getResetHour()} hours, {@link Quest#getResetMinutes()} minutes of the following day.<br>
  850. * It can be overridden in scripts (quests).
  851. */
  852. public void setRestartTime()
  853. {
  854. final Calendar reDo = Calendar.getInstance();
  855. if (reDo.get(Calendar.HOUR_OF_DAY) >= getQuest().getResetHour())
  856. {
  857. reDo.add(Calendar.DATE, 1);
  858. }
  859. reDo.set(Calendar.HOUR_OF_DAY, getQuest().getResetHour());
  860. reDo.set(Calendar.MINUTE, getQuest().getResetMinutes());
  861. set("restartTime", String.valueOf(reDo.getTimeInMillis()));
  862. }
  863. /**
  864. * @return {@code true} if the quest is available, for example daily quests, {@code false} otherwise.
  865. */
  866. public boolean isNowAvailable()
  867. {
  868. final String val = get("restartTime");
  869. return ((val == null) || !Util.isDigit(val)) || (Long.parseLong(val) <= System.currentTimeMillis());
  870. }
  871. }