storage.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/cbasetypes.h"
  4. #include "../common/db.h"
  5. #include "../common/nullpo.h"
  6. #include "../common/malloc.h"
  7. #include "../common/showmsg.h"
  8. #include "map.h" // struct map_session_data
  9. #include "storage.h"
  10. #include "chrif.h"
  11. #include "itemdb.h"
  12. #include "clif.h"
  13. #include "intif.h"
  14. #include "pc.h"
  15. #include "guild.h"
  16. #include "battle.h"
  17. #include "atcommand.h"
  18. #include "log.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. static DBMap* guild_storage_db; // int guild_id -> struct guild_storage*
  23. /*==========================================
  24. * 倉庫内アイテムソート
  25. *------------------------------------------*/
  26. static int storage_comp_item(const void *_i1, const void *_i2)
  27. {
  28. struct item *i1 = (struct item *)_i1;
  29. struct item *i2 = (struct item *)_i2;
  30. if (i1->nameid == i2->nameid)
  31. return 0;
  32. else if (!(i1->nameid) || !(i1->amount))
  33. return 1;
  34. else if (!(i2->nameid) || !(i2->amount))
  35. return -1;
  36. return i1->nameid - i2->nameid;
  37. }
  38. static void storage_sortitem(struct item* items, unsigned int size)
  39. {
  40. nullpo_retv(items);
  41. if( battle_config.client_sort_storage )
  42. {
  43. qsort(items, size, sizeof(struct item), storage_comp_item);
  44. }
  45. }
  46. /*==========================================
  47. * 初期化とか
  48. *------------------------------------------*/
  49. int do_init_storage(void) // map.c::do_init()から呼ばれる
  50. {
  51. guild_storage_db=idb_alloc(DB_OPT_RELEASE_DATA);
  52. return 1;
  53. }
  54. void do_final_storage(void) // by [MC Cameri]
  55. {
  56. guild_storage_db->destroy(guild_storage_db,NULL);
  57. }
  58. /**
  59. * Parses storage and saves 'dirty' ones upon reconnect. [Skotlex]
  60. * @see DBApply
  61. */
  62. static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
  63. {
  64. struct guild_storage *stor = db_data2ptr(data);
  65. if (stor->dirty && stor->storage_status == 0) //Save closed storages.
  66. storage_guild_storagesave(0, stor->guild_id,0);
  67. return 0;
  68. }
  69. //Function to be invoked upon server reconnection to char. To save all 'dirty' storages [Skotlex]
  70. void do_reconnect_storage(void)
  71. {
  72. guild_storage_db->foreach(guild_storage_db, storage_reconnect_sub);
  73. }
  74. /*==========================================
  75. * Opens a storage. Returns:
  76. * 0 - success
  77. * 1 - fail
  78. *------------------------------------------*/
  79. int storage_storageopen(struct map_session_data *sd)
  80. {
  81. nullpo_ret(sd);
  82. if(sd->state.storage_flag)
  83. return 1; //Already open?
  84. if( !pc_can_give_items(sd) )
  85. { //check is this GM level is allowed to put items to storage
  86. clif_displaymessage(sd->fd, msg_txt(246));
  87. return 1;
  88. }
  89. sd->state.storage_flag = 1;
  90. storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
  91. clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
  92. clif_updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
  93. return 0;
  94. }
  95. // helper function
  96. int compare_item(struct item *a, struct item *b)
  97. {
  98. if( a->nameid == b->nameid &&
  99. a->identify == b->identify &&
  100. a->refine == b->refine &&
  101. a->attribute == b->attribute &&
  102. a->expire_time == b->expire_time )
  103. {
  104. int i;
  105. for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
  106. return (i == MAX_SLOTS);
  107. }
  108. return 0;
  109. }
  110. /*==========================================
  111. * Internal add-item function.
  112. *------------------------------------------*/
  113. static int storage_additem(struct map_session_data* sd, struct item* item_data, int amount)
  114. {
  115. struct storage_data* stor = &sd->status.storage;
  116. struct item_data *data;
  117. int i;
  118. if( item_data->nameid <= 0 || amount <= 0 )
  119. return 1;
  120. data = itemdb_search(item_data->nameid);
  121. if( !itemdb_canstore(item_data, pc_get_group_level(sd)) )
  122. { //Check if item is storable. [Skotlex]
  123. clif_displaymessage (sd->fd, msg_txt(264));
  124. return 1;
  125. }
  126. if( itemdb_isstackable2(data) )
  127. {//Stackable
  128. for( i = 0; i < MAX_STORAGE; i++ )
  129. {
  130. if( compare_item(&stor->items[i], item_data) )
  131. {// existing items found, stack them
  132. if( amount > MAX_AMOUNT - stor->items[i].amount )
  133. return 1;
  134. stor->items[i].amount += amount;
  135. clif_storageitemadded(sd,&stor->items[i],i,amount);
  136. return 0;
  137. }
  138. }
  139. }
  140. // find free slot
  141. ARR_FIND( 0, MAX_STORAGE, i, stor->items[i].nameid == 0 );
  142. if( i >= MAX_STORAGE )
  143. return 1;
  144. // add item to slot
  145. memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
  146. stor->storage_amount++;
  147. stor->items[i].amount = amount;
  148. clif_storageitemadded(sd,&stor->items[i],i,amount);
  149. clif_updatestorageamount(sd, stor->storage_amount, MAX_STORAGE);
  150. return 0;
  151. }
  152. /*==========================================
  153. * Internal del-item function
  154. *------------------------------------------*/
  155. int storage_delitem(struct map_session_data* sd, int n, int amount)
  156. {
  157. if( sd->status.storage.items[n].nameid == 0 || sd->status.storage.items[n].amount < amount )
  158. return 1;
  159. sd->status.storage.items[n].amount -= amount;
  160. if( sd->status.storage.items[n].amount == 0 )
  161. {
  162. memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
  163. sd->status.storage.storage_amount--;
  164. if( sd->state.storage_flag == 1 ) clif_updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
  165. }
  166. if( sd->state.storage_flag == 1 ) clif_storageitemremoved(sd,n,amount);
  167. return 0;
  168. }
  169. /*==========================================
  170. * Add an item to the storage from the inventory.
  171. *------------------------------------------*/
  172. int storage_storageadd(struct map_session_data* sd, int index, int amount)
  173. {
  174. nullpo_ret(sd);
  175. if( sd->status.storage.storage_amount > MAX_STORAGE )
  176. return 0; // storage full
  177. if( index < 0 || index >= MAX_INVENTORY )
  178. return 0;
  179. if( sd->status.inventory[index].nameid <= 0 )
  180. return 0; // No item on that spot
  181. if( amount < 1 || amount > sd->status.inventory[index].amount )
  182. return 0;
  183. if( storage_additem(sd,&sd->status.inventory[index],amount) == 0 )
  184. pc_delitem(sd,index,amount,0,4,LOG_TYPE_STORAGE);
  185. return 1;
  186. }
  187. /*==========================================
  188. * Retrieve an item from the storage.
  189. *------------------------------------------*/
  190. int storage_storageget(struct map_session_data* sd, int index, int amount)
  191. {
  192. int flag;
  193. if( index < 0 || index >= MAX_STORAGE )
  194. return 0;
  195. if( sd->status.storage.items[index].nameid <= 0 )
  196. return 0; //Nothing there
  197. if( amount < 1 || amount > sd->status.storage.items[index].amount )
  198. return 0;
  199. if( (flag = pc_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
  200. storage_delitem(sd,index,amount);
  201. else
  202. clif_additem(sd,0,0,flag);
  203. return 1;
  204. }
  205. /*==========================================
  206. * Move an item from cart to storage.
  207. *------------------------------------------*/
  208. int storage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
  209. {
  210. nullpo_ret(sd);
  211. if( sd->status.storage.storage_amount > MAX_STORAGE )
  212. return 0; // storage full / storage closed
  213. if( index < 0 || index >= MAX_CART )
  214. return 0;
  215. if( sd->status.cart[index].nameid <= 0 )
  216. return 0; //No item there.
  217. if( amount < 1 || amount > sd->status.cart[index].amount )
  218. return 0;
  219. if( storage_additem(sd,&sd->status.cart[index],amount) == 0 )
  220. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
  221. return 1;
  222. }
  223. /*==========================================
  224. * Get from Storage to the Cart
  225. *------------------------------------------*/
  226. int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
  227. {
  228. nullpo_ret(sd);
  229. if( index < 0 || index >= MAX_STORAGE )
  230. return 0;
  231. if( sd->status.storage.items[index].nameid <= 0 )
  232. return 0; //Nothing there.
  233. if( amount < 1 || amount > sd->status.storage.items[index].amount )
  234. return 0;
  235. if( pc_cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE) == 0 )
  236. storage_delitem(sd,index,amount);
  237. return 1;
  238. }
  239. /*==========================================
  240. * Modified By Valaris to save upon closing [massdriller]
  241. *------------------------------------------*/
  242. void storage_storageclose(struct map_session_data* sd)
  243. {
  244. nullpo_retv(sd);
  245. clif_storageclose(sd);
  246. if( save_settings&4 )
  247. chrif_save(sd,0); //Invokes the storage saving as well.
  248. sd->state.storage_flag = 0;
  249. }
  250. /*==========================================
  251. * When quitting the game.
  252. *------------------------------------------*/
  253. void storage_storage_quit(struct map_session_data* sd, int flag)
  254. {
  255. nullpo_retv(sd);
  256. if (save_settings&4)
  257. chrif_save(sd, flag); //Invokes the storage saving as well.
  258. sd->state.storage_flag = 0;
  259. }
  260. /**
  261. * @see DBCreateData
  262. */
  263. static DBData create_guildstorage(DBKey key, va_list args)
  264. {
  265. struct guild_storage *gs = NULL;
  266. gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1);
  267. gs->guild_id=key.i;
  268. return db_ptr2data(gs);
  269. }
  270. struct guild_storage *guild2storage(int guild_id)
  271. {
  272. struct guild_storage *gs = NULL;
  273. if(guild_search(guild_id) != NULL)
  274. gs = idb_ensure(guild_storage_db,guild_id,create_guildstorage);
  275. return gs;
  276. }
  277. struct guild_storage *guild2storage2(int guild_id)
  278. { //For just locating a storage without creating one. [Skotlex]
  279. return (struct guild_storage*)idb_get(guild_storage_db,guild_id);
  280. }
  281. int guild_storage_delete(int guild_id)
  282. {
  283. idb_remove(guild_storage_db,guild_id);
  284. return 0;
  285. }
  286. int storage_guild_storageopen(struct map_session_data* sd)
  287. {
  288. struct guild_storage *gstor;
  289. nullpo_ret(sd);
  290. if(sd->status.guild_id <= 0)
  291. return 2;
  292. if(sd->state.storage_flag)
  293. return 1; //Can't open both storages at a time.
  294. if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
  295. clif_displaymessage(sd->fd, msg_txt(246));
  296. return 1;
  297. }
  298. if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
  299. intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
  300. return 0;
  301. }
  302. if(gstor->storage_status)
  303. return 1;
  304. gstor->storage_status = 1;
  305. sd->state.storage_flag = 2;
  306. storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
  307. clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
  308. clif_updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE);
  309. return 0;
  310. }
  311. int guild_storage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item_data, int amount)
  312. {
  313. struct item_data *data;
  314. int i;
  315. nullpo_retr(1, sd);
  316. nullpo_retr(1, stor);
  317. nullpo_retr(1, item_data);
  318. if(item_data->nameid <= 0 || amount <= 0)
  319. return 1;
  320. data = itemdb_search(item_data->nameid);
  321. if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time )
  322. { //Check if item is storable. [Skotlex]
  323. clif_displaymessage (sd->fd, msg_txt(264));
  324. return 1;
  325. }
  326. if(itemdb_isstackable2(data)){ //Stackable
  327. for(i=0;i<MAX_GUILD_STORAGE;i++){
  328. if(compare_item(&stor->items[i], item_data)) {
  329. if(stor->items[i].amount+amount > MAX_AMOUNT)
  330. return 1;
  331. stor->items[i].amount+=amount;
  332. clif_storageitemadded(sd,&stor->items[i],i,amount);
  333. stor->dirty = 1;
  334. return 0;
  335. }
  336. }
  337. }
  338. //Add item
  339. for(i=0;i<MAX_GUILD_STORAGE && stor->items[i].nameid;i++);
  340. if(i>=MAX_GUILD_STORAGE)
  341. return 1;
  342. memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
  343. stor->items[i].amount=amount;
  344. stor->storage_amount++;
  345. clif_storageitemadded(sd,&stor->items[i],i,amount);
  346. clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
  347. stor->dirty = 1;
  348. return 0;
  349. }
  350. int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
  351. {
  352. nullpo_retr(1, sd);
  353. nullpo_retr(1, stor);
  354. if(stor->items[n].nameid==0 || stor->items[n].amount<amount)
  355. return 1;
  356. stor->items[n].amount-=amount;
  357. if(stor->items[n].amount==0){
  358. memset(&stor->items[n],0,sizeof(stor->items[0]));
  359. stor->storage_amount--;
  360. clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
  361. }
  362. clif_storageitemremoved(sd,n,amount);
  363. stor->dirty = 1;
  364. return 0;
  365. }
  366. int storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
  367. {
  368. struct guild_storage *stor;
  369. nullpo_ret(sd);
  370. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  371. if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
  372. return 0;
  373. if( index<0 || index>=MAX_INVENTORY )
  374. return 0;
  375. if( sd->status.inventory[index].nameid <= 0 )
  376. return 0;
  377. if( amount < 1 || amount > sd->status.inventory[index].amount )
  378. return 0;
  379. if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
  380. pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
  381. return 1;
  382. }
  383. int storage_guild_storageget(struct map_session_data* sd, int index, int amount)
  384. {
  385. struct guild_storage *stor;
  386. int flag;
  387. nullpo_ret(sd);
  388. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  389. if(!stor->storage_status)
  390. return 0;
  391. if(index<0 || index>=MAX_GUILD_STORAGE)
  392. return 0;
  393. if(stor->items[index].nameid <= 0)
  394. return 0;
  395. if(amount < 1 || amount > stor->items[index].amount)
  396. return 0;
  397. if((flag = pc_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
  398. guild_storage_delitem(sd,stor,index,amount);
  399. else
  400. clif_additem(sd,0,0,flag);
  401. // log_fromstorage(sd, index, 1);
  402. return 0;
  403. }
  404. int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
  405. {
  406. struct guild_storage *stor;
  407. nullpo_ret(sd);
  408. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  409. if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
  410. return 0;
  411. if( index < 0 || index >= MAX_CART )
  412. return 0;
  413. if( sd->status.cart[index].nameid <= 0 )
  414. return 0;
  415. if( amount < 1 || amount > sd->status.cart[index].amount )
  416. return 0;
  417. if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
  418. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
  419. return 1;
  420. }
  421. int storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
  422. {
  423. struct guild_storage *stor;
  424. nullpo_ret(sd);
  425. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  426. if(!stor->storage_status)
  427. return 0;
  428. if(index<0 || index>=MAX_GUILD_STORAGE)
  429. return 0;
  430. if(stor->items[index].nameid<=0)
  431. return 0;
  432. if(amount < 1 || amount > stor->items[index].amount)
  433. return 0;
  434. if(pc_cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)==0)
  435. guild_storage_delitem(sd,stor,index,amount);
  436. return 1;
  437. }
  438. int storage_guild_storagesave(int account_id, int guild_id, int flag)
  439. {
  440. struct guild_storage *stor = guild2storage2(guild_id);
  441. if(stor)
  442. {
  443. if (flag) //Char quitting, close it.
  444. stor->storage_status = 0;
  445. if (stor->dirty)
  446. intif_send_guild_storage(account_id,stor);
  447. return 1;
  448. }
  449. return 0;
  450. }
  451. int storage_guild_storagesaved(int guild_id)
  452. {
  453. struct guild_storage *stor;
  454. if((stor=guild2storage2(guild_id)) != NULL) {
  455. if (stor->dirty && stor->storage_status == 0)
  456. { //Storage has been correctly saved.
  457. stor->dirty = 0;
  458. }
  459. return 1;
  460. }
  461. return 0;
  462. }
  463. int storage_guild_storageclose(struct map_session_data* sd)
  464. {
  465. struct guild_storage *stor;
  466. nullpo_ret(sd);
  467. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  468. clif_storageclose(sd);
  469. if (stor->storage_status)
  470. {
  471. if (save_settings&4)
  472. chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
  473. else
  474. storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
  475. stor->storage_status=0;
  476. }
  477. sd->state.storage_flag = 0;
  478. return 0;
  479. }
  480. int storage_guild_storage_quit(struct map_session_data* sd, int flag)
  481. {
  482. struct guild_storage *stor;
  483. nullpo_ret(sd);
  484. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  485. if(flag)
  486. { //Only during a guild break flag is 1 (don't save storage)
  487. sd->state.storage_flag = 0;
  488. stor->storage_status = 0;
  489. clif_storageclose(sd);
  490. if (save_settings&4)
  491. chrif_save(sd,0);
  492. return 0;
  493. }
  494. if(stor->storage_status) {
  495. if (save_settings&4)
  496. chrif_save(sd,0);
  497. else
  498. storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
  499. }
  500. sd->state.storage_flag = 0;
  501. stor->storage_status = 0;
  502. return 0;
  503. }