int_quest.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "int_quest.hpp"
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <common/malloc.hpp>
  7. #include <common/mmo.hpp>
  8. #include <common/socket.hpp>
  9. #include <common/sql.hpp>
  10. #include <common/strlib.hpp>
  11. #include "char.hpp"
  12. #include "inter.hpp"
  13. /**
  14. * Loads the entire questlog for a character.
  15. *
  16. * @param char_id Character ID
  17. * @param count Pointer to return the number of found entries.
  18. * @return Array of found entries. It has *count entries, and it is care of the
  19. * caller to aFree() it afterwards.
  20. */
  21. struct quest *mapif_quests_fromsql( uint32 char_id, size_t& count ){
  22. struct quest *questlog = nullptr;
  23. struct quest tmp_quest;
  24. SqlStmt stmt{ *sql_handle };
  25. memset(&tmp_quest, 0, sizeof(struct quest));
  26. if( SQL_ERROR == stmt.Prepare("SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? ", schema_config.quest_db)
  27. || SQL_ERROR == stmt.BindParam(0, SQLDT_INT, &char_id, 0)
  28. || SQL_ERROR == stmt.Execute()
  29. || SQL_ERROR == stmt.BindColumn(0, SQLDT_INT, &tmp_quest.quest_id, 0, nullptr, nullptr)
  30. || SQL_ERROR == stmt.BindColumn(1, SQLDT_INT, &tmp_quest.state, 0, nullptr, nullptr)
  31. || SQL_ERROR == stmt.BindColumn(2, SQLDT_UINT, &tmp_quest.time, 0, nullptr, nullptr)
  32. || SQL_ERROR == stmt.BindColumn(3, SQLDT_INT, &tmp_quest.count[0], 0, nullptr, nullptr)
  33. || SQL_ERROR == stmt.BindColumn(4, SQLDT_INT, &tmp_quest.count[1], 0, nullptr, nullptr)
  34. || SQL_ERROR == stmt.BindColumn(5, SQLDT_INT, &tmp_quest.count[2], 0, nullptr, nullptr)
  35. ) {
  36. SqlStmt_ShowDebug(stmt);
  37. count = 0;
  38. return nullptr;
  39. }
  40. count = static_cast<std::remove_reference<decltype(count)>::type>( stmt.NumRows() );
  41. if( count > 0 ) {
  42. size_t i = 0;
  43. questlog = (struct quest *)aCalloc( count, sizeof( struct quest ) );
  44. while( SQL_SUCCESS == stmt.NextRow() ) {
  45. // Sanity check, should never happen
  46. if( i >= count ){
  47. break;
  48. }
  49. memcpy(&questlog[i++], &tmp_quest, sizeof(tmp_quest));
  50. }
  51. if( i < count ) {
  52. //Should never happen. Compact array
  53. count = i;
  54. questlog = (struct quest *)aRealloc(questlog, sizeof(struct quest) * i);
  55. }
  56. }
  57. return questlog;
  58. }
  59. /**
  60. * Deletes a quest from a character's questlog.
  61. *
  62. * @param char_id Character ID
  63. * @param quest_id Quest ID
  64. * @return false in case of errors, true otherwise
  65. */
  66. bool mapif_quest_delete(uint32 char_id, int32 quest_id) {
  67. if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", schema_config.quest_db, quest_id, char_id) )
  68. {
  69. Sql_ShowDebug(sql_handle);
  70. return false;
  71. }
  72. return true;
  73. }
  74. /**
  75. * Adds a quest to a character's questlog.
  76. *
  77. * @param char_id Character ID
  78. * @param qd Quest data
  79. * @return false in case of errors, true otherwise
  80. */
  81. bool mapif_quest_add(uint32 char_id, struct quest qd) {
  82. if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d', '%u', '%d', '%d', '%d')", schema_config.quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) )
  83. {
  84. Sql_ShowDebug(sql_handle);
  85. return false;
  86. }
  87. return true;
  88. }
  89. /**
  90. * Updates a quest in a character's questlog.
  91. *
  92. * @param char_id Character ID
  93. * @param qd Quest data
  94. * @return false in case of errors, true otherwise
  95. */
  96. bool mapif_quest_update(uint32 char_id, struct quest qd) {
  97. if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", schema_config.quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) )
  98. {
  99. Sql_ShowDebug(sql_handle);
  100. return false;
  101. }
  102. return true;
  103. }
  104. /**
  105. * Handles the save request from mapserver for a character's questlog.
  106. *
  107. * Received quests are saved, and an ack is sent back to the map server.
  108. *
  109. * @see inter_parse_frommap
  110. */
  111. int32 mapif_parse_quest_save(int32 fd) {
  112. uint32 char_id = RFIFOL(fd,4);
  113. struct quest *old_qd = nullptr, *new_qd = nullptr;
  114. bool success = true;
  115. size_t old_n, new_n = ( RFIFOW( fd, 2 ) - 8 ) / sizeof( struct quest );
  116. if( new_n > 0 )
  117. new_qd = (struct quest*)RFIFOP(fd,8);
  118. old_qd = mapif_quests_fromsql( char_id, old_n );
  119. for( size_t i = 0, j; i < new_n; i++ ) {
  120. ARR_FIND(0, old_n, j, new_qd[i].quest_id == old_qd[j].quest_id);
  121. if( j < old_n ) { //Update existing quests
  122. size_t k;
  123. //Only states and counts are changable.
  124. ARR_FIND(0, MAX_QUEST_OBJECTIVES, k, new_qd[i].count[k] != old_qd[j].count[k]);
  125. if( k != MAX_QUEST_OBJECTIVES || new_qd[i].state != old_qd[j].state )
  126. success &= mapif_quest_update(char_id, new_qd[i]);
  127. if( j < (--old_n) ) {
  128. //Compact array
  129. memmove(&old_qd[j], &old_qd[j + 1], sizeof(struct quest) * (old_n - j));
  130. memset(&old_qd[old_n], 0, sizeof(struct quest));
  131. }
  132. } else //Add new quests
  133. success &= mapif_quest_add(char_id, new_qd[i]);
  134. }
  135. // Quests not in new_qd but in old_qd are to be erased.
  136. for( size_t i = 0; i < old_n; i++ ){
  137. success &= mapif_quest_delete(char_id, old_qd[i].quest_id);
  138. }
  139. if( old_qd )
  140. aFree(old_qd);
  141. //Send ack
  142. WFIFOHEAD(fd,7);
  143. WFIFOW(fd,0) = 0x3861;
  144. WFIFOL(fd,2) = char_id;
  145. WFIFOB(fd,6) = success ? 1 : 0;
  146. WFIFOSET(fd,7);
  147. return 0;
  148. }
  149. /**
  150. * Sends questlog to the map server
  151. *
  152. * NOTE: Completed quests (state == Q_COMPLETE) are guaranteed to be sent last
  153. * and the map server relies on this behavior (once the first Q_COMPLETE quest,
  154. * all of them are considered to be Q_COMPLETE)
  155. *
  156. * @see inter_parse_frommap
  157. */
  158. int32 mapif_parse_quest_load(int32 fd) {
  159. uint32 char_id = RFIFOL(fd,2);
  160. size_t num_quests;
  161. struct quest* tmp_questlog = mapif_quests_fromsql( char_id, num_quests );
  162. WFIFOHEAD(fd,num_quests * sizeof(struct quest) + 8);
  163. WFIFOW(fd,0) = 0x3860;
  164. WFIFOW(fd,2) = static_cast<int16>( num_quests * sizeof( struct quest ) + 8 );
  165. WFIFOL(fd,4) = char_id;
  166. if( num_quests > 0 )
  167. memcpy(WFIFOP(fd,8), tmp_questlog, sizeof(struct quest) * num_quests);
  168. WFIFOSET(fd,num_quests * sizeof(struct quest) + 8);
  169. if( tmp_questlog )
  170. aFree(tmp_questlog);
  171. return 0;
  172. }
  173. /**
  174. * Parses questlog related packets from the map server.
  175. *
  176. * @see inter_parse_frommap
  177. */
  178. int32 inter_quest_parse_frommap(int32 fd) {
  179. switch(RFIFOW(fd,0)) {
  180. case 0x3060: mapif_parse_quest_load(fd); break;
  181. case 0x3061: mapif_parse_quest_save(fd); break;
  182. default:
  183. return 0;
  184. }
  185. return 1;
  186. }