quest.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "quest.hpp"
  4. #include <stdlib.h>
  5. #include "../common/cbasetypes.hpp"
  6. #include "../common/malloc.hpp"
  7. #include "../common/nullpo.hpp"
  8. #include "../common/random.hpp"
  9. #include "../common/showmsg.hpp"
  10. #include "../common/socket.hpp"
  11. #include "../common/strlib.hpp"
  12. #include "../common/utilities.hpp"
  13. #include "../common/utils.hpp"
  14. #include "battle.hpp"
  15. #include "chrif.hpp"
  16. #include "clif.hpp"
  17. #include "intif.hpp"
  18. #include "itemdb.hpp"
  19. #include "log.hpp"
  20. #include "map.hpp"
  21. #include "mob.hpp"
  22. #include "party.hpp"
  23. #include "pc.hpp"
  24. static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minute, int *second);
  25. const std::string QuestDatabase::getDefaultLocation() {
  26. return std::string(db_path) + "/quest_db.yml";
  27. }
  28. /**
  29. * Reads and parses an entry from the quest_db.
  30. * @param node: YAML node containing the entry.
  31. * @return count of successfully parsed rows
  32. */
  33. uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
  34. uint32 quest_id;
  35. if (!this->asUInt32(node, "Id", quest_id))
  36. return 0;
  37. std::shared_ptr<s_quest_db> quest = this->find(quest_id);
  38. bool exists = quest != nullptr;
  39. if (!exists) {
  40. if (!this->nodesExist(node, { "Title" }))
  41. return 0;
  42. quest = std::make_shared<s_quest_db>();
  43. quest->id = quest_id;
  44. }
  45. if (this->nodeExists(node, "Title")) {
  46. std::string name;
  47. if (!this->asString(node, "Title", name))
  48. return 0;
  49. quest->name = name;
  50. }
  51. if (this->nodeExists(node, "TimeLimit")) {
  52. std::string time;
  53. if (!this->asString(node, "TimeLimit", time))
  54. return 0;
  55. if (time.find("+") != std::string::npos) {
  56. double timediff = solve_time(const_cast<char *>(time.c_str()));
  57. if (timediff <= 0) {
  58. this->invalidWarning(node["TimeLimit"], "Incorrect TimeLimit format %s given, skipping.\n", time.c_str());
  59. return 0;
  60. }
  61. quest->time = static_cast<time_t>(timediff);
  62. }
  63. else {// '+' not found, set to specific time
  64. int32 day, hour, minute, second;
  65. if (split_exact_quest_time(const_cast<char *>(time.c_str()), &day, &hour, &minute, &second) == 0) {
  66. this->invalidWarning(node["TimeLimit"], "Incorrect TimeLimit format %s given, skipping.\n", time.c_str());
  67. return 0;
  68. }
  69. quest->time = day * 86400 + hour * 3600 + minute * 60 + second;
  70. quest->time_at = true;
  71. }
  72. } else {
  73. if (!exists) {
  74. quest->time = 0;
  75. quest->time_at = false;
  76. }
  77. }
  78. if (this->nodeExists(node, "Targets")) {
  79. const YAML::Node &targets = node["Targets"];
  80. for (const YAML::Node &targetNode : targets) {
  81. if (quest->objectives.size() >= MAX_QUEST_OBJECTIVES) {
  82. this->invalidWarning(targetNode, "Targets list exceeds the maximum of %d, skipping.\n", MAX_QUEST_OBJECTIVES);
  83. return 0;
  84. }
  85. if (!this->nodeExists(targetNode, "Mob") && !this->nodeExists(targetNode, "Id")) {
  86. this->invalidWarning(targetNode, "Missing Target 'Mob' or 'Id', skipping.\n");
  87. return 0;
  88. }
  89. std::shared_ptr<s_quest_objective> target;
  90. std::vector<std::shared_ptr<s_quest_objective>>::iterator it;
  91. uint16 index = 0, mob_id = 0;
  92. if (this->nodeExists(targetNode, "Mob")) {
  93. std::string mob_name;
  94. if (!this->asString(targetNode, "Mob", mob_name))
  95. return 0;
  96. struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
  97. if (!mob) {
  98. this->invalidWarning(targetNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
  99. return 0;
  100. }
  101. mob_id = mob->vd.class_;
  102. it = std::find_if(quest->objectives.begin(), quest->objectives.end(), [&](std::shared_ptr<s_quest_objective> const &v) {
  103. return (*v).mob_id == mob_id;
  104. });
  105. }
  106. else {
  107. if (!this->asUInt16(targetNode, "Id", index)) {
  108. this->invalidWarning(targetNode, "Missing 'Id', skipping.\n");
  109. return 0;
  110. }
  111. if (index == 0) {
  112. this->invalidWarning(targetNode["Id"], "'Id' can't be 0, skipping.\n");
  113. return 0;
  114. }
  115. it = std::find_if(quest->objectives.begin(), quest->objectives.end(), [&](std::shared_ptr<s_quest_objective> const &v) {
  116. return (*v).index == index;
  117. });
  118. }
  119. if (it != quest->objectives.end())
  120. target = (*it);
  121. else
  122. target = nullptr;
  123. bool targetExists = target != nullptr;
  124. if (!targetExists) {
  125. if (!this->nodeExists(targetNode, "Count")) {
  126. this->invalidWarning(targetNode["Count"], "Targets has no Count value specified, skipping.\n");
  127. return 0;
  128. }
  129. if (!this->nodeExists(targetNode, "Mob") && !this->nodeExists(targetNode, "MinLevel") && !this->nodeExists(targetNode, "MaxLevel") &&
  130. !this->nodeExists(targetNode, "Race") && !this->nodeExists(targetNode, "Size") && !this->nodeExists(targetNode, "Element")) {
  131. this->invalidWarning(targetNode, "Targets is missing required field, skipping.\n");
  132. return 0;
  133. }
  134. target = std::make_shared<s_quest_objective>();
  135. target->index = index;
  136. target->mob_id = mob_id;
  137. target->min_level = 0;
  138. target->max_level = 0;
  139. target->race = RC_ALL;
  140. target->size = SZ_ALL;
  141. target->element = ELE_ALL;
  142. }
  143. if (!this->nodeExists(targetNode, "Mob")) {
  144. if (this->nodeExists(targetNode, "MinLevel")) {
  145. uint16 level;
  146. if (!this->asUInt16(targetNode, "MinLevel", level))
  147. return 0;
  148. target->min_level = level;
  149. }
  150. if (this->nodeExists(targetNode, "MaxLevel")) {
  151. uint16 level;
  152. if (!this->asUInt16(targetNode, "MaxLevel", level))
  153. return 0;
  154. if (target->min_level > level) {
  155. this->invalidWarning(targetNode["MaxLevel"], "%d's MinLevel is greater than MaxLevel. Defaulting MaxLevel to %d.\n", target->min_level, MAX_LEVEL);
  156. level = MAX_LEVEL;
  157. }
  158. target->max_level = level;
  159. }
  160. if (this->nodeExists(targetNode, "Race")) {
  161. std::string race;
  162. if (!this->asString(targetNode, "Race", race))
  163. return 0;
  164. std::string race_constant = "RC_" + race;
  165. int64 constant;
  166. if (!script_get_constant(race_constant.c_str(), &constant)) {
  167. this->invalidWarning(targetNode["Race"], "Invalid race %s, skipping.\n", race.c_str());
  168. return 0;
  169. }
  170. if (constant < RC_FORMLESS || constant > RC_ALL || constant == RC_PLAYER_HUMAN || constant == RC_PLAYER_DORAM) {
  171. this->invalidWarning(targetNode["Race"], "Unsupported race %s, skipping.\n", race.c_str());
  172. return 0;
  173. }
  174. target->race = static_cast<e_race>(constant);
  175. }
  176. if (this->nodeExists(targetNode, "Size")) {
  177. std::string size_;
  178. if (!this->asString(targetNode, "Size", size_))
  179. return 0;
  180. std::string size_constant = "Size_" + size_;
  181. int64 constant;
  182. if (!script_get_constant(size_constant.c_str(), &constant)) {
  183. this->invalidWarning(targetNode["Size"], "Invalid size type %s, skipping.\n", size_.c_str());
  184. return 0;
  185. }
  186. if (constant < SZ_SMALL || constant > SZ_ALL) {
  187. this->invalidWarning(targetNode["size"], "Unsupported size %s, skipping.\n", size_.c_str());
  188. return 0;
  189. }
  190. target->size = static_cast<e_size>(constant);
  191. }
  192. if (this->nodeExists(targetNode, "Element")) {
  193. std::string element;
  194. if (!this->asString(targetNode, "Element", element))
  195. return 0;
  196. std::string element_constant = "Ele_" + element;
  197. int64 constant;
  198. if (!script_get_constant(element_constant.c_str(), &constant)) {
  199. this->invalidWarning(targetNode["Element"], "Invalid element %s, skipping.\n", element.c_str());
  200. return 0;
  201. }
  202. if (constant < ELE_NEUTRAL || constant > ELE_ALL) {
  203. this->invalidWarning(targetNode["Element"], "Unsupported element %s, skipping.\n", element.c_str());
  204. return 0;
  205. }
  206. target->element = static_cast<e_element>(constant);
  207. }
  208. // if max_level is set, min_level is 1
  209. if (target->min_level == 0 && target->max_level > 0)
  210. target->min_level = 1;
  211. }
  212. if (this->nodeExists(targetNode, "Count")) {
  213. uint16 count;
  214. if (!this->asUInt16(targetNode, "Count", count))
  215. return 0;
  216. target->count = count;
  217. }
  218. quest->objectives.push_back(target);
  219. }
  220. }
  221. if (this->nodeExists(node, "Drops")) {
  222. const YAML::Node &drops = node["Drops"];
  223. for (const YAML::Node &dropNode : drops) {
  224. if (quest->objectives.size() >= MAX_QUEST_OBJECTIVES) {
  225. this->invalidWarning(dropNode, "Drops list exceeds the maximum of %d, skipping.\n", MAX_QUEST_OBJECTIVES);
  226. return 0;
  227. }
  228. uint32 mob_id = 0; // Can be 0 which means all monsters
  229. if (this->nodeExists(dropNode, "Mob")) {
  230. std::string mob_name;
  231. if (!this->asString(dropNode, "Mob", mob_name))
  232. return 0;
  233. struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
  234. if (!mob) {
  235. this->invalidWarning(dropNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
  236. continue;
  237. }
  238. mob_id = mob->vd.class_;
  239. }
  240. //std::shared_ptr<s_quest_dropitem> target = util::vector_find(quest->dropitem, mob_id);
  241. std::shared_ptr<s_quest_dropitem> target;
  242. std::vector<std::shared_ptr<s_quest_dropitem>>::iterator it = std::find_if(quest->dropitem.begin(), quest->dropitem.end(), [&](std::shared_ptr<s_quest_dropitem> const &v) {
  243. return (*v).mob_id == mob_id;
  244. });
  245. if (it != quest->dropitem.end())
  246. target = (*it);
  247. else
  248. target = nullptr;
  249. bool targetExists = target != nullptr;
  250. if (!targetExists) {
  251. if (!this->nodeExists(dropNode, "Item")) {
  252. this->invalidWarning(dropNode["Item"], "Drops has no Item value specified, skipping.\n");
  253. continue;
  254. }
  255. if (!this->nodeExists(dropNode, "Rate")) {
  256. this->invalidWarning(dropNode["Item"], "Drops has no Rate value specified, skipping.\n");
  257. continue;
  258. }
  259. target = std::make_shared<s_quest_dropitem>();
  260. target->mob_id = mob_id;
  261. }
  262. if (this->nodeExists(dropNode, "Item")) {
  263. std::string item_name;
  264. if (!this->asString(dropNode, "Item", item_name))
  265. return 0;
  266. struct item_data *item = itemdb_search_aegisname(item_name.c_str());
  267. if (!item) {
  268. this->invalidWarning(dropNode["Item"], "Item %s does not exist, skipping.\n", item_name.c_str());
  269. continue;
  270. }
  271. target->nameid = item->nameid;
  272. }
  273. if (this->nodeExists(dropNode, "Count")) {
  274. uint16 count;
  275. if (!this->asUInt16(dropNode, "Count", count))
  276. return 0;
  277. if (!itemdb_isstackable(target->nameid)) {
  278. this->invalidWarning(dropNode["Count"], "Item %s is not stackable, capping to 1.\n", itemdb_name(target->nameid));
  279. count = 1;
  280. }
  281. target->count = count;
  282. } else {
  283. if (!targetExists)
  284. target->count = 1;
  285. }
  286. if (this->nodeExists(dropNode, "Rate")) {
  287. uint16 rate;
  288. if (!this->asUInt16(dropNode, "Rate", rate))
  289. return 0;
  290. target->rate = rate;
  291. }
  292. quest->dropitem.push_back(target);
  293. }
  294. }
  295. if (!exists)
  296. this->put(quest_id, quest);
  297. return 1;
  298. }
  299. static int split_exact_quest_time(char* modif_p, int* day, int* hour, int* minute, int *second) {
  300. int d = -1, h = -1, mn = -1, s = -1;
  301. nullpo_retr(0, modif_p);
  302. while (modif_p[0] != '\0') {
  303. int value = atoi(modif_p);
  304. if (modif_p[0] == '-' || modif_p[0] == '+')
  305. modif_p++;
  306. while (modif_p[0] >= '0' && modif_p[0] <= '9')
  307. modif_p++;
  308. if (modif_p[0] == 's') {
  309. s = value;
  310. modif_p++;
  311. } else if (modif_p[0] == 'm' && modif_p[1] == 'n') {
  312. mn = value;
  313. modif_p = modif_p + 2;
  314. } else if (modif_p[0] == 'h') {
  315. h = value;
  316. modif_p++;
  317. } else if (modif_p[0] == 'd' || modif_p[0] == 'j') {
  318. d = value;
  319. modif_p++;
  320. } else if (modif_p[0] != '\0') {
  321. modif_p++;
  322. }
  323. }
  324. if (h < 0 || h > 23 || mn > 59 || s > 59) // hour is required
  325. return 0;
  326. *day = max(0,d);
  327. *hour = h;
  328. *minute = max(0,mn);
  329. *second = max(0,s);
  330. return 1;
  331. }
  332. /**
  333. * Searches a quest by ID.
  334. * @param quest_id : ID to lookup
  335. * @return Quest entry or nullptr on failure
  336. */
  337. std::shared_ptr<s_quest_db> quest_search(int quest_id)
  338. {
  339. auto quest = quest_db.find(quest_id);
  340. if (!quest)
  341. return nullptr;
  342. return quest;
  343. }
  344. /**
  345. * Sends quest info to the player on login.
  346. * @param sd : Player's data
  347. * @return 0 in case of success, nonzero otherwise (i.e. the player has no quests)
  348. */
  349. int quest_pc_login(struct map_session_data *sd)
  350. {
  351. if (!sd->avail_quests)
  352. return 1;
  353. clif_quest_send_list(sd);
  354. #if PACKETVER < 20141022
  355. clif_quest_send_mission(sd);
  356. //@TODO[Haru]: Is this necessary? Does quest_send_mission not take care of this?
  357. for (int i = 0; i < sd->avail_quests; i++)
  358. clif_quest_update_objective(sd, &sd->quest_log[i]);
  359. #endif
  360. return 0;
  361. }
  362. /**
  363. * Determine a quest's time limit.
  364. * @param qi: Quest data
  365. * @return Time limit value
  366. */
  367. static time_t quest_time(std::shared_ptr<s_quest_db> qi)
  368. {
  369. if (!qi || qi->time < 0)
  370. return 0;
  371. if (!qi->time_at && qi->time > 0)
  372. return time(nullptr) + qi->time;
  373. else if (qi->time_at) {
  374. time_t t = time(nullptr);
  375. struct tm *lt = localtime(&t);
  376. uint32 time_today = lt->tm_hour * 3600 + lt->tm_min * 60 + lt->tm_sec;
  377. if (time_today < (qi->time % 86400))
  378. return static_cast<time_t>(t + qi->time - time_today);
  379. else // Carry over to the next day
  380. return static_cast<time_t>(t + 86400 + qi->time - time_today);
  381. }
  382. return 0;
  383. }
  384. /**
  385. * Adds a quest to the player's list.
  386. * New quest will be added as Q_ACTIVE.
  387. * @param sd : Player's data
  388. * @param quest_id : ID of the quest to add.
  389. * @return 0 in case of success, nonzero otherwise
  390. */
  391. int quest_add(struct map_session_data *sd, int quest_id)
  392. {
  393. std::shared_ptr<s_quest_db> qi = quest_search(quest_id);
  394. if (!qi) {
  395. ShowError("quest_add: quest %d not found in DB.\n", quest_id);
  396. return -1;
  397. }
  398. if (quest_check(sd, quest_id, HAVEQUEST) >= 0) {
  399. ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id);
  400. return -1;
  401. }
  402. int n = sd->avail_quests; //Insertion point
  403. sd->num_quests++;
  404. sd->avail_quests++;
  405. RECREATE(sd->quest_log, struct quest, sd->num_quests);
  406. //The character has some completed quests, make room before them so that they will stay at the end of the array
  407. if (sd->avail_quests != sd->num_quests)
  408. memmove(&sd->quest_log[n + 1], &sd->quest_log[n], sizeof(struct quest) * (sd->num_quests-sd->avail_quests));
  409. sd->quest_log[n] = {};
  410. sd->quest_log[n].quest_id = qi->id;
  411. sd->quest_log[n].time = (uint32)quest_time(qi);
  412. sd->quest_log[n].state = Q_ACTIVE;
  413. sd->save_quest = true;
  414. clif_quest_add(sd, &sd->quest_log[n]);
  415. clif_quest_update_objective(sd, &sd->quest_log[n]);
  416. if( save_settings&CHARSAVE_QUEST )
  417. chrif_save(sd, CSAVE_NORMAL);
  418. return 0;
  419. }
  420. /**
  421. * Replaces a quest in a player's list with another one.
  422. * @param sd : Player's data
  423. * @param qid1 : Current quest to replace
  424. * @param qid2 : New quest to add
  425. * @return 0 in case of success, nonzero otherwise
  426. */
  427. int quest_change(struct map_session_data *sd, int qid1, int qid2)
  428. {
  429. std::shared_ptr<s_quest_db> qi = quest_search(qid2);
  430. if (!qi) {
  431. ShowError("quest_change: quest %d not found in DB.\n", qid2);
  432. return -1;
  433. }
  434. if (quest_check(sd, qid2, HAVEQUEST) >= 0) {
  435. ShowError("quest_change: Character %d already has quest %d.\n", sd->status.char_id, qid2);
  436. return -1;
  437. }
  438. if (quest_check(sd, qid1, HAVEQUEST) < 0) {
  439. ShowError("quest_change: Character %d doesn't have quest %d.\n", sd->status.char_id, qid1);
  440. return -1;
  441. }
  442. int i;
  443. ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == qid1);
  444. if (i == sd->avail_quests) {
  445. ShowError("quest_change: Character %d has completed quest %d.\n", sd->status.char_id, qid1);
  446. return -1;
  447. }
  448. sd->quest_log[i] = {};
  449. sd->quest_log[i].quest_id = qi->id;
  450. sd->quest_log[i].time = (uint32)quest_time(qi);
  451. sd->quest_log[i].state = Q_ACTIVE;
  452. sd->save_quest = true;
  453. clif_quest_delete(sd, qid1);
  454. clif_quest_add(sd, &sd->quest_log[i]);
  455. clif_quest_update_objective(sd, &sd->quest_log[i]);
  456. if( save_settings&CHARSAVE_QUEST )
  457. chrif_save(sd, CSAVE_NORMAL);
  458. return 0;
  459. }
  460. /**
  461. * Removes a quest from a player's list
  462. * @param sd : Player's data
  463. * @param quest_id : ID of the quest to remove
  464. * @return 0 in case of success, nonzero otherwise
  465. */
  466. int quest_delete(struct map_session_data *sd, int quest_id)
  467. {
  468. int i;
  469. //Search for quest
  470. ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
  471. if (i == sd->num_quests) {
  472. ShowError("quest_delete: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id);
  473. return -1;
  474. }
  475. if (sd->quest_log[i].state != Q_COMPLETE)
  476. sd->avail_quests--;
  477. if (i < --sd->num_quests) //Compact the array
  478. memmove(&sd->quest_log[i], &sd->quest_log[i + 1], sizeof(struct quest) * (sd->num_quests - i));
  479. if (sd->num_quests == 0) {
  480. aFree(sd->quest_log);
  481. sd->quest_log = NULL;
  482. } else
  483. RECREATE(sd->quest_log, struct quest, sd->num_quests);
  484. sd->save_quest = true;
  485. clif_quest_delete(sd, quest_id);
  486. if( save_settings&CHARSAVE_QUEST )
  487. chrif_save(sd, CSAVE_NORMAL);
  488. return 0;
  489. }
  490. /**
  491. * Map iterator subroutine to update quest objectives for a party after killing a monster.
  492. * @see map_foreachinrange
  493. * @param ap : Argument list, expecting:
  494. * int Party ID
  495. * int Mob ID
  496. * int Mob Level
  497. * int Mob Race
  498. * int Mob Size
  499. * int Mob Element
  500. */
  501. int quest_update_objective_sub(struct block_list *bl, va_list ap)
  502. {
  503. nullpo_ret(bl);
  504. struct map_session_data *sd;
  505. nullpo_ret(sd = (struct map_session_data *)bl);
  506. if( !sd->avail_quests )
  507. return 0;
  508. int party_id = va_arg(ap,int);
  509. int mob_id = va_arg(ap, int);
  510. int mob_level = va_arg(ap, int);
  511. e_race mob_race = static_cast<e_race>(va_arg(ap, int));
  512. e_size mob_size = static_cast<e_size>(va_arg(ap, int));
  513. e_element mob_element = static_cast<e_element>(va_arg(ap, int));
  514. if( sd->status.party_id != party_id )
  515. return 0;
  516. quest_update_objective(sd, mob_id, mob_level, mob_race, mob_size, mob_element);
  517. return 1;
  518. }
  519. /**
  520. * Updates the quest objectives for a character after killing a monster, including the handling of quest-granted drops.
  521. * @param sd: Character's data
  522. * @param mob_id: Monster ID
  523. * @param mob_level: Monster Level
  524. * @param mob_race: Monster Race
  525. * @param mob_size: Monster Size
  526. * @param mob_element: Monster Element
  527. */
  528. void quest_update_objective(struct map_session_data *sd, int mob_id, int mob_level, e_race mob_race, e_size mob_size, e_element mob_element)
  529. {
  530. nullpo_retv(sd);
  531. for (int i = 0; i < sd->avail_quests; i++) {
  532. if (sd->quest_log[i].state == Q_COMPLETE) // Skip complete quests
  533. continue;
  534. std::shared_ptr<s_quest_db> qi = quest_search(sd->quest_log[i].quest_id);
  535. if (!qi)
  536. continue;
  537. // Process quest objectives
  538. for (int j = 0; j < qi->objectives.size(); j++) {
  539. uint8 objective_check = 0; // Must pass all 5 checks
  540. if (qi->objectives[j]->mob_id == mob_id)
  541. objective_check = 5;
  542. else if (qi->objectives[j]->mob_id == 0) {
  543. if (qi->objectives[j]->min_level == 0 || qi->objectives[j]->min_level <= mob_level)
  544. objective_check++;
  545. if (qi->objectives[j]->max_level == 0 || qi->objectives[j]->max_level >= mob_level)
  546. objective_check++;
  547. if (qi->objectives[j]->race == RC_ALL || qi->objectives[j]->race == mob_race)
  548. objective_check++;
  549. if (qi->objectives[j]->size == SZ_ALL || qi->objectives[j]->size == mob_size)
  550. objective_check++;
  551. if (qi->objectives[j]->element == ELE_ALL || qi->objectives[j]->element == mob_element)
  552. objective_check++;
  553. }
  554. if (objective_check == 5 && sd->quest_log[i].count[j] < qi->objectives[j]->count) {
  555. sd->quest_log[i].count[j]++;
  556. sd->save_quest = true;
  557. clif_quest_update_objective(sd, &sd->quest_log[i]);
  558. }
  559. }
  560. // Process quest-granted extra drop bonuses
  561. for (const auto &it : qi->dropitem) {
  562. if (it->mob_id != 0 && it->mob_id != mob_id)
  563. continue;
  564. if (it->rate < 10000 && rnd()%10000 >= it->rate)
  565. continue; // TODO: Should this be affected by server rates?
  566. if (!itemdb_exists(it->nameid))
  567. continue;
  568. struct item entry = {};
  569. entry.nameid = it->nameid;
  570. entry.identify = itemdb_isidentified(it->nameid);
  571. entry.amount = it->count;
  572. //#ifdef BOUND_ITEMS
  573. // entry.bound = it->bound;
  574. //#endif
  575. // if (it.isGUID)
  576. // item.unique_id = pc_generate_unique_id(sd);
  577. e_additem_result result;
  578. if ((result = pc_additem(sd, &entry, 1, LOG_TYPE_QUEST)) != ADDITEM_SUCCESS) // Failed to obtain the item
  579. clif_additem(sd, 0, 0, result);
  580. // else if (it.isAnnounced || itemdb_exists(it.nameid)->flag.broadcast)
  581. // intif_broadcast_obtain_special_item(sd, it.nameid, it.mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM);
  582. }
  583. }
  584. pc_show_questinfo(sd);
  585. }
  586. /**
  587. * Updates a quest's state.
  588. * Only status of active and inactive quests can be updated. Completed quests can't (for now).
  589. * @param sd : Character's data
  590. * @param quest_id : Quest ID to update
  591. * @param qs : New quest state
  592. * @return 0 in case of success, nonzero otherwise
  593. * @author [Inkfish]
  594. */
  595. int quest_update_status(struct map_session_data *sd, int quest_id, e_quest_state status)
  596. {
  597. int i;
  598. ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id);
  599. if (i == sd->avail_quests) {
  600. ShowError("quest_update_status: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id);
  601. return -1;
  602. }
  603. sd->quest_log[i].state = status;
  604. sd->save_quest = true;
  605. if (status < Q_COMPLETE) {
  606. clif_quest_update_status(sd, quest_id, status == Q_ACTIVE ? true : false);
  607. return 0;
  608. }
  609. // The quest is complete, so it needs to be moved to the completed quests block at the end of the array.
  610. if (i < (--sd->avail_quests)) {
  611. struct quest tmp_quest;
  612. memcpy(&tmp_quest, &sd->quest_log[i], sizeof(struct quest));
  613. memcpy(&sd->quest_log[i], &sd->quest_log[sd->avail_quests], sizeof(struct quest));
  614. memcpy(&sd->quest_log[sd->avail_quests], &tmp_quest, sizeof(struct quest));
  615. }
  616. clif_quest_delete(sd, quest_id);
  617. if (save_settings&CHARSAVE_QUEST)
  618. chrif_save(sd, CSAVE_NORMAL);
  619. return 0;
  620. }
  621. /**
  622. * Queries quest information for a character.
  623. * @param sd : Character's data
  624. * @param quest_id : Quest ID
  625. * @param type : Check type
  626. * @return -1 if the quest was not found, otherwise it depends on the type:
  627. * HAVEQUEST: The quest's state
  628. * PLAYTIME: 2 if the quest's timeout has expired
  629. * 1 if the quest was completed
  630. * 0 otherwise
  631. * HUNTING: 2 if the quest has not been marked as completed yet, and its objectives have been fulfilled
  632. * 1 if the quest's timeout has expired
  633. * 0 otherwise
  634. */
  635. int quest_check(struct map_session_data *sd, int quest_id, e_quest_check_type type)
  636. {
  637. int i;
  638. ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
  639. if (i == sd->num_quests)
  640. return -1;
  641. switch (type) {
  642. case HAVEQUEST:
  643. if (sd->quest_log[i].state == Q_INACTIVE) // Player has the quest but it's in the inactive state; send it as Q_ACTIVE.
  644. return 1;
  645. return sd->quest_log[i].state;
  646. case PLAYTIME:
  647. return (sd->quest_log[i].time < (unsigned int)time(nullptr) ? 2 : sd->quest_log[i].state == Q_COMPLETE ? 1 : 0);
  648. case HUNTING:
  649. if (sd->quest_log[i].state == Q_INACTIVE || sd->quest_log[i].state == Q_ACTIVE) {
  650. int j;
  651. std::shared_ptr<s_quest_db> qi = quest_search(sd->quest_log[i].quest_id);
  652. ARR_FIND(0, qi->objectives.size(), j, sd->quest_log[i].count[j] < qi->objectives[j]->count);
  653. if (j == qi->objectives.size())
  654. return 2;
  655. if (sd->quest_log[i].time < (unsigned int)time(nullptr))
  656. return 1;
  657. }
  658. return 0;
  659. default:
  660. ShowError("quest_check_quest: Unknown parameter %d",type);
  661. break;
  662. }
  663. return -1;
  664. }
  665. /**
  666. * Map iterator to ensures a player has no invalid quest log entries.
  667. * Any entries that are no longer in the db are removed.
  668. * @see map_foreachpc
  669. * @param sd : Character's data
  670. * @param ap : Ignored
  671. */
  672. static int quest_reload_check_sub(struct map_session_data *sd, va_list ap)
  673. {
  674. nullpo_ret(sd);
  675. int i, j = 0;
  676. for (i = 0; i < sd->num_quests; i++) {
  677. std::shared_ptr<s_quest_db> qi = quest_search(sd->quest_log[i].quest_id);
  678. if (!qi) { //Remove no longer existing entries
  679. if (sd->quest_log[i].state != Q_COMPLETE) //And inform the client if necessary
  680. clif_quest_delete(sd, sd->quest_log[i].quest_id);
  681. continue;
  682. }
  683. if (i != j) {
  684. //Move entries if there's a gap to fill
  685. memcpy(&sd->quest_log[j], &sd->quest_log[i], sizeof(struct quest));
  686. }
  687. j++;
  688. }
  689. sd->num_quests = j;
  690. ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].state == Q_COMPLETE);
  691. sd->avail_quests = i;
  692. return 1;
  693. }
  694. bool QuestDatabase::reload() {
  695. if (!TypesafeYamlDatabase::reload())
  696. return false;
  697. // Update quest data for players, to ensure no entries about removed quests are left over.
  698. map_foreachpc(&quest_reload_check_sub);
  699. return true;
  700. }
  701. QuestDatabase quest_db;
  702. /**
  703. * Initializes the quest interface.
  704. */
  705. void do_init_quest(void)
  706. {
  707. quest_db.load();
  708. }
  709. /**
  710. * Finalizes the quest interface before shutdown.
  711. */
  712. void do_final_quest(void)
  713. {
  714. }