QuestState.java 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. /*
  2. * Copyright (C) 2004-2013 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J Server is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.l2jserver.gameserver.model.quest;
  20. import java.sql.Connection;
  21. import java.sql.PreparedStatement;
  22. import java.sql.ResultSet;
  23. import java.util.Calendar;
  24. import java.util.HashMap;
  25. import java.util.Map;
  26. import java.util.logging.Level;
  27. import java.util.logging.Logger;
  28. import com.l2jserver.L2DatabaseFactory;
  29. import com.l2jserver.gameserver.cache.HtmCache;
  30. import com.l2jserver.gameserver.instancemanager.QuestManager;
  31. import com.l2jserver.gameserver.model.actor.L2Character;
  32. import com.l2jserver.gameserver.model.actor.L2Npc;
  33. import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
  34. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  35. import com.l2jserver.gameserver.model.holders.ItemHolder;
  36. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  37. import com.l2jserver.gameserver.model.quest.Quest.QuestSound;
  38. import com.l2jserver.gameserver.network.serverpackets.ExShowQuestMark;
  39. import com.l2jserver.gameserver.network.serverpackets.PlaySound;
  40. import com.l2jserver.gameserver.network.serverpackets.QuestList;
  41. import com.l2jserver.gameserver.network.serverpackets.TutorialCloseHtml;
  42. import com.l2jserver.gameserver.network.serverpackets.TutorialEnableClientEvent;
  43. import com.l2jserver.gameserver.network.serverpackets.TutorialShowHtml;
  44. import com.l2jserver.gameserver.network.serverpackets.TutorialShowQuestionMark;
  45. import com.l2jserver.gameserver.util.Util;
  46. /**
  47. * Quest state class.
  48. * @author Luis Arias
  49. */
  50. public final class QuestState
  51. {
  52. protected static final Logger _log = Logger.getLogger(QuestState.class.getName());
  53. /** The name of the quest of this QuestState */
  54. private final String _questName;
  55. /** The "owner" of this QuestState object */
  56. private final L2PcInstance _player;
  57. /** The current state of the quest */
  58. private byte _state;
  59. /** A map of key->value pairs containing the quest state variables and their values */
  60. private Map<String, String> _vars;
  61. /**
  62. * boolean flag letting QuestStateManager know to exit quest when cleaning up
  63. */
  64. private boolean _isExitQuestOnCleanUp = false;
  65. /**
  66. * This enumerate represent the different quest types.
  67. */
  68. public static enum QuestType
  69. {
  70. REPEATABLE,
  71. ONE_TIME,
  72. DAILY
  73. }
  74. /**
  75. * Constructor of the QuestState. Creates the QuestState object and sets the player's progress of the quest to this QuestState.
  76. * @param quest the {@link Quest} object associated with the QuestState
  77. * @param player the owner of this {@link QuestState} object
  78. * @param state the initial state of the quest
  79. */
  80. public QuestState(Quest quest, L2PcInstance player, byte state)
  81. {
  82. _questName = quest.getName();
  83. _player = player;
  84. _state = state;
  85. player.setQuestState(this);
  86. }
  87. /**
  88. * @return the name of the quest of this QuestState
  89. */
  90. public String getQuestName()
  91. {
  92. return _questName;
  93. }
  94. /**
  95. * @return the {@link Quest} object of this QuestState
  96. */
  97. public Quest getQuest()
  98. {
  99. return QuestManager.getInstance().getQuest(_questName);
  100. }
  101. /**
  102. * @return the {@link L2PcInstance} object of the owner of this QuestState
  103. */
  104. public L2PcInstance getPlayer()
  105. {
  106. return _player;
  107. }
  108. /**
  109. * @return the current State of this QuestState
  110. */
  111. public byte getState()
  112. {
  113. return _state;
  114. }
  115. /**
  116. * @return {@code true} if the State of this QuestState is CREATED, {@code false} otherwise
  117. */
  118. public boolean isCreated()
  119. {
  120. return (_state == State.CREATED);
  121. }
  122. /**
  123. * @return {@code true} if the State of this QuestState is STARTED, {@code false} otherwise
  124. */
  125. public boolean isStarted()
  126. {
  127. return (_state == State.STARTED);
  128. }
  129. /**
  130. * @return {@code true} if the State of this QuestState is COMPLETED, {@code false} otherwise
  131. */
  132. public boolean isCompleted()
  133. {
  134. return (_state == State.COMPLETED);
  135. }
  136. /**
  137. * @param state the new state of the quest to set
  138. * @return {@code true} if state was changed, {@code false} otherwise
  139. * @see #setState(byte state, boolean saveInDb)
  140. */
  141. public boolean setState(byte state)
  142. {
  143. return setState(state, true);
  144. }
  145. /**
  146. * Change the state of this quest to the specified value.
  147. * @param state the new state of the quest to set
  148. * @param saveInDb if {@code true}, will save the state change in the database
  149. * @return {@code true} if state was changed, {@code false} otherwise
  150. */
  151. public boolean setState(byte state, boolean saveInDb)
  152. {
  153. if (_state == state)
  154. {
  155. return false;
  156. }
  157. final boolean newQuest = isCreated();
  158. _state = state;
  159. if (saveInDb)
  160. {
  161. if (newQuest)
  162. {
  163. Quest.createQuestInDb(this);
  164. }
  165. else
  166. {
  167. Quest.updateQuestInDb(this);
  168. }
  169. }
  170. _player.sendPacket(new QuestList());
  171. return true;
  172. }
  173. /**
  174. * Add parameter used in quests.
  175. * @param var String pointing out the name of the variable for quest
  176. * @param val String pointing out the value of the variable for quest
  177. * @return String (equal to parameter "val")
  178. */
  179. public String setInternal(String var, String val)
  180. {
  181. if (_vars == null)
  182. {
  183. _vars = new HashMap<>();
  184. }
  185. if (val == null)
  186. {
  187. val = "";
  188. }
  189. _vars.put(var, val);
  190. return val;
  191. }
  192. public String set(String var, int val)
  193. {
  194. return set(var, String.valueOf(val));
  195. }
  196. /**
  197. * Return value of parameter "val" after adding the couple (var,val) in class variable "vars".<br>
  198. * Actions:<br>
  199. * <ul>
  200. * <li>Initialize class variable "vars" if is null.</li>
  201. * <li>Initialize parameter "val" if is null</li>
  202. * <li>Add/Update couple (var,val) in class variable FastMap "vars"</li>
  203. * <li>If the key represented by "var" exists in FastMap "vars", the couple (var,val) is updated in the database.<br>
  204. * The key is known as existing if the preceding value of the key (given as result of function put()) is not null.<br>
  205. * If the key doesn't exist, the couple is added/created in the database</li>
  206. * <ul>
  207. * @param var String indicating the name of the variable for quest
  208. * @param val String indicating the value of the variable for quest
  209. * @return String (equal to parameter "val")
  210. */
  211. public String set(String var, String val)
  212. {
  213. if (_vars == null)
  214. {
  215. _vars = new HashMap<>();
  216. }
  217. if (val == null)
  218. {
  219. val = "";
  220. }
  221. String old = _vars.put(var, val);
  222. if (old != null)
  223. {
  224. Quest.updateQuestVarInDb(this, var, val);
  225. }
  226. else
  227. {
  228. Quest.createQuestVarInDb(this, var, val);
  229. }
  230. if ("cond".equals(var))
  231. {
  232. try
  233. {
  234. int previousVal = 0;
  235. try
  236. {
  237. previousVal = Integer.parseInt(old);
  238. }
  239. catch (Exception ex)
  240. {
  241. previousVal = 0;
  242. }
  243. setCond(Integer.parseInt(val), previousVal);
  244. }
  245. catch (Exception e)
  246. {
  247. _log.log(Level.WARNING, _player.getName() + ", " + getQuestName() + " cond [" + val + "] is not an integer. Value stored, but no packet was sent: " + e.getMessage(), e);
  248. }
  249. }
  250. return val;
  251. }
  252. /**
  253. * Internally handles the progression of the quest so that it is ready for sending appropriate packets to the client.<br>
  254. * <u><i>Actions :</i></u><br>
  255. * <ul>
  256. * <li>Check if the new progress number resets the quest to a previous (smaller) step.</li>
  257. * <li>If not, check if quest progress steps have been skipped.</li>
  258. * <li>If skipped, prepare the variable completedStateFlags appropriately to be ready for sending to clients.</li>
  259. * <li>If no steps were skipped, flags do not need to be prepared...</li>
  260. * <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>
  261. * </ul>
  262. * @param cond the current quest progress condition (0 - 31 including)
  263. * @param old the previous quest progress condition to check against
  264. */
  265. private void setCond(int cond, int old)
  266. {
  267. if (cond == old)
  268. {
  269. return;
  270. }
  271. int completedStateFlags = 0;
  272. // cond 0 and 1 do not need completedStateFlags. Also, if cond > 1, the 1st step must
  273. // always exist (i.e. it can never be skipped). So if cond is 2, we can still safely
  274. // assume no steps have been skipped.
  275. // Finally, more than 31 steps CANNOT be supported in any way with skipping.
  276. if ((cond < 3) || (cond > 31))
  277. {
  278. unset("__compltdStateFlags");
  279. }
  280. else
  281. {
  282. completedStateFlags = getInt("__compltdStateFlags");
  283. }
  284. // case 1: No steps have been skipped so far...
  285. if (completedStateFlags == 0)
  286. {
  287. // check if this step also doesn't skip anything. If so, no further work is needed
  288. // also, in this case, no work is needed if the state is being reset to a smaller value
  289. // in those cases, skip forward to informing the client about the change...
  290. // ELSE, if we just now skipped for the first time...prepare the flags!!!
  291. if (cond > (old + 1))
  292. {
  293. // set the most significant bit to 1 (indicates that there exist skipped states)
  294. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  295. // what the cond says)
  296. completedStateFlags = 0x80000001;
  297. // since no flag had been skipped until now, the least significant bits must all
  298. // be set to 1, up until "old" number of bits.
  299. completedStateFlags |= ((1 << old) - 1);
  300. // now, just set the bit corresponding to the passed cond to 1 (current step)
  301. completedStateFlags |= (1 << (cond - 1));
  302. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  303. }
  304. }
  305. // case 2: There were exist previously skipped steps
  306. // if this is a push back to a previous step, clear all completion flags ahead
  307. else if (cond < old)
  308. {
  309. // note, this also unsets the flag indicating that there exist skips
  310. completedStateFlags &= ((1 << cond) - 1);
  311. // now, check if this resulted in no steps being skipped any more
  312. if (completedStateFlags == ((1 << cond) - 1))
  313. {
  314. unset("__compltdStateFlags");
  315. }
  316. else
  317. {
  318. // set the most significant bit back to 1 again, to correctly indicate that this skips states.
  319. // also, ensure that the least significant bit is an 1 (the first step is never skipped, no matter
  320. // what the cond says)
  321. completedStateFlags |= 0x80000001;
  322. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  323. }
  324. }
  325. // If this moves forward, it changes nothing on previously skipped steps.
  326. // Just mark this state and we are done.
  327. else
  328. {
  329. completedStateFlags |= (1 << (cond - 1));
  330. set("__compltdStateFlags", String.valueOf(completedStateFlags));
  331. }
  332. // send a packet to the client to inform it of the quest progress (step change)
  333. _player.sendPacket(new QuestList());
  334. final Quest q = getQuest();
  335. if (!q.isCustomQuest() && (cond > 0))
  336. {
  337. _player.sendPacket(new ExShowQuestMark(q.getQuestIntId()));
  338. }
  339. }
  340. /**
  341. * Removes a quest variable from the list of existing quest variables.
  342. * @param var the name of the variable to remove
  343. * @return the previous value of the variable or {@code null} if none were found
  344. */
  345. public String unset(String var)
  346. {
  347. if (_vars == null)
  348. {
  349. return null;
  350. }
  351. String old = _vars.remove(var);
  352. if (old != null)
  353. {
  354. Quest.deleteQuestVarInDb(this, var);
  355. }
  356. return old;
  357. }
  358. /**
  359. * Insert (or update) in the database variables that need to stay persistent for this player after a reboot. This function is for storage of values that are not related to a specific quest but are global instead, i.e. can be used by any script.
  360. * @param var the name of the variable to save
  361. * @param value the value of the variable
  362. */
  363. // TODO: these methods should not be here, they could be used by other classes to save some variables, but they can't because they require to create a QuestState first.
  364. public final void saveGlobalQuestVar(String var, String value)
  365. {
  366. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  367. PreparedStatement statement = con.prepareStatement("REPLACE INTO character_quest_global_data (charId, var, value) VALUES (?, ?, ?)"))
  368. {
  369. statement.setInt(1, _player.getObjectId());
  370. statement.setString(2, var);
  371. statement.setString(3, value);
  372. statement.executeUpdate();
  373. }
  374. catch (Exception e)
  375. {
  376. _log.log(Level.WARNING, "Could not insert player's global quest variable: " + e.getMessage(), e);
  377. }
  378. }
  379. /**
  380. * Read from the database a previously saved variable for this quest.<br>
  381. * Due to performance considerations, this function should best be used only when the quest is first loaded.<br>
  382. * Subclasses of this class can define structures into which these loaded values can be saved.<br>
  383. * However, on-demand usage of this function throughout the script is not prohibited, only not recommended.<br>
  384. * Values read from this function were entered by calls to "saveGlobalQuestVar".
  385. * @param var the name of the variable whose value to get
  386. * @return the value of the variable or an empty string if the variable does not exist in the database
  387. */
  388. // TODO: these methods should not be here, they could be used by other classes to save some variables, but they can't because they require to create a QuestState first.
  389. public final String getGlobalQuestVar(String var)
  390. {
  391. String result = "";
  392. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  393. PreparedStatement ps = con.prepareStatement("SELECT value FROM character_quest_global_data WHERE charId = ? AND var = ?"))
  394. {
  395. ps.setInt(1, _player.getObjectId());
  396. ps.setString(2, var);
  397. try (ResultSet rs = ps.executeQuery())
  398. {
  399. if (rs.first())
  400. {
  401. result = rs.getString(1);
  402. }
  403. }
  404. }
  405. catch (Exception e)
  406. {
  407. _log.log(Level.WARNING, "Could not load player's global quest variable: " + e.getMessage(), e);
  408. }
  409. return result;
  410. }
  411. /**
  412. * Permanently delete a global quest variable from the database.
  413. * @param var the name of the variable to delete
  414. */
  415. public final void deleteGlobalQuestVar(String var)
  416. {
  417. try (Connection con = L2DatabaseFactory.getInstance().getConnection();
  418. PreparedStatement statement = con.prepareStatement("DELETE FROM character_quest_global_data WHERE charId = ? AND var = ?"))
  419. {
  420. statement.setInt(1, _player.getObjectId());
  421. statement.setString(2, var);
  422. statement.executeUpdate();
  423. }
  424. catch (Exception e)
  425. {
  426. _log.log(Level.WARNING, "could not delete player's global quest variable; charId = " + _player.getObjectId() + ", variable name = " + var + ". Exception: " + e.getMessage(), e);
  427. }
  428. }
  429. /**
  430. * @param var the name of the variable to get
  431. * @return the value of the variable from the list of quest variables
  432. */
  433. public String get(String var)
  434. {
  435. if (_vars == null)
  436. {
  437. return null;
  438. }
  439. return _vars.get(var);
  440. }
  441. /**
  442. * @param var the name of the variable to get
  443. * @return the integer value of the variable or 0 if the variable does not exist or its value is not an integer
  444. */
  445. public int getInt(String var)
  446. {
  447. if (_vars == null)
  448. {
  449. return 0;
  450. }
  451. final String variable = _vars.get(var);
  452. if ((variable == null) || variable.isEmpty())
  453. {
  454. return 0;
  455. }
  456. int varint = 0;
  457. try
  458. {
  459. varint = Integer.parseInt(variable);
  460. }
  461. catch (NumberFormatException nfe)
  462. {
  463. _log.log(Level.INFO, "Quest " + getQuestName() + ", method getInt(" + var + "), tried to parse a non-integer value (" + variable + "). Char Id: " + _player.getObjectId(), nfe);
  464. }
  465. return varint;
  466. }
  467. /**
  468. * Checks if the quest state progress ({@code cond}) is at the specified step.
  469. * @param condition the condition to check against
  470. * @return {@code true} if the quest condition is equal to {@code condition}, {@code false} otherwise
  471. * @see #getInt(String var)
  472. */
  473. public boolean isCond(int condition)
  474. {
  475. return (getInt("cond") == condition);
  476. }
  477. /**
  478. * Sets the quest state progress ({@code cond}) to the specified step.
  479. * @param value the new value of the quest state progress
  480. * @return this {@link QuestState} object
  481. * @see #set(String var, String val)
  482. * @see #setCond(int, boolean)
  483. */
  484. public QuestState setCond(int value)
  485. {
  486. if (isStarted())
  487. {
  488. set("cond", String.valueOf(value));
  489. }
  490. return this;
  491. }
  492. /**
  493. * @return the current quest progress ({@code cond})
  494. */
  495. public int getCond()
  496. {
  497. if (isStarted())
  498. {
  499. return getInt("cond");
  500. }
  501. return 0;
  502. }
  503. /**
  504. * Check if a given variable is set for this quest.
  505. * @param variable the variable to check
  506. * @return {@code true} if the variable is set, {@code false} otherwise
  507. * @see #get(String)
  508. * @see #getInt(String)
  509. * @see #getCond()
  510. */
  511. public boolean isSet(String variable)
  512. {
  513. return (get(variable) != null);
  514. }
  515. /**
  516. * Sets the quest state progress ({@code cond}) to the specified step.
  517. * @param value the new value of the quest state progress
  518. * @param playQuestMiddle if {@code true}, plays "ItemSound.quest_middle"
  519. * @return this {@link QuestState} object
  520. * @see #setCond(int value)
  521. * @see #set(String var, String val)
  522. */
  523. public QuestState setCond(int value, boolean playQuestMiddle)
  524. {
  525. if (!isStarted())
  526. {
  527. return this;
  528. }
  529. set("cond", String.valueOf(value));
  530. if (playQuestMiddle)
  531. {
  532. playSound(QuestSound.ITEMSOUND_QUEST_MIDDLE);
  533. }
  534. return this;
  535. }
  536. /**
  537. * Add player to get notification of characters death
  538. * @param character the {@link L2Character} object of the character to get notification of death
  539. */
  540. public void addNotifyOfDeath(L2Character character)
  541. {
  542. if (!(character instanceof L2PcInstance))
  543. {
  544. return;
  545. }
  546. ((L2PcInstance) character).addNotifyQuestOfDeath(this);
  547. }
  548. // TODO: This all remains because of backward compatibility, should be cleared when all scripts are rewritten in java
  549. /**
  550. * Return the quantity of one sort of item hold by the player
  551. * @param itemId the Id of the item wanted to be count
  552. * @return long
  553. */
  554. public long getQuestItemsCount(int itemId)
  555. {
  556. return Quest.getQuestItemsCount(getPlayer(), itemId);
  557. }
  558. /**
  559. * @param itemId the Id of the item required
  560. * @return true if item exists in player's inventory, false - if not
  561. */
  562. public boolean hasQuestItems(int itemId)
  563. {
  564. return Quest.hasQuestItems(getPlayer(), itemId);
  565. }
  566. /**
  567. * @param itemIds list of items that are required
  568. * @return true if all items exists in player's inventory, false - if not
  569. */
  570. public boolean hasQuestItems(int... itemIds)
  571. {
  572. return Quest.hasQuestItems(getPlayer(), itemIds);
  573. }
  574. /**
  575. * Return the level of enchantment on the weapon of the player(Done specifically for weapon SA's)
  576. * @param itemId Id of the item to check enchantment
  577. * @return int
  578. */
  579. public int getEnchantLevel(int itemId)
  580. {
  581. return Quest.getEnchantLevel(getPlayer(), itemId);
  582. }
  583. /**
  584. * Give adena to the player
  585. * @param count
  586. * @param applyRates
  587. */
  588. public void giveAdena(long count, boolean applyRates)
  589. {
  590. giveItems(PcInventory.ADENA_ID, count, applyRates ? 0 : 1);
  591. }
  592. /**
  593. * Give reward to player using multiplier's
  594. * @param itemId
  595. * @param count
  596. */
  597. public void rewardItems(int itemId, long count)
  598. {
  599. Quest.rewardItems(getPlayer(), itemId, count);
  600. }
  601. /**
  602. * Give item/reward to the player
  603. * @param itemId
  604. * @param count
  605. */
  606. public void giveItems(int itemId, long count)
  607. {
  608. giveItems(itemId, count, 0);
  609. }
  610. public void giveItems(ItemHolder holder)
  611. {
  612. giveItems(holder.getId(), holder.getCount(), 0);
  613. }
  614. public void giveItems(int itemId, long count, int enchantlevel)
  615. {
  616. Quest.giveItems(getPlayer(), itemId, count, enchantlevel);
  617. }
  618. public void giveItems(int itemId, long count, byte attributeId, int attributeLevel)
  619. {
  620. Quest.giveItems(getPlayer(), itemId, count, attributeId, attributeLevel);
  621. }
  622. /**
  623. * Drop Quest item using Config.RATE_QUEST_DROP
  624. * @param itemId int Item Identifier of the item to be dropped
  625. * @param count (minCount, maxCount) long Quantity of items to be dropped
  626. * @param neededCount Quantity of items needed for quest
  627. * @param dropChance int Base chance of drop, same as in droplist
  628. * @param sound boolean indicating whether to play sound
  629. * @return boolean indicating whether player has requested number of items
  630. */
  631. public boolean dropQuestItems(int itemId, int count, long neededCount, int dropChance, boolean sound)
  632. {
  633. return dropQuestItems(itemId, count, count, neededCount, dropChance, sound);
  634. }
  635. public boolean dropQuestItems(int itemId, int minCount, int maxCount, long neededCount, int dropChance, boolean sound)
  636. {
  637. return Quest.dropQuestItems(getPlayer(), itemId, minCount, maxCount, neededCount, dropChance, sound);
  638. }
  639. // TODO: More radar functions need to be added when the radar class is complete.
  640. // BEGIN STUFF THAT WILL PROBABLY BE CHANGED
  641. public void addRadar(int x, int y, int z)
  642. {
  643. _player.getRadar().addMarker(x, y, z);
  644. }
  645. public void removeRadar(int x, int y, int z)
  646. {
  647. _player.getRadar().removeMarker(x, y, z);
  648. }
  649. public void clearRadar()
  650. {
  651. _player.getRadar().removeAllMarkers();
  652. }
  653. // END STUFF THAT WILL PROBABLY BE CHANGED
  654. /**
  655. * Remove items from player's inventory when talking to NPC in order to have rewards.<br>
  656. * Actions:<br>
  657. * <ul>
  658. * <li>Destroy quantity of items wanted</li>
  659. * <li>Send new inventory list to player</li>
  660. * </ul>
  661. * @param itemId Identifier of the item
  662. * @param count Quantity of items to destroy
  663. */
  664. public void takeItems(int itemId, long count)
  665. {
  666. Quest.takeItems(getPlayer(), itemId, count);
  667. }
  668. /**
  669. * Send a packet in order to play a sound to the player.
  670. * @param sound the name of the sound to play
  671. */
  672. public void playSound(String sound)
  673. {
  674. Quest.playSound(getPlayer(), sound);
  675. }
  676. /**
  677. * Send a packet in order to play a sound to the player.
  678. * @param sound the {@link QuestSound} object of the sound to play
  679. */
  680. public void playSound(QuestSound sound)
  681. {
  682. Quest.playSound(getPlayer(), sound);
  683. }
  684. /**
  685. * Add XP and SP as quest reward
  686. * @param exp
  687. * @param sp
  688. */
  689. public void addExpAndSp(int exp, int sp)
  690. {
  691. Quest.addExpAndSp(getPlayer(), exp, sp);
  692. }
  693. /**
  694. * @param loc
  695. * @return number of ticks from GameTimeController
  696. */
  697. public int getItemEquipped(int loc)
  698. {
  699. return Quest.getItemEquipped(getPlayer(), loc);
  700. }
  701. /**
  702. * @return {@code true} if quest is to be exited on clean up by QuestStateManager, {@code false} otherwise
  703. */
  704. public final boolean isExitQuestOnCleanUp()
  705. {
  706. return _isExitQuestOnCleanUp;
  707. }
  708. /**
  709. * @param isExitQuestOnCleanUp {@code true} if quest is to be exited on clean up by QuestStateManager, {@code false} otherwise
  710. */
  711. public void setIsExitQuestOnCleanUp(boolean isExitQuestOnCleanUp)
  712. {
  713. _isExitQuestOnCleanUp = isExitQuestOnCleanUp;
  714. }
  715. /**
  716. * Start a timed event for a quest.<br>
  717. * Will call an event in onEvent/onAdvEvent.
  718. * @param name the name of the timer/event
  719. * @param time time in milliseconds till the event is executed
  720. */
  721. public void startQuestTimer(String name, long time)
  722. {
  723. getQuest().startQuestTimer(name, time, null, getPlayer(), false);
  724. }
  725. /**
  726. * Start a timed event for a quest.<br>
  727. * Will call an event in onEvent/onAdvEvent.
  728. * @param name the name of the timer/event
  729. * @param time time in milliseconds till the event is executed
  730. * @param npc the L2Npc associated with this event
  731. */
  732. public void startQuestTimer(String name, long time, L2Npc npc)
  733. {
  734. getQuest().startQuestTimer(name, time, npc, getPlayer(), false);
  735. }
  736. /**
  737. * Start a repeating timed event for a quest.<br>
  738. * Will call an event in onEvent/onAdvEvent.
  739. * @param name the name of the timer/event
  740. * @param time time in milliseconds till the event is executed/repeated
  741. */
  742. public void startRepeatingQuestTimer(String name, long time)
  743. {
  744. getQuest().startQuestTimer(name, time, null, getPlayer(), true);
  745. }
  746. /**
  747. * Start a repeating timed event for a quest.<br>
  748. * Will call an event in onEvent/onAdvEvent.
  749. * @param name the name of the timer/event
  750. * @param time time in milliseconds till the event is executed/repeated
  751. * @param npc the L2Npc associated with this event
  752. */
  753. public void startRepeatingQuestTimer(String name, long time, L2Npc npc)
  754. {
  755. getQuest().startQuestTimer(name, time, npc, getPlayer(), true);
  756. }
  757. /**
  758. * @param name the name of the QuestTimer required
  759. * @return the {@link QuestTimer} object with the specified name or {@code null} if it doesn't exist
  760. */
  761. public final QuestTimer getQuestTimer(String name)
  762. {
  763. return getQuest().getQuestTimer(name, null, getPlayer());
  764. }
  765. // --- Spawn methods ---
  766. /**
  767. * Add a temporary spawn of the specified npc.<br>
  768. * Player's coordinates will be used for the spawn.
  769. * @param npcId the Id of the npc to spawn
  770. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  771. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  772. */
  773. public L2Npc addSpawn(int npcId)
  774. {
  775. return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, 0, false);
  776. }
  777. /**
  778. * Add a temporary spawn of the specified npc.<br>
  779. * Player's coordinates will be used for the spawn.
  780. * @param npcId the Id of the npc to spawn
  781. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  782. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  783. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  784. */
  785. public L2Npc addSpawn(int npcId, int despawnDelay)
  786. {
  787. return addSpawn(npcId, _player.getX(), _player.getY(), _player.getZ(), 0, false, despawnDelay, false);
  788. }
  789. /**
  790. * Add a temporary spawn of the specified npc.
  791. * @param npcId the Id of the npc to spawn
  792. * @param x the X coordinate of the npc spawn location
  793. * @param y the Y coordinate of the npc spawn location
  794. * @param z the Z coordinate (height) of the npc spawn location
  795. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  796. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  797. */
  798. public L2Npc addSpawn(int npcId, int x, int y, int z)
  799. {
  800. return addSpawn(npcId, x, y, z, 0, false, 0, false);
  801. }
  802. /**
  803. * Add a temporary spawn of the specified npc.
  804. * @param npcId the Id of the npc to spawn
  805. * @param x the X coordinate of the npc spawn location
  806. * @param y the Y coordinate of the npc spawn location
  807. * @param z the Z coordinate (height) of the npc spawn location
  808. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  809. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  810. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  811. */
  812. public L2Npc addSpawn(int npcId, int x, int y, int z, int despawnDelay)
  813. {
  814. return addSpawn(npcId, x, y, z, 0, false, despawnDelay, false);
  815. }
  816. /**
  817. * Add a temporary spawn of the specified npc.
  818. * @param npcId the Id of the npc to spawn
  819. * @param cha the character whose coordinates will be used for the npc spawn
  820. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  821. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  822. */
  823. public L2Npc addSpawn(int npcId, L2Character cha)
  824. {
  825. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, 0, false);
  826. }
  827. /**
  828. * Add a temporary spawn of the specified npc.
  829. * @param npcId the Id of the npc to spawn
  830. * @param cha the character whose coordinates will be used for the npc spawn
  831. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  832. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  833. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  834. */
  835. public L2Npc addSpawn(int npcId, L2Character cha, int despawnDelay)
  836. {
  837. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), true, despawnDelay, false);
  838. }
  839. /**
  840. * Add a temporary spawn of the specified npc.
  841. * @param npcId the Id of the npc to spawn
  842. * @param cha the character whose coordinates will be used for the npc spawn
  843. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  844. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  845. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  846. * @see #addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  847. */
  848. public L2Npc addSpawn(int npcId, L2Character cha, boolean randomOffset, int despawnDelay)
  849. {
  850. return addSpawn(npcId, cha.getX(), cha.getY(), cha.getZ(), cha.getHeading(), randomOffset, despawnDelay, false);
  851. }
  852. /**
  853. * Add a temporary spawn of the specified npc.
  854. * @param npcId the Id of the npc to spawn
  855. * @param x the X coordinate of the npc spawn location
  856. * @param y the Y coordinate of the npc spawn location
  857. * @param z the Z coordinate (height) of the npc spawn location
  858. * @param heading the heading of the npc
  859. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  860. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  861. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  862. * @see #addSpawn(int, int, int, int, int, boolean, int, boolean)
  863. */
  864. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay)
  865. {
  866. return addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, false);
  867. }
  868. /**
  869. * Add a temporary spawn of the specified npc.
  870. * @param npcId the Id of the npc to spawn
  871. * @param x the X coordinate of the npc spawn location
  872. * @param y the Y coordinate of the npc spawn location
  873. * @param z the Z coordinate (height) of the npc spawn location
  874. * @param heading the heading of the npc
  875. * @param randomOffset if {@code true}, adds +/- 50~100 to X/Y coordinates of the spawn location
  876. * @param despawnDelay time in milliseconds till the npc is despawned (default: 0)
  877. * @param isSummonSpawn if {@code true}, displays a summon animation on npc spawn (default: {@code false})
  878. * @return the {@link L2Npc} object of the newly spawned npc or {@code null} if the npc doesn't exist
  879. * @see #addSpawn(int)
  880. * @see #addSpawn(int, int)
  881. * @see #addSpawn(int, L2Character)
  882. * @see #addSpawn(int, L2Character, int)
  883. * @see #addSpawn(int, int, int, int)
  884. * @see #addSpawn(int, L2Character, boolean, int)
  885. * @see #addSpawn(int, int, int, int, int)
  886. * @see #addSpawn(int, int, int, int, int, boolean, int)
  887. * @see #addSpawn(int, int, int, int, int, boolean, int, boolean)
  888. */
  889. public L2Npc addSpawn(int npcId, int x, int y, int z, int heading, boolean randomOffset, int despawnDelay, boolean isSummonSpawn)
  890. {
  891. return Quest.addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay, isSummonSpawn);
  892. }
  893. /**
  894. * @param fileName the name of the file you want to show. Must be in the same folder (or subfolder) as script
  895. * @return a String containing the contents of the specified HTML file
  896. */
  897. public String showHtmlFile(String fileName)
  898. {
  899. return getQuest().showHtmlFile(getPlayer(), fileName);
  900. }
  901. /**
  902. * Set condition to 1, state to STARTED and play the "ItemSound.quest_accept".<br>
  903. * Works only if state is CREATED and the quest is not a custom quest.
  904. * @return the newly created {@code QuestState} object
  905. */
  906. public QuestState startQuest()
  907. {
  908. if (isCreated() && !getQuest().isCustomQuest())
  909. {
  910. set("cond", "1");
  911. setState(State.STARTED);
  912. playSound(QuestSound.ITEMSOUND_QUEST_ACCEPT);
  913. }
  914. return this;
  915. }
  916. /**
  917. * Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
  918. * If {@code type} is {@code QuestType.ONE_TIME}, also removes all other quest data associated with this quest.
  919. * @param type the {@link QuestType} of the quest
  920. * @return this {@link QuestState} object
  921. * @see #exitQuest(QuestType type, boolean playExitQuest)
  922. * @see #exitQuest(boolean repeatable)
  923. * @see #exitQuest(boolean repeatable, boolean playExitQuest)
  924. */
  925. public QuestState exitQuest(QuestType type)
  926. {
  927. switch (type)
  928. {
  929. case DAILY:
  930. {
  931. exitQuest(false);
  932. setRestartTime();
  933. break;
  934. }
  935. // case ONE_TIME:
  936. // case REPEATABLE:
  937. default:
  938. {
  939. exitQuest(type == QuestType.REPEATABLE);
  940. break;
  941. }
  942. }
  943. return this;
  944. }
  945. /**
  946. * Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
  947. * If {@code type} is {@code QuestType.ONE_TIME}, also removes all other quest data associated with this quest.
  948. * @param type the {@link QuestType} of the quest
  949. * @param playExitQuest if {@code true}, plays "ItemSound.quest_finish"
  950. * @return this {@link QuestState} object
  951. * @see #exitQuest(QuestType type)
  952. * @see #exitQuest(boolean repeatable)
  953. * @see #exitQuest(boolean repeatable, boolean playExitQuest)
  954. */
  955. public QuestState exitQuest(QuestType type, boolean playExitQuest)
  956. {
  957. exitQuest(type);
  958. if (playExitQuest)
  959. {
  960. playSound(QuestSound.ITEMSOUND_QUEST_FINISH);
  961. }
  962. return this;
  963. }
  964. /**
  965. * Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
  966. * If {@code repeatable} is set to {@code false}, also removes all other quest data associated with this quest.
  967. * @param repeatable if {@code true}, deletes all data and variables of this quest, otherwise keeps them
  968. * @return this {@link QuestState} object
  969. * @see #exitQuest(QuestType type)
  970. * @see #exitQuest(QuestType type, boolean playExitQuest)
  971. * @see #exitQuest(boolean repeatable, boolean playExitQuest)
  972. */
  973. public QuestState exitQuest(boolean repeatable)
  974. {
  975. _player.removeNotifyQuestOfDeath(this);
  976. if (!isStarted())
  977. {
  978. return this;
  979. }
  980. // Clean registered quest items
  981. getQuest().removeRegisteredQuestItems(_player);
  982. Quest.deleteQuestInDb(this, repeatable);
  983. if (repeatable)
  984. {
  985. _player.delQuestState(getQuestName());
  986. _player.sendPacket(new QuestList());
  987. }
  988. else
  989. {
  990. setState(State.COMPLETED);
  991. }
  992. _vars = null;
  993. return this;
  994. }
  995. /**
  996. * Finishes the quest and removes all quest items associated with this quest from the player's inventory.<br>
  997. * If {@code repeatable} is set to {@code false}, also removes all other quest data associated with this quest.
  998. * @param repeatable if {@code true}, deletes all data and variables of this quest, otherwise keeps them
  999. * @param playExitQuest if {@code true}, plays "ItemSound.quest_finish"
  1000. * @return this {@link QuestState} object
  1001. * @see #exitQuest(QuestType type)
  1002. * @see #exitQuest(QuestType type, boolean playExitQuest)
  1003. * @see #exitQuest(boolean repeatable)
  1004. */
  1005. public QuestState exitQuest(boolean repeatable, boolean playExitQuest)
  1006. {
  1007. exitQuest(repeatable);
  1008. if (playExitQuest)
  1009. {
  1010. playSound(QuestSound.ITEMSOUND_QUEST_FINISH);
  1011. }
  1012. return this;
  1013. }
  1014. public void showQuestionMark(int number)
  1015. {
  1016. _player.sendPacket(new TutorialShowQuestionMark(number));
  1017. }
  1018. // TODO make tutorial voices the same as quest sounds
  1019. public void playTutorialVoice(String voice)
  1020. {
  1021. _player.sendPacket(new PlaySound(2, voice, 0, 0, _player.getX(), _player.getY(), _player.getZ()));
  1022. }
  1023. public void showTutorialHTML(String html)
  1024. {
  1025. String text = HtmCache.getInstance().getHtm(_player.getHtmlPrefix(), "data/scripts/quests/255_Tutorial/" + html);
  1026. if (text == null)
  1027. {
  1028. _log.warning("missing html page data/scripts/quests/255_Tutorial/" + html);
  1029. text = "<html><body>File data/scripts/quests/255_Tutorial/" + html + " not found or file is empty.</body></html>";
  1030. }
  1031. _player.sendPacket(new TutorialShowHtml(text));
  1032. }
  1033. public void closeTutorialHtml()
  1034. {
  1035. _player.sendPacket(TutorialCloseHtml.STATIC_PACKET);
  1036. }
  1037. public void onTutorialClientEvent(int number)
  1038. {
  1039. _player.sendPacket(new TutorialEnableClientEvent(number));
  1040. }
  1041. public void dropItem(L2MonsterInstance npc, L2PcInstance player, int itemId, int count)
  1042. {
  1043. npc.dropItem(player, itemId, count);
  1044. }
  1045. /**
  1046. * Set the restart time for the daily quests.<br>
  1047. * The time is hardcoded at {@link Quest#getResetHour()} hours, {@link Quest#getResetMinutes()} minutes of the following day.<br>
  1048. * It can be overridden in scripts (quests).
  1049. */
  1050. public void setRestartTime()
  1051. {
  1052. final Calendar reDo = Calendar.getInstance();
  1053. if (reDo.get(Calendar.HOUR_OF_DAY) >= getQuest().getResetHour())
  1054. {
  1055. reDo.add(Calendar.DATE, 1);
  1056. }
  1057. reDo.set(Calendar.HOUR_OF_DAY, getQuest().getResetHour());
  1058. reDo.set(Calendar.MINUTE, getQuest().getResetMinutes());
  1059. set("restartTime", String.valueOf(reDo.getTimeInMillis()));
  1060. }
  1061. /**
  1062. * Check if a daily quest is available to be started over.
  1063. * @return {@code true} if the quest is available, {@code false} otherwise.
  1064. */
  1065. public boolean isNowAvailable()
  1066. {
  1067. final String val = get("restartTime");
  1068. return ((val == null) || !Util.isDigit(val)) || (Long.parseLong(val) <= System.currentTimeMillis());
  1069. }
  1070. }