storage.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  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; ///Databases of guild_storage : int guild_id -> struct guild_storage*
  23. /**
  24. * Storage item comparator (for qsort)
  25. * sort by itemid and amount
  26. * @param _i1 : item a
  27. * @param _i2 : item b
  28. * @return i1<=>i2
  29. */
  30. static int storage_comp_item(const void *_i1, const void *_i2)
  31. {
  32. struct item *i1 = (struct item *)_i1;
  33. struct item *i2 = (struct item *)_i2;
  34. if (i1->nameid == i2->nameid)
  35. return 0;
  36. else if (!(i1->nameid) || !(i1->amount))
  37. return 1;
  38. else if (!(i2->nameid) || !(i2->amount))
  39. return -1;
  40. return i1->nameid - i2->nameid;
  41. }
  42. /**
  43. * Sort item by storage_comp_item (nameid)
  44. * used when we open up our storage or guild_storage
  45. * @param items : list of items to sort
  46. * @param size : number of item in list
  47. */
  48. static void storage_sortitem(struct item* items, unsigned int size)
  49. {
  50. nullpo_retv(items);
  51. if( battle_config.client_sort_storage )
  52. {
  53. qsort(items, size, sizeof(struct item), storage_comp_item);
  54. }
  55. }
  56. /**
  57. * Initiate storage module
  58. * Called from map.c::do_init()
  59. * @return 1
  60. */
  61. int do_init_storage(void) //
  62. {
  63. guild_storage_db=idb_alloc(DB_OPT_RELEASE_DATA);
  64. return 1;
  65. }
  66. /**
  67. * Destroy storage module
  68. * @author : [MC Cameri]
  69. * Called from map.c::do_final()
  70. */
  71. void do_final_storage(void)
  72. {
  73. guild_storage_db->destroy(guild_storage_db,NULL);
  74. }
  75. /**
  76. * Parses storage and saves 'dirty' ones upon reconnect.
  77. * @author [Skotlex]
  78. * @see DBApply
  79. * @return 0
  80. */
  81. static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
  82. {
  83. struct guild_storage *stor = db_data2ptr(data);
  84. if (stor->dirty && stor->storage_status == 0) //Save closed storages.
  85. storage_guild_storagesave(0, stor->guild_id,0);
  86. return 0;
  87. }
  88. /**
  89. * Function to be invoked upon server reconnection to char. To save all 'dirty' storages
  90. * @author [Skotlex]
  91. */
  92. void do_reconnect_storage(void)
  93. {
  94. guild_storage_db->foreach(guild_storage_db, storage_reconnect_sub);
  95. }
  96. /**
  97. * Player attempt tp open his storage.
  98. * @param sd : player
  99. * @return 0:success, 1:fail
  100. */
  101. int storage_storageopen(struct map_session_data *sd)
  102. {
  103. nullpo_ret(sd);
  104. if(sd->state.storage_flag)
  105. return 1; //Already open?
  106. if( !pc_can_give_items(sd) )
  107. { //check is this GM level is allowed to put items to storage
  108. clif_displaymessage(sd->fd, msg_txt(sd,246));
  109. return 1;
  110. }
  111. sd->state.storage_flag = 1;
  112. storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
  113. clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
  114. clif_updatestorageamount(sd, sd->status.storage.storage_amount, sd->storage_size);
  115. return 0;
  116. }
  117. /**
  118. * check if 2 item a and b have same values
  119. * @param a : item 1
  120. * @param b : item 2
  121. * @return 1:same, 0:are different
  122. */
  123. int compare_item(struct item *a, struct item *b)
  124. {
  125. if( a->nameid == b->nameid &&
  126. a->identify == b->identify &&
  127. a->refine == b->refine &&
  128. a->attribute == b->attribute &&
  129. a->expire_time == b->expire_time &&
  130. a->bound == b->bound )
  131. {
  132. int i;
  133. for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
  134. return (i == MAX_SLOTS);
  135. }
  136. return 0;
  137. }
  138. /**
  139. * Make a player add an item to his storage
  140. * @param sd : player
  141. * @param item_data : item to add
  142. * @param amount : quantity of items
  143. * @return 0:success, 1:failed
  144. */
  145. static int storage_additem(struct map_session_data* sd, struct item* item_data, int amount)
  146. {
  147. struct storage_data* stor = &sd->status.storage;
  148. struct item_data *data;
  149. int i;
  150. if( item_data->nameid <= 0 || amount <= 0 )
  151. return 1;
  152. data = itemdb_search(item_data->nameid);
  153. if( data->stack.storage && amount > data->stack.amount )
  154. {// item stack limitation
  155. return 1;
  156. }
  157. if( !itemdb_canstore(item_data, pc_get_group_level(sd)) )
  158. { //Check if item is storable. [Skotlex]
  159. clif_displaymessage (sd->fd, msg_txt(sd,264));
  160. return 1;
  161. }
  162. if( (item_data->bound > 1) && !pc_can_give_bounded_items(sd) ) {
  163. clif_displaymessage(sd->fd, msg_txt(sd,294));
  164. return 1;
  165. }
  166. if( itemdb_isstackable2(data) )
  167. {//Stackable
  168. for( i = 0; i < sd->storage_size; i++ )
  169. {
  170. if( compare_item(&stor->items[i], item_data) )
  171. {// existing items found, stack them
  172. if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) )
  173. return 1;
  174. stor->items[i].amount += amount;
  175. clif_storageitemadded(sd,&stor->items[i],i,amount);
  176. return 0;
  177. }
  178. }
  179. }
  180. // find free slot
  181. ARR_FIND( 0, sd->storage_size, i, stor->items[i].nameid == 0 );
  182. if( i >= sd->storage_size )
  183. return 1;
  184. // add item to slot
  185. memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
  186. stor->storage_amount++;
  187. stor->items[i].amount = amount;
  188. clif_storageitemadded(sd,&stor->items[i],i,amount);
  189. clif_updatestorageamount(sd, stor->storage_amount, sd->storage_size);
  190. return 0;
  191. }
  192. /**
  193. * Make a player delete an item from his storage
  194. * @param sd : player
  195. * @param n : idx on storage to remove the item from
  196. * @param amount :number of item to remove
  197. * @return 0:sucess, 1:fail
  198. */
  199. int storage_delitem(struct map_session_data* sd, int n, int amount)
  200. {
  201. if( sd->status.storage.items[n].nameid == 0 || sd->status.storage.items[n].amount < amount )
  202. return 1;
  203. sd->status.storage.items[n].amount -= amount;
  204. if( sd->status.storage.items[n].amount == 0 )
  205. {
  206. memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
  207. sd->status.storage.storage_amount--;
  208. if( sd->state.storage_flag == 1 ) clif_updatestorageamount(sd, sd->status.storage.storage_amount, sd->storage_size);
  209. }
  210. if( sd->state.storage_flag == 1 ) clif_storageitemremoved(sd,n,amount);
  211. return 0;
  212. }
  213. /**
  214. * Add an item to the storage from the inventory.
  215. * @param sd : player
  216. * @param index : inventory index to take the item from
  217. * @param amount : number of item to take
  218. * @return 0:fail, 1:success
  219. */
  220. int storage_storageadd(struct map_session_data* sd, int index, int amount)
  221. {
  222. nullpo_ret(sd);
  223. if( sd->status.storage.storage_amount > sd->storage_size )
  224. return 0; // storage full
  225. if( index < 0 || index >= MAX_INVENTORY )
  226. return 0;
  227. if( sd->status.inventory[index].nameid <= 0 )
  228. return 0; // No item on that spot
  229. if( amount < 1 || amount > sd->status.inventory[index].amount )
  230. return 0;
  231. if( storage_additem(sd,&sd->status.inventory[index],amount) == 0 )
  232. pc_delitem(sd,index,amount,0,4,LOG_TYPE_STORAGE);
  233. else {
  234. clif_dropitem(sd,index,0);
  235. return 0;
  236. }
  237. return 1;
  238. }
  239. /**
  240. * Retrieve an item from the storage into inventory
  241. * @param sd : player
  242. * @param index : storage index to take the item from
  243. * @param amount : number of item to take
  244. * @return 0:fail, 1:success
  245. */
  246. int storage_storageget(struct map_session_data* sd, int index, int amount)
  247. {
  248. int flag;
  249. if( index < 0 || index >= sd->storage_size )
  250. return 0;
  251. if( sd->status.storage.items[index].nameid <= 0 )
  252. return 0; //Nothing there
  253. if( amount < 1 || amount > sd->status.storage.items[index].amount )
  254. return 0;
  255. if( (flag = pc_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
  256. storage_delitem(sd,index,amount);
  257. else
  258. clif_additem(sd,0,0,flag);
  259. return 1;
  260. }
  261. /**
  262. * Move an item from cart to storage.
  263. * @param sd : player
  264. * @param index : cart index to take the item from
  265. * @param amount : number of item to take
  266. * @return 0:fail, 1:success
  267. */
  268. int storage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
  269. {
  270. nullpo_ret(sd);
  271. if( sd->status.storage.storage_amount > sd->storage_size )
  272. return 0; // storage full / storage closed
  273. if( index < 0 || index >= MAX_CART )
  274. return 0;
  275. if( sd->status.cart[index].nameid <= 0 )
  276. return 0; //No item there.
  277. if( amount < 1 || amount > sd->status.cart[index].amount )
  278. return 0;
  279. if( storage_additem(sd,&sd->status.cart[index],amount) == 0 )
  280. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
  281. return 1;
  282. }
  283. /**
  284. * Get from Storage to the Cart inventory
  285. * @param sd : player
  286. * @param index : storage index to take the item from
  287. * @param amount : number of item to take
  288. * @return 0:fail, 1:success
  289. */
  290. int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
  291. {
  292. short flag;
  293. nullpo_ret(sd);
  294. if( index < 0 || index >= sd->storage_size )
  295. return 0;
  296. if( sd->status.storage.items[index].nameid <= 0 )
  297. return 0; //Nothing there.
  298. if( amount < 1 || amount > sd->status.storage.items[index].amount )
  299. return 0;
  300. if( (flag = pc_cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
  301. storage_delitem(sd,index,amount);
  302. else {
  303. clif_dropitem(sd,index,0);
  304. clif_cart_additem_ack(sd,(flag==1)?ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
  305. }
  306. return 1;
  307. }
  308. /**
  309. * Make player close his storage
  310. * @author : [massdriller] / modified by [Valaris]
  311. * @param sd : player
  312. */
  313. void storage_storageclose(struct map_session_data* sd)
  314. {
  315. nullpo_retv(sd);
  316. clif_storageclose(sd);
  317. if( save_settings&4 )
  318. chrif_save(sd,0); //Invokes the storage saving as well.
  319. sd->state.storage_flag = 0;
  320. }
  321. /**
  322. * Force closing the storage for player without displaying result
  323. * (exemple when quitting the game)
  324. * @param sd : player to close storage
  325. * @param flag : \n
  326. * 1: Character is quitting \n
  327. * 2(x): Character is changing map-servers
  328. */
  329. void storage_storage_quit(struct map_session_data* sd, int flag)
  330. {
  331. nullpo_retv(sd);
  332. if (save_settings&4)
  333. chrif_save(sd, flag); //Invokes the storage saving as well.
  334. sd->state.storage_flag = 0;
  335. }
  336. /**
  337. * Create a guild_storage stucture and add it into the db
  338. * @see DBCreateData
  339. * @param key
  340. * @param args
  341. * @return
  342. */
  343. static DBData create_guildstorage(DBKey key, va_list args)
  344. {
  345. struct guild_storage *gs = NULL;
  346. gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1);
  347. gs->guild_id=key.i;
  348. return db_ptr2data(gs);
  349. }
  350. /**
  351. * Retrieve the guild_storage of a guild
  352. * will create a new storage if none found for the guild
  353. * @param guild_id : id of the guild
  354. * @return guild_storage
  355. */
  356. struct guild_storage *guild2storage(int guild_id)
  357. {
  358. struct guild_storage *gs = NULL;
  359. if(guild_search(guild_id) != NULL)
  360. gs = idb_ensure(guild_storage_db,guild_id,create_guildstorage);
  361. return gs;
  362. }
  363. /**
  364. * See if the guild_storage exist in db and fetch it if it,s the case
  365. * @author : [Skotlex]
  366. * @param guild_id : guild_id to search the storage
  367. * @return guild_storage or NULL
  368. */
  369. struct guild_storage *guild2storage2(int guild_id)
  370. {
  371. return (struct guild_storage*)idb_get(guild_storage_db,guild_id);
  372. }
  373. /**
  374. * Delete a guild_storage and remove it from db
  375. * @param guild_id : guild to remove the storage from
  376. * @return 0
  377. */
  378. int guild_storage_delete(int guild_id)
  379. {
  380. idb_remove(guild_storage_db,guild_id);
  381. return 0;
  382. }
  383. /**
  384. * Attempt to open guild storage for player
  385. * @param sd : player
  386. * @return * 0 : success, 1 : fail, 2 : no guild found
  387. */
  388. int storage_guild_storageopen(struct map_session_data* sd)
  389. {
  390. struct guild_storage *gstor;
  391. nullpo_ret(sd);
  392. if(sd->status.guild_id <= 0)
  393. return 2;
  394. if(sd->state.storage_flag)
  395. return 1; //Can't open both storages at a time.
  396. if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
  397. clif_displaymessage(sd->fd, msg_txt(sd,246));
  398. return 1;
  399. }
  400. if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
  401. intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
  402. return 0;
  403. }
  404. if(gstor->storage_status)
  405. return 1;
  406. if( gstor->lock )
  407. return 1;
  408. gstor->storage_status = 1;
  409. sd->state.storage_flag = 2;
  410. storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
  411. clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
  412. clif_updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE);
  413. return 0;
  414. }
  415. /**
  416. * Attempt to add an item in guild storage, then refresh it
  417. * @param sd : player attempting to open the guild_storage
  418. * @param stor : guild_storage
  419. * @param item_data : item to add
  420. * @param amount : number of item to add
  421. * @return 0 : success, 1 : fail
  422. */
  423. int guild_storage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item_data, int amount)
  424. {
  425. struct item_data *data;
  426. int i;
  427. nullpo_retr(1, sd);
  428. nullpo_retr(1, stor);
  429. nullpo_retr(1, item_data);
  430. if(item_data->nameid <= 0 || amount <= 0)
  431. return 1;
  432. data = itemdb_search(item_data->nameid);
  433. if( data->stack.guildstorage && amount > data->stack.amount )
  434. {// item stack limitation
  435. return 1;
  436. }
  437. if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time )
  438. { //Check if item is storable. [Skotlex]
  439. clif_displaymessage (sd->fd, msg_txt(sd,264));
  440. return 1;
  441. }
  442. if( (item_data->bound == 1 || item_data->bound > 2) && !pc_can_give_bounded_items(sd) ) {
  443. clif_displaymessage(sd->fd, msg_txt(sd,294));
  444. return 1;
  445. }
  446. if(itemdb_isstackable2(data)){ //Stackable
  447. for(i=0;i<MAX_GUILD_STORAGE;i++){
  448. if(compare_item(&stor->items[i], item_data)) {
  449. if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.guildstorage && amount > data->stack.amount - stor->items[i].amount ) )
  450. return 1;
  451. stor->items[i].amount+=amount;
  452. clif_storageitemadded(sd,&stor->items[i],i,amount);
  453. stor->dirty = 1;
  454. return 0;
  455. }
  456. }
  457. }
  458. //Add item
  459. for(i=0;i<MAX_GUILD_STORAGE && stor->items[i].nameid;i++);
  460. if(i>=MAX_GUILD_STORAGE)
  461. return 1;
  462. memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
  463. stor->items[i].amount=amount;
  464. stor->storage_amount++;
  465. clif_storageitemadded(sd,&stor->items[i],i,amount);
  466. clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
  467. stor->dirty = 1;
  468. return 0;
  469. }
  470. /**
  471. * Attempt to delete an item in guild storage, then refresh it
  472. * @param sd : player
  473. * @param stor : guild_storage
  474. * @param n : index of item in guild storage
  475. * @param amount : number of item to delete
  476. * @return 0 : success, 1 : fail
  477. */
  478. int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
  479. {
  480. nullpo_retr(1, sd);
  481. nullpo_retr(1, stor);
  482. if(stor->items[n].nameid==0 || stor->items[n].amount<amount)
  483. return 1;
  484. stor->items[n].amount-=amount;
  485. if(stor->items[n].amount==0){
  486. memset(&stor->items[n],0,sizeof(stor->items[0]));
  487. stor->storage_amount--;
  488. clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
  489. }
  490. clif_storageitemremoved(sd,n,amount);
  491. stor->dirty = 1;
  492. return 0;
  493. }
  494. /**
  495. * Attempt to add an item in guild storage from inventory, then refresh it
  496. * @param sd : player
  497. * @param amount : number of item to delete
  498. * @return 1:success, 0:fail
  499. */
  500. int storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
  501. {
  502. struct guild_storage *stor;
  503. nullpo_ret(sd);
  504. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  505. if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
  506. return 0;
  507. if( index<0 || index>=MAX_INVENTORY )
  508. return 0;
  509. if( sd->status.inventory[index].nameid <= 0 )
  510. return 0;
  511. if( amount < 1 || amount > sd->status.inventory[index].amount )
  512. return 0;
  513. if( stor->lock ) {
  514. storage_guild_storageclose(sd);
  515. return 0;
  516. }
  517. if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
  518. pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
  519. else {
  520. clif_dropitem(sd,index,0);
  521. return 0;
  522. }
  523. return 1;
  524. }
  525. /**
  526. * Attempt to retrieve an item from guild storage to inventory, then refresh it
  527. * @param sd : player
  528. * @param index : index of item in storage
  529. * @param amount : number of item to get
  530. * @return 1:success, 0:fail
  531. */
  532. int storage_guild_storageget(struct map_session_data* sd, int index, int amount)
  533. {
  534. struct guild_storage *stor;
  535. int flag;
  536. nullpo_ret(sd);
  537. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  538. if(!stor->storage_status)
  539. return 0;
  540. if(index<0 || index>=MAX_GUILD_STORAGE)
  541. return 0;
  542. if(stor->items[index].nameid <= 0)
  543. return 0;
  544. if(amount < 1 || amount > stor->items[index].amount)
  545. return 0;
  546. if( stor->lock ) {
  547. storage_guild_storageclose(sd);
  548. return 0;
  549. }
  550. if((flag = pc_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
  551. guild_storage_delitem(sd,stor,index,amount);
  552. else {//inform fail
  553. clif_additem(sd,0,0,flag);
  554. return 0;
  555. }
  556. // log_fromstorage(sd, index, 1);
  557. return 1;
  558. }
  559. /**
  560. * Attempt to add an item in guild storage from cart, then refresh it
  561. * @param sd : player
  562. * @param index : index of item in cart
  563. * @param amount : number of item to transfer
  564. * @return 1:fail, 0:success
  565. */
  566. int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
  567. {
  568. struct guild_storage *stor;
  569. nullpo_ret(sd);
  570. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  571. if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
  572. return 0;
  573. if( index < 0 || index >= MAX_CART )
  574. return 0;
  575. if( sd->status.cart[index].nameid <= 0 )
  576. return 0;
  577. if( amount < 1 || amount > sd->status.cart[index].amount )
  578. return 0;
  579. if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
  580. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
  581. return 1;
  582. }
  583. /**
  584. * Attempt to retrieve an item from guild storage to cart, then refresh it
  585. * @param sd : player
  586. * @param index : index of item in storage
  587. * @param amount : number of item to transfert
  588. * @return 1:fail, 0:success
  589. */
  590. int storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
  591. {
  592. short flag;
  593. struct guild_storage *stor;
  594. nullpo_ret(sd);
  595. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  596. if(!stor->storage_status)
  597. return 0;
  598. if(index<0 || index>=MAX_GUILD_STORAGE)
  599. return 0;
  600. if(stor->items[index].nameid<=0)
  601. return 0;
  602. if(amount < 1 || amount > stor->items[index].amount)
  603. return 0;
  604. if((flag = pc_cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
  605. guild_storage_delitem(sd,stor,index,amount);
  606. else {
  607. clif_dropitem(sd,index,0);
  608. clif_cart_additem_ack(sd,(flag==1)?ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
  609. return 0;
  610. }
  611. return 1;
  612. }
  613. /**
  614. * Request to save guild storage
  615. * @param account_id : account requesting the save
  616. * @param guild_id : guild to take the guild_storage
  617. * @param flag : ?
  618. * @return 0 : fail (no storage), 1 : success (requested)
  619. */
  620. int storage_guild_storagesave(int account_id, int guild_id, int flag)
  621. {
  622. struct guild_storage *stor = guild2storage2(guild_id);
  623. if(stor)
  624. {
  625. if (flag) //Char quitting, close it.
  626. stor->storage_status = 0;
  627. if (stor->dirty)
  628. intif_send_guild_storage(account_id,stor);
  629. return 1;
  630. }
  631. return 0;
  632. }
  633. /**
  634. * ACK save of guild storage
  635. * @param guild_id : guild to use the storage
  636. * @return 0 : fail (no storage), 1 : succes
  637. */
  638. int storage_guild_storagesaved(int guild_id)
  639. {
  640. struct guild_storage *stor;
  641. if((stor=guild2storage2(guild_id)) != NULL) {
  642. if (stor->dirty && stor->storage_status == 0)
  643. { //Storage has been correctly saved.
  644. stor->dirty = 0;
  645. }
  646. return 1;
  647. }
  648. return 0;
  649. }
  650. /**
  651. * Close storage for player then save it
  652. * @param sd : player
  653. * @return 0
  654. */
  655. int storage_guild_storageclose(struct map_session_data* sd)
  656. {
  657. struct guild_storage *stor;
  658. nullpo_ret(sd);
  659. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  660. clif_storageclose(sd);
  661. if (stor->storage_status)
  662. {
  663. if (save_settings&4)
  664. chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
  665. else
  666. storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
  667. stor->storage_status=0;
  668. }
  669. sd->state.storage_flag = 0;
  670. return 0;
  671. }
  672. /**
  673. * Close storage for player then save it
  674. * @param sd
  675. * @param flag
  676. * @return
  677. */
  678. int storage_guild_storage_quit(struct map_session_data* sd, int flag)
  679. {
  680. struct guild_storage *stor;
  681. nullpo_ret(sd);
  682. nullpo_ret(stor=guild2storage2(sd->status.guild_id));
  683. if(flag)
  684. { //Only during a guild break flag is 1 (don't save storage)
  685. sd->state.storage_flag = 0;
  686. stor->storage_status = 0;
  687. clif_storageclose(sd);
  688. if (save_settings&4)
  689. chrif_save(sd,0);
  690. return 0;
  691. }
  692. if(stor->storage_status) {
  693. if (save_settings&4)
  694. chrif_save(sd,0);
  695. else
  696. storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
  697. }
  698. sd->state.storage_flag = 0;
  699. stor->storage_status = 0;
  700. return 0;
  701. }