QuestState.java 30 KB

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