int_storage.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #pragma warning(disable:4800) //forcing value to bool
  4. #include "int_storage.hpp"
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "../common/malloc.hpp"
  8. #include "../common/mmo.hpp"
  9. #include "../common/showmsg.hpp"
  10. #include "../common/socket.hpp"
  11. #include "../common/sql.hpp"
  12. #include "../common/strlib.hpp" // StringBuf
  13. #include "char.hpp"
  14. #include "inter.hpp"
  15. /**
  16. * Check if storage ID is valid
  17. * @param id Storage ID
  18. * @return True:Valid, False:Invalid
  19. **/
  20. bool inter_premiumStorage_exists(uint8 id) {
  21. return interserv_config.storages.find(id) != interserv_config.storages.end();
  22. }
  23. /**
  24. * Get max storage amount
  25. * @param id Storage ID
  26. * @return Max amount
  27. **/
  28. int inter_premiumStorage_getMax(uint8 id) {
  29. if (inter_premiumStorage_exists(id))
  30. return interserv_config.storages[id]->max_num;
  31. return MAX_STORAGE;
  32. }
  33. /**
  34. * Get table name of storage
  35. * @param id Storage ID
  36. * @return Table name
  37. **/
  38. const char *inter_premiumStorage_getTableName(uint8 id) {
  39. if (inter_premiumStorage_exists(id))
  40. return interserv_config.storages[id]->table;
  41. return schema_config.storage_db;
  42. }
  43. /**
  44. * Get printable name of storage
  45. * @param id Storage ID
  46. * @return printable name
  47. **/
  48. const char *inter_premiumStorage_getPrintableName(uint8 id) {
  49. if (inter_premiumStorage_exists(id))
  50. return interserv_config.storages[id]->name;
  51. return "Storage";
  52. }
  53. /**
  54. * Save inventory entries to SQL
  55. * @param char_id: Character ID to save
  56. * @param p: Inventory entries
  57. * @return 0 if success, or error count
  58. */
  59. int inventory_tosql(uint32 char_id, struct s_storage* p)
  60. {
  61. return char_memitemdata_to_sql(p->u.items_inventory, MAX_INVENTORY, char_id, TABLE_INVENTORY, p->stor_id);
  62. }
  63. /**
  64. * Save storage entries to SQL
  65. * @param char_id: Character ID to save
  66. * @param p: Storage entries
  67. * @return 0 if success, or error count
  68. */
  69. int storage_tosql(uint32 account_id, struct s_storage* p)
  70. {
  71. return char_memitemdata_to_sql(p->u.items_storage, MAX_STORAGE, account_id, TABLE_STORAGE, p->stor_id);
  72. }
  73. /**
  74. * Save cart entries to SQL
  75. * @param char_id: Character ID to save
  76. * @param p: Cart entries
  77. * @return 0 if success, or error count
  78. */
  79. int cart_tosql(uint32 char_id, struct s_storage* p)
  80. {
  81. return char_memitemdata_to_sql(p->u.items_cart, MAX_CART, char_id, TABLE_CART, p->stor_id);
  82. }
  83. /**
  84. * Fetch inventory entries from table
  85. * @param char_id: Character ID to fetch
  86. * @param p: Inventory list to save the entries
  87. * @return True if success, False if failed
  88. */
  89. bool inventory_fromsql(uint32 char_id, struct s_storage* p)
  90. {
  91. return char_memitemdata_from_sql( p, MAX_INVENTORY, char_id, TABLE_INVENTORY, p->stor_id );
  92. }
  93. /**
  94. * Fetch cart entries from table
  95. * @param char_id: Character ID to fetch
  96. * @param p: Cart list to save the entries
  97. * @return True if success, False if failed
  98. */
  99. bool cart_fromsql(uint32 char_id, struct s_storage* p)
  100. {
  101. return char_memitemdata_from_sql( p, MAX_CART, char_id, TABLE_CART, p->stor_id );
  102. }
  103. /**
  104. * Fetch storage entries from table
  105. * @param char_id: Character ID to fetch
  106. * @param p: Storage list to save the entries
  107. * @param stor_id: Storage ID
  108. * @return True if success, False if failed
  109. */
  110. bool storage_fromsql(uint32 account_id, struct s_storage* p)
  111. {
  112. return char_memitemdata_from_sql( p, MAX_STORAGE, account_id, TABLE_STORAGE, p->stor_id );
  113. }
  114. /**
  115. * Save guild_storage data to sql
  116. * @param guild_id: Character ID to save
  117. * @param p: Guild Storage list to save the entries
  118. * @return 0 if success, or error count
  119. */
  120. bool guild_storage_tosql(int guild_id, struct s_storage* p)
  121. {
  122. //ShowInfo("Guild Storage has been saved (GID: %d)\n", guild_id);
  123. return char_memitemdata_to_sql(p->u.items_guild, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE, p->stor_id);
  124. }
  125. /**
  126. * Fetch guild_storage entries from table
  127. * @param char_id: Character ID to fetch
  128. * @param p: Storage list to save the entries
  129. * @return True if success, False if failed
  130. */
  131. bool guild_storage_fromsql(int guild_id, struct s_storage* p)
  132. {
  133. return char_memitemdata_from_sql( p, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE, p->stor_id );
  134. }
  135. void inter_storage_checkDB(void) {
  136. // Checking storage tables
  137. for (auto storage_table : interserv_config.storages) {
  138. if (SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`account_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
  139. "`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,"
  140. "`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,"
  141. "`expire_time`,`bound`,`unique_id`"
  142. " FROM `%s` LIMIT 1;", storage_table.second->table)) {
  143. Sql_ShowDebug(sql_handle);
  144. }else{
  145. Sql_FreeResult(sql_handle);
  146. }
  147. }
  148. }
  149. //---------------------------------------------------------
  150. // storage data initialize
  151. void inter_storage_sql_init(void)
  152. {
  153. inter_storage_checkDB();
  154. return;
  155. }
  156. // storage data finalize
  157. void inter_storage_sql_final(void)
  158. {
  159. return;
  160. }
  161. //---------------------------------------------------------
  162. // packet from map server
  163. bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
  164. {
  165. if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) )
  166. Sql_ShowDebug(sql_handle);
  167. else if( Sql_NumRows(sql_handle) > 0 )
  168. {// guild exists
  169. WFIFOHEAD(fd, sizeof(struct s_storage)+13);
  170. WFIFOW(fd,0) = 0x3818;
  171. WFIFOW(fd,2) = sizeof(struct s_storage)+13;
  172. WFIFOL(fd,4) = account_id;
  173. WFIFOL(fd,8) = guild_id;
  174. WFIFOB(fd,12) = flag; //1 open storage, 0 don't open
  175. guild_storage_fromsql(guild_id, (struct s_storage*)WFIFOP(fd,13));
  176. WFIFOSET(fd, WFIFOW(fd,2));
  177. return false;
  178. }
  179. // guild does not exist
  180. Sql_FreeResult(sql_handle);
  181. WFIFOHEAD(fd, 12);
  182. WFIFOW(fd,0) = 0x3818;
  183. WFIFOW(fd,2) = 12;
  184. WFIFOL(fd,4) = account_id;
  185. WFIFOL(fd,8) = 0;
  186. WFIFOSET(fd, 12);
  187. return true;
  188. }
  189. void mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail)
  190. {
  191. WFIFOHEAD(fd,11);
  192. WFIFOW(fd,0)=0x3819;
  193. WFIFOL(fd,2)=account_id;
  194. WFIFOL(fd,6)=guild_id;
  195. WFIFOB(fd,10)=fail;
  196. WFIFOSET(fd,11);
  197. }
  198. //---------------------------------------------------------
  199. // packet from map server
  200. void mapif_parse_LoadGuildStorage(int fd)
  201. {
  202. RFIFOHEAD(fd);
  203. mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1);
  204. }
  205. bool mapif_parse_SaveGuildStorage(int fd)
  206. {
  207. int guild_id;
  208. int len;
  209. RFIFOHEAD(fd);
  210. guild_id = RFIFOL(fd,8);
  211. len = RFIFOW(fd,2);
  212. if( sizeof(struct s_storage) != len - 12 )
  213. {
  214. ShowError("inter storage: data size error %d != %d\n", sizeof(struct s_storage), len - 12);
  215. }
  216. else
  217. {
  218. if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) )
  219. Sql_ShowDebug(sql_handle);
  220. else if( Sql_NumRows(sql_handle) > 0 )
  221. {// guild exists
  222. Sql_FreeResult(sql_handle);
  223. guild_storage_tosql(guild_id, (struct s_storage*)RFIFOP(fd,12));
  224. mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0);
  225. return false;
  226. }
  227. Sql_FreeResult(sql_handle);
  228. }
  229. mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1);
  230. return true;
  231. }
  232. #ifdef BOUND_ITEMS
  233. /**
  234. * IZ 0x3856 <account_id>.L <guild_id>.W
  235. * Tells map-server if the process if complete, unlock the guild storage
  236. */
  237. void mapif_itembound_ack(int fd, int account_id, int guild_id)
  238. {
  239. WFIFOHEAD(fd,8);
  240. WFIFOW(fd,0) = 0x3856;
  241. WFIFOL(fd,2) = account_id;
  242. WFIFOW(fd,6) = guild_id;
  243. WFIFOSET(fd,8);
  244. char_unset_session_flag(account_id, 1);
  245. }
  246. /**
  247. * IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
  248. * Send the retrieved guild bound items to map-server, store them to guild storage.
  249. * By using this method, stackable items will looks how it should be, and overflowed
  250. * item's stack won't disturbs the guild storage table and the leftover items (when
  251. * storage is full) will be discarded.
  252. * @param fd
  253. * @param guild_id
  254. * @param items[]
  255. * @param count
  256. * @author [Cydh]
  257. */
  258. void mapif_itembound_store2gstorage(int fd, int guild_id, struct item items[], unsigned short count) {
  259. int size = 8 + sizeof(struct item) * MAX_INVENTORY, i;
  260. WFIFOHEAD(fd, size);
  261. WFIFOW(fd, 0) = 0x3857;
  262. WFIFOW(fd, 2) = size;
  263. WFIFOW(fd, 6) = guild_id;
  264. for (i = 0; i < count && i < MAX_INVENTORY; i++) {
  265. if (!&items[i])
  266. continue;
  267. memcpy(WFIFOP(fd, 8 + (i * sizeof(struct item))), &items[i], sizeof(struct item));
  268. }
  269. WFIFOW(fd, 4) = i;
  270. WFIFOSET(fd, size);
  271. }
  272. /**
  273. * ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
  274. * Pulls guild bound items for offline characters
  275. * @author [Akinari]
  276. */
  277. bool mapif_parse_itembound_retrieve(int fd)
  278. {
  279. StringBuf buf;
  280. SqlStmt* stmt;
  281. unsigned short i = 0, count = 0;
  282. struct item item, items[MAX_INVENTORY];
  283. int j, guild_id = RFIFOW(fd,10);
  284. uint32 char_id = RFIFOL(fd,2), account_id = RFIFOL(fd,6);
  285. StringBuf_Init(&buf);
  286. // Get bound items from player's inventory
  287. StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
  288. for( j = 0; j < MAX_SLOTS; ++j )
  289. StringBuf_Printf(&buf, ", `card%d`", j);
  290. for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
  291. StringBuf_Printf(&buf, ", `option_id%d`", j);
  292. StringBuf_Printf(&buf, ", `option_val%d`", j);
  293. StringBuf_Printf(&buf, ", `option_parm%d`", j);
  294. }
  295. StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = %d", schema_config.inventory_db,char_id, BOUND_GUILD);
  296. stmt = SqlStmt_Malloc(sql_handle);
  297. if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
  298. SQL_ERROR == SqlStmt_Execute(stmt) )
  299. {
  300. SqlStmt_ShowDebug(stmt);
  301. SqlStmt_Free(stmt);
  302. StringBuf_Destroy(&buf);
  303. mapif_itembound_ack(fd,account_id,guild_id);
  304. return true;
  305. }
  306. SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
  307. SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &item.nameid, 0, NULL, NULL);
  308. SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
  309. SqlStmt_BindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL);
  310. SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
  311. SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
  312. SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
  313. SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
  314. SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL);
  315. for( j = 0; j < MAX_SLOTS; ++j )
  316. SqlStmt_BindColumn(stmt, 9+j, SQLDT_USHORT, &item.card[j], 0, NULL, NULL);
  317. for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
  318. SqlStmt_BindColumn(stmt, 9+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].id, 0, NULL, NULL);
  319. SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+j*3, SQLDT_SHORT, &item.option[j].value, 0, NULL, NULL);
  320. SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+j*3, SQLDT_CHAR, &item.option[j].param, 0, NULL, NULL);
  321. }
  322. memset(&items, 0, sizeof(items));
  323. while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
  324. memcpy(&items[count++], &item, sizeof(struct item));
  325. Sql_FreeResult(sql_handle);
  326. ShowInfo("Found '" CL_WHITE "%d" CL_RESET "' guild bound item(s) from CID = " CL_WHITE "%d" CL_RESET ", AID = %d, Guild ID = " CL_WHITE "%d" CL_RESET ".\n", count, char_id, account_id, guild_id);
  327. if (!count) { //No items found - No need to continue
  328. StringBuf_Destroy(&buf);
  329. SqlStmt_Free(stmt);
  330. mapif_itembound_ack(fd,account_id,guild_id);
  331. return true;
  332. }
  333. char_set_session_flag(account_id, 1);
  334. // Delete bound items from player's inventory
  335. StringBuf_Clear(&buf);
  336. StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE `char_id` = %d AND `bound` = %d",schema_config.inventory_db, char_id, BOUND_GUILD);
  337. if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
  338. SQL_ERROR == SqlStmt_Execute(stmt) )
  339. {
  340. SqlStmt_ShowDebug(stmt);
  341. SqlStmt_Free(stmt);
  342. StringBuf_Destroy(&buf);
  343. mapif_itembound_ack(fd,account_id,guild_id);
  344. return true;
  345. }
  346. // Send the deleted items to map-server to store them in guild storage [Cydh]
  347. mapif_itembound_store2gstorage(fd, guild_id, items, count);
  348. // Verifies equip bitmasks (see item.equip) and handles the sql statement
  349. #define CHECK_REMOVE(var,mask,token,num) {\
  350. if ((var)&(mask) && !(j&(num))) {\
  351. if (j)\
  352. StringBuf_AppendStr(&buf, ",");\
  353. StringBuf_AppendStr(&buf, "`"#token"`='0'");\
  354. j |= (1<<num);\
  355. }\
  356. }
  357. StringBuf_Clear(&buf);
  358. j = 0;
  359. for (i = 0; i < count && i < MAX_INVENTORY; i++) {
  360. if (!&items[i] || !items[i].equip)
  361. continue;
  362. // Equips can be at more than one slot at the same time
  363. CHECK_REMOVE(items[i].equip, EQP_HAND_R, weapon, 0);
  364. CHECK_REMOVE(items[i].equip, EQP_HAND_L, shield, 1);
  365. CHECK_REMOVE(items[i].equip, EQP_HEAD_TOP|EQP_COSTUME_HEAD_TOP, head_top, 2);
  366. CHECK_REMOVE(items[i].equip, EQP_HEAD_MID|EQP_COSTUME_HEAD_MID, head_mid, 3);
  367. CHECK_REMOVE(items[i].equip, EQP_HEAD_LOW|EQP_COSTUME_HEAD_LOW, head_bottom, 4);
  368. CHECK_REMOVE(items[i].equip, EQP_GARMENT|EQP_COSTUME_GARMENT, robe, 5);
  369. }
  370. #undef CHECK_REMOVE
  371. // Update player's view
  372. if (j) {
  373. StringBuf buf2;
  374. StringBuf_Init(&buf2);
  375. StringBuf_Printf(&buf2, "UPDATE `%s` SET %s WHERE `char_id`='%d'", schema_config.char_db, StringBuf_Value(&buf), char_id);
  376. if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
  377. SQL_ERROR == SqlStmt_Execute(stmt) )
  378. {
  379. SqlStmt_ShowDebug(stmt);
  380. SqlStmt_Free(stmt);
  381. StringBuf_Destroy(&buf);
  382. StringBuf_Destroy(&buf2);
  383. mapif_itembound_ack(fd,account_id,guild_id);
  384. return true;
  385. }
  386. StringBuf_Destroy(&buf2);
  387. }
  388. StringBuf_Destroy(&buf);
  389. SqlStmt_Free(stmt);
  390. char_unset_session_flag(account_id, 1);
  391. return false;
  392. }
  393. #endif
  394. /*==========================================
  395. * Storages (Inventory/Storage/Cart)
  396. *------------------------------------------*/
  397. /**
  398. * Sending inventory/cart/storage data to player
  399. * IZ 0x388a <size>.W <type>.B <account_id>.L <result>.B <inventory>.?B
  400. * @param fd
  401. * @param account_id
  402. * @param type
  403. * @param entries Inventory/cart/storage entries
  404. * @param result
  405. */
  406. void mapif_storage_data_loaded(int fd, uint32 account_id, char type, struct s_storage entries, bool result) {
  407. uint16 size = sizeof(struct s_storage) + 10;
  408. WFIFOHEAD(fd, size);
  409. WFIFOW(fd, 0) = 0x388a;
  410. WFIFOW(fd, 2) = size;
  411. WFIFOB(fd, 4) = type;
  412. WFIFOL(fd, 5) = account_id;
  413. WFIFOB(fd, 9) = result;
  414. memcpy(WFIFOP(fd, 10), &entries, sizeof(struct s_storage));
  415. WFIFOSET(fd, size);
  416. }
  417. /**
  418. * Tells player if inventory/cart/storage is saved
  419. * IZ 0x388b <account_id>.L <result>.B <type>.B
  420. * @param fd
  421. * @param account_id
  422. * @param char_id
  423. * @param success
  424. * @param type
  425. * @param stor_id
  426. */
  427. void mapif_storage_saved(int fd, uint32 account_id, uint32 char_id, bool success, char type, uint8 stor_id) {
  428. WFIFOHEAD(fd,9);
  429. WFIFOW(fd, 0) = 0x388b;
  430. WFIFOL(fd, 2) = account_id;
  431. WFIFOB(fd, 6) = success;
  432. WFIFOB(fd, 7) = type;
  433. WFIFOB(fd, 8) = stor_id;
  434. WFIFOSET(fd,9);
  435. }
  436. /**
  437. * Requested inventory/cart/storage data for a player
  438. * ZI 0x308a <type>.B <account_id>.L <char_id>.L <storage_id>.B <mode>.B
  439. * @param fd
  440. */
  441. bool mapif_parse_StorageLoad(int fd) {
  442. uint32 aid, cid;
  443. int type;
  444. uint8 stor_id, mode;
  445. struct s_storage stor;
  446. bool res = true;
  447. type = RFIFOB(fd,2);
  448. aid = RFIFOL(fd,3);
  449. cid = RFIFOL(fd,7);
  450. stor_id = RFIFOB(fd,11);
  451. memset(&stor, 0, sizeof(struct s_storage));
  452. stor.stor_id = stor_id;
  453. //ShowInfo("Loading storage for AID=%d.\n", aid);
  454. switch (type) {
  455. case TABLE_INVENTORY: res = inventory_fromsql(cid, &stor); break;
  456. case TABLE_STORAGE:
  457. if (!inter_premiumStorage_exists(stor_id)) {
  458. ShowError("Invalid storage with id %d\n", stor_id);
  459. return false;
  460. }
  461. res = storage_fromsql(aid, &stor);
  462. break;
  463. case TABLE_CART: res = cart_fromsql(cid, &stor); break;
  464. default: return false;
  465. }
  466. mode = RFIFOB(fd, 12);
  467. stor.state.put = (mode&STOR_MODE_PUT) ? 1 : 0;
  468. stor.state.get = (mode&STOR_MODE_GET) ? 1 : 0;
  469. mapif_storage_data_loaded(fd, aid, type, stor, res);
  470. return true;
  471. }
  472. /**
  473. * Asking to save player's inventory/cart/storage data
  474. * ZI 0x308b <size>.W <type>.B <account_id>.L <char_id>.L <entries>.?B
  475. * @param fd
  476. */
  477. bool mapif_parse_StorageSave(int fd) {
  478. int aid, cid, type;
  479. struct s_storage stor;
  480. RFIFOHEAD(fd);
  481. type = RFIFOB(fd, 4);
  482. aid = RFIFOL(fd, 5);
  483. cid = RFIFOL(fd, 9);
  484. memset(&stor, 0, sizeof(struct s_storage));
  485. memcpy(&stor, RFIFOP(fd, 13), sizeof(struct s_storage));
  486. //ShowInfo("Saving storage data for AID=%d.\n", aid);
  487. switch(type){
  488. case TABLE_INVENTORY: inventory_tosql(cid, &stor); break;
  489. case TABLE_STORAGE:
  490. if (!inter_premiumStorage_exists(stor.stor_id)) {
  491. ShowError("Invalid storage with id %d\n", stor.stor_id);
  492. return false;
  493. }
  494. storage_tosql(aid, &stor);
  495. break;
  496. case TABLE_CART: cart_tosql(cid, &stor); break;
  497. default: return false;
  498. }
  499. mapif_storage_saved(fd, aid, cid, true, type, stor.stor_id);
  500. return false;
  501. }
  502. /*==========================================
  503. * Parse packet from map-server
  504. *------------------------------------------*/
  505. bool inter_storage_parse_frommap(int fd)
  506. {
  507. RFIFOHEAD(fd);
  508. switch(RFIFOW(fd,0)){
  509. case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
  510. case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
  511. #ifdef BOUND_ITEMS
  512. case 0x3056: mapif_parse_itembound_retrieve(fd); break;
  513. #endif
  514. case 0x308a: mapif_parse_StorageLoad(fd); break;
  515. case 0x308b: mapif_parse_StorageSave(fd); break;
  516. default:
  517. return false;
  518. }
  519. return true;
  520. }