quest.cpp 26 KB

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