storage.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  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 <stdlib.h>
  16. #include <string.h>
  17. static DBMap* guild_storage_db; ///Databases of guild_storage : int guild_id -> struct guild_storage*
  18. struct s_storage_table *storage_db;
  19. int storage_count;
  20. /**
  21. * Get storage name
  22. * @param id Storage ID
  23. * @return Storage name or "Storage" if not found
  24. * @author [Cydh]
  25. **/
  26. const char *storage_getName(uint8 id) {
  27. if (storage_db && storage_count) {
  28. int i;
  29. for (i = 0; i < storage_count; i++) {
  30. if (&storage_db[i] && storage_db[i].id == id && storage_db[i].name && storage_db[i].name[0] != '\0')
  31. return storage_db[i].name;
  32. }
  33. }
  34. return "Storage";
  35. }
  36. /**
  37. * Check if sotrage ID is valid
  38. * @param id Storage ID
  39. * @return True:Valid, False:Invalid
  40. **/
  41. bool storage_exists(uint8 id) {
  42. if (storage_db && storage_count) {
  43. int i;
  44. for (i = 0; i < storage_count; i++) {
  45. if (storage_db[i].id == id)
  46. return true;
  47. }
  48. }
  49. return false;
  50. }
  51. /**
  52. * Storage item comparator (for qsort)
  53. * sort by itemid and amount
  54. * @param _i1 : item a
  55. * @param _i2 : item b
  56. * @return i1<=>i2
  57. */
  58. static int storage_comp_item(const void *_i1, const void *_i2)
  59. {
  60. struct item *i1 = (struct item *)_i1;
  61. struct item *i2 = (struct item *)_i2;
  62. if (i1->nameid == i2->nameid)
  63. return 0;
  64. else if (!(i1->nameid) || !(i1->amount))
  65. return 1;
  66. else if (!(i2->nameid) || !(i2->amount))
  67. return -1;
  68. return i1->nameid - i2->nameid;
  69. }
  70. /**
  71. * Sort item by storage_comp_item (nameid)
  72. * used when we open up our storage or guild_storage
  73. * @param items : list of items to sort
  74. * @param size : number of item in list
  75. */
  76. void storage_sortitem(struct item* items, unsigned int size)
  77. {
  78. nullpo_retv(items);
  79. if( battle_config.client_sort_storage )
  80. qsort(items, size, sizeof(struct item), storage_comp_item);
  81. }
  82. /**
  83. * Initiate storage module
  84. * Called from map.c::do_init()
  85. */
  86. void do_init_storage(void)
  87. {
  88. guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA);
  89. storage_db = NULL;
  90. storage_count = 0;
  91. }
  92. /**
  93. * Destroy storage module
  94. * @author : [MC Cameri]
  95. * Called from map.c::do_final()
  96. */
  97. void do_final_storage(void)
  98. {
  99. guild_storage_db->destroy(guild_storage_db,NULL);
  100. if (storage_db)
  101. aFree(storage_db);
  102. storage_db = NULL;
  103. storage_count = 0;
  104. }
  105. /**
  106. * Parses storage and saves 'dirty' ones upon reconnect.
  107. * @author [Skotlex]
  108. * @see DBApply
  109. * @return 0
  110. */
  111. static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
  112. {
  113. struct s_storage *stor = db_data2ptr(data);
  114. if (stor->dirty && stor->status == 0) //Save closed storages.
  115. storage_guild_storagesave(0, stor->id, 0);
  116. return 0;
  117. }
  118. /**
  119. * Function to be invoked upon server reconnection to char. To save all 'dirty' storages
  120. * @author [Skotlex]
  121. */
  122. void do_reconnect_storage(void)
  123. {
  124. guild_storage_db->foreach(guild_storage_db, storage_reconnect_sub);
  125. }
  126. /**
  127. * Player attempt tp open his storage.
  128. * @param sd : player
  129. * @return 0:success, 1:fail
  130. */
  131. int storage_storageopen(struct map_session_data *sd)
  132. {
  133. nullpo_ret(sd);
  134. if(sd->state.storage_flag)
  135. return 1; //Already open?
  136. if( !pc_can_give_items(sd) ) { // check is this GM level is allowed to put items to storage
  137. clif_displaymessage(sd->fd, msg_txt(sd,246));
  138. return 1;
  139. }
  140. sd->state.storage_flag = 1;
  141. storage_sortitem(sd->storage.u.items_storage, sd->storage.max_amount);
  142. clif_storagelist(sd, sd->storage.u.items_storage, sd->storage.max_amount, storage_getName(0));
  143. clif_updatestorageamount(sd, sd->storage.amount, sd->storage.max_amount);
  144. return 0;
  145. }
  146. /**
  147. * Check if 2 item a and b have same values
  148. * @param a : item 1
  149. * @param b : item 2
  150. * @return 1:same, 0:are different
  151. */
  152. int compare_item(struct item *a, struct item *b)
  153. {
  154. if( a->nameid == b->nameid &&
  155. a->identify == b->identify &&
  156. a->refine == b->refine &&
  157. a->attribute == b->attribute &&
  158. a->expire_time == b->expire_time &&
  159. a->bound == b->bound &&
  160. a->unique_id == b->unique_id
  161. )
  162. {
  163. int i;
  164. for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
  165. return (i == MAX_SLOTS);
  166. }
  167. return 0;
  168. }
  169. /**
  170. * Check if item can be added to storage
  171. * @param stor Storage data
  172. * @param idx Index item from inventory/cart
  173. * @param items List of items from inventory/cart
  174. * @param amount Amount of item will be added
  175. * @param max_num Max inventory/cart
  176. * @return @see enum e_storage_add
  177. **/
  178. static enum e_storage_add storage_canAddItem(struct s_storage *stor, int idx, struct item items[], int amount, int max_num) {
  179. if (stor->amount >= stor->max_amount)
  180. return STORAGE_ADD_NOROOM; // storage full
  181. if (idx < 0 || idx >= max_num)
  182. return STORAGE_ADD_INVALID;
  183. if (items[idx].nameid <= 0)
  184. return STORAGE_ADD_INVALID; // No item on that spot
  185. if (amount < 1 || amount > items[idx].amount)
  186. return STORAGE_ADD_INVALID;
  187. if (!stor->state.put)
  188. return STORAGE_ADD_NOACCESS;
  189. return STORAGE_ADD_OK;
  190. }
  191. /**
  192. * Check if item can be moved from storage
  193. * @param stor Storage data
  194. * @param idx Index from storage
  195. * @param amount Number of item
  196. * @return @see enum e_storage_add
  197. **/
  198. static enum e_storage_add storage_canGetItem(struct s_storage *stor, int idx, int amount) {
  199. // If last index check is sd->storage_size, if player isn't VIP anymore but there's item, player can't take it
  200. // Example the storage size when not VIP anymore is 350/300, player still can take the 301st~349th item.
  201. if( idx < 0 || idx >= ARRAYLENGTH(stor->u.items_storage) )
  202. return STORAGE_ADD_INVALID;
  203. if( stor->u.items_storage[idx].nameid <= 0 )
  204. return STORAGE_ADD_INVALID; //Nothing there
  205. if( amount < 1 || amount > stor->u.items_storage[idx].amount )
  206. return STORAGE_ADD_INVALID;
  207. if (!stor->state.get)
  208. return STORAGE_ADD_NOACCESS;
  209. return STORAGE_ADD_OK;
  210. }
  211. /**
  212. * Make a player add an item to his storage
  213. * @param sd : player
  214. * @param stor : Storage data
  215. * @param item_data : item to add
  216. * @param amount : quantity of items
  217. * @return 0:success, 1:failed
  218. */
  219. static int storage_additem(struct map_session_data* sd, struct s_storage *stor, struct item *it, int amount)
  220. {
  221. struct item_data *data;
  222. int i;
  223. if( it->nameid == 0 || amount <= 0 )
  224. return 1;
  225. data = itemdb_search(it->nameid);
  226. if( data->stack.storage && amount > data->stack.amount ) // item stack limitation
  227. return 1;
  228. if( !itemdb_canstore(it, pc_get_group_level(sd)) ) { // Check if item is storable. [Skotlex]
  229. clif_displaymessage (sd->fd, msg_txt(sd,264));
  230. return 1;
  231. }
  232. if( (it->bound > BOUND_ACCOUNT) && !pc_can_give_bounded_items(sd) ) {
  233. clif_displaymessage(sd->fd, msg_txt(sd,294));
  234. return 1;
  235. }
  236. if( itemdb_isstackable2(data) ) { // Stackable
  237. for( i = 0; i < stor->max_amount; i++ ) {
  238. if( compare_item(&stor->u.items_storage[i], it) ) { // existing items found, stack them
  239. if( amount > MAX_AMOUNT - stor->u.items_storage[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->u.items_storage[i].amount ) )
  240. return 1;
  241. stor->u.items_storage[i].amount += amount;
  242. stor->dirty = true;
  243. clif_storageitemadded(sd,&stor->u.items_storage[i],i,amount);
  244. return 0;
  245. }
  246. }
  247. }
  248. // find free slot
  249. ARR_FIND( 0, stor->max_amount, i, stor->u.items_storage[i].nameid == 0 );
  250. if( i >= stor->max_amount )
  251. return 1;
  252. // add item to slot
  253. memcpy(&stor->u.items_storage[i],it,sizeof(stor->u.items_storage[0]));
  254. stor->amount++;
  255. stor->u.items_storage[i].amount = amount;
  256. stor->dirty = true;
  257. clif_storageitemadded(sd,&stor->u.items_storage[i],i,amount);
  258. clif_updatestorageamount(sd, stor->amount, stor->max_amount);
  259. return 0;
  260. }
  261. /**
  262. * Make a player delete an item from his storage
  263. * @param sd : player
  264. * @param n : idx on storage to remove the item from
  265. * @param amount :number of item to remove
  266. * @return 0:sucess, 1:fail
  267. */
  268. int storage_delitem(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
  269. {
  270. if( stor->u.items_storage[index].nameid == 0 || stor->u.items_storage[index].amount < amount )
  271. return 1;
  272. stor->u.items_storage[index].amount -= amount;
  273. stor->dirty = true;
  274. if( stor->u.items_storage[index].amount == 0 ) {
  275. memset(&stor->u.items_storage[index],0,sizeof(stor->u.items_storage[0]));
  276. stor->amount--;
  277. if( sd->state.storage_flag == 1 || sd->state.storage_flag == 3 )
  278. clif_updatestorageamount(sd, stor->amount, sd->storage.max_amount);
  279. }
  280. if( sd->state.storage_flag == 1 || sd->state.storage_flag == 3 )
  281. clif_storageitemremoved(sd,index,amount);
  282. return 0;
  283. }
  284. /**
  285. * Add an item to the storage from the inventory.
  286. * @param sd : player
  287. * @param stor : Storage data
  288. * @param index : inventory index to take the item from
  289. * @param amount : number of item to take
  290. * @return 0:fail, 1:success
  291. */
  292. void storage_storageadd(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
  293. {
  294. enum e_storage_add result;
  295. nullpo_retv(sd);
  296. result = storage_canAddItem(stor, index, sd->inventory.u.items_inventory, amount, MAX_INVENTORY);
  297. if (result == STORAGE_ADD_INVALID)
  298. return;
  299. else if (result == STORAGE_ADD_OK && storage_additem(sd,stor,&sd->inventory.u.items_inventory[index],amount) == 0) {
  300. pc_delitem(sd,index,amount,0,4,LOG_TYPE_STORAGE);
  301. return;
  302. }
  303. clif_storageitemremoved(sd,index,0);
  304. clif_dropitem(sd,index,0);
  305. }
  306. /**
  307. * Retrieve an item from the storage into inventory
  308. * @param sd : player
  309. * @param index : storage index to take the item from
  310. * @param amount : number of item to take
  311. * @return 0:fail, 1:success
  312. */
  313. void storage_storageget(struct map_session_data *sd, struct s_storage *stor, int index, int amount)
  314. {
  315. unsigned char flag = 0;
  316. enum e_storage_add result;
  317. nullpo_retv(sd);
  318. result = storage_canGetItem(stor, index, amount);
  319. if (result != STORAGE_ADD_OK)
  320. return;
  321. if ((flag = pc_additem(sd,&stor->u.items_storage[index],amount,LOG_TYPE_STORAGE)) == ADDITEM_SUCCESS)
  322. storage_delitem(sd,stor,index,amount);
  323. else {
  324. clif_storageitemremoved(sd,index,0);
  325. clif_additem(sd,0,0,flag);
  326. }
  327. }
  328. /**
  329. * Move an item from cart to storage.
  330. * @param sd : player
  331. * @param stor : Storage data
  332. * @param index : cart index to take the item from
  333. * @param amount : number of item to take
  334. * @return 0:fail, 1:success
  335. */
  336. void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *stor, int index, int amount)
  337. {
  338. enum e_storage_add result;
  339. nullpo_retv(sd);
  340. result = storage_canAddItem(stor, index, sd->cart.u.items_inventory, amount, MAX_INVENTORY);
  341. if (result == STORAGE_ADD_INVALID)
  342. return;
  343. else if (result == STORAGE_ADD_OK && storage_additem(sd,stor,&sd->cart.u.items_cart[index],amount) == 0) {
  344. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
  345. return;
  346. }
  347. clif_storageitemremoved(sd,index,0);
  348. clif_dropitem(sd,index,0);
  349. }
  350. /**
  351. * Get from Storage to the Cart inventory
  352. * @param sd : player
  353. * @param stor : Storage data
  354. * @param index : storage index to take the item from
  355. * @param amount : number of item to take
  356. * @return 0:fail, 1:success
  357. */
  358. void storage_storagegettocart(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
  359. {
  360. unsigned char flag = 0;
  361. enum e_storage_add result;
  362. nullpo_retv(sd);
  363. result = storage_canGetItem(stor, index, amount);
  364. if (result != STORAGE_ADD_OK)
  365. return;
  366. if ((flag = pc_cart_additem(sd,&stor->u.items_storage[index],amount,LOG_TYPE_STORAGE)) == 0)
  367. storage_delitem(sd,stor,index,amount);
  368. else {
  369. clif_storageitemremoved(sd,index,0);
  370. clif_cart_additem_ack(sd,(flag==1)?ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
  371. }
  372. }
  373. /**
  374. * Make player close his storage
  375. * @author : [massdriller] / modified by [Valaris]
  376. * @param sd : player
  377. */
  378. void storage_storageclose(struct map_session_data* sd)
  379. {
  380. nullpo_retv(sd);
  381. clif_storageclose(sd);
  382. if (save_settings&CHARSAVE_STORAGE)
  383. chrif_save(sd,0);
  384. sd->state.storage_flag = 0;
  385. }
  386. /**
  387. * Force closing the storage for player without displaying result
  388. * (example when quitting the game)
  389. * @param sd : player to close storage
  390. * @param flag :
  391. * 1: Character is quitting
  392. * 2(x): Character is changing map-servers
  393. */
  394. void storage_storage_quit(struct map_session_data* sd, int flag)
  395. {
  396. nullpo_retv(sd);
  397. if (save_settings&CHARSAVE_STORAGE)
  398. chrif_save(sd,0);
  399. sd->state.storage_flag = 0;
  400. }
  401. /**
  402. * Create a guild_storage stucture and add it into the db
  403. * @see DBCreateData
  404. * @param key
  405. * @param args
  406. * @return
  407. */
  408. static DBData create_guildstorage(DBKey key, va_list args)
  409. {
  410. struct s_storage *gs = NULL;
  411. gs = (struct s_storage *) aCalloc(sizeof(struct s_storage), 1);
  412. gs->type = TABLE_GUILD_STORAGE;
  413. gs->id = key.i;
  414. return db_ptr2data(gs);
  415. }
  416. /**
  417. * Retrieve the guild_storage of a guild
  418. * will create a new storage if none found for the guild
  419. * @param guild_id : id of the guild
  420. * @return s_storage
  421. */
  422. struct s_storage *guild2storage(int guild_id)
  423. {
  424. struct s_storage *gs = NULL;
  425. if (guild_search(guild_id) != NULL)
  426. gs = (struct s_storage *)idb_ensure(guild_storage_db,guild_id,create_guildstorage);
  427. return gs;
  428. }
  429. /**
  430. * See if the guild_storage exist in db and fetch it if it's the case
  431. * @author : [Skotlex]
  432. * @param guild_id : guild_id to search the storage
  433. * @return s_storage or NULL
  434. */
  435. struct s_storage *guild2storage2(int guild_id)
  436. {
  437. return (struct s_storage*)idb_get(guild_storage_db,guild_id);
  438. }
  439. /**
  440. * Delete a guild_storage and remove it from db
  441. * @param guild_id : guild to remove the storage from
  442. * @return 0
  443. */
  444. void storage_guild_delete(int guild_id)
  445. {
  446. idb_remove(guild_storage_db,guild_id);
  447. }
  448. /**
  449. * Attempt to open guild storage for player
  450. * @param sd : player
  451. * @return 0 : success, 1 : fail, 2 : no guild found
  452. */
  453. char storage_guild_storageopen(struct map_session_data* sd)
  454. {
  455. struct s_storage *gstor;
  456. nullpo_ret(sd);
  457. if(sd->status.guild_id <= 0)
  458. return 2;
  459. if(sd->state.storage_flag)
  460. return 1; //Can't open both storages at a time.
  461. if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
  462. clif_displaymessage(sd->fd, msg_txt(sd,246));
  463. return 1;
  464. }
  465. if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
  466. intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
  467. return 0;
  468. }
  469. if(gstor->status)
  470. return 1;
  471. if( gstor->lock )
  472. return 1;
  473. gstor->status = true;
  474. sd->state.storage_flag = 2;
  475. storage_sortitem(gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild));
  476. clif_storagelist(sd, gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild), "Guild Storage");
  477. clif_updatestorageamount(sd, gstor->amount, MAX_GUILD_STORAGE);
  478. return 0;
  479. }
  480. /**
  481. * Attempt to add an item in guild storage, then refresh it
  482. * @param sd : player attempting to open the guild_storage
  483. * @param stor : guild_storage
  484. * @param item : item to add
  485. * @param amount : number of item to add
  486. * @return True : success, False : fail
  487. */
  488. bool storage_guild_additem(struct map_session_data* sd, struct s_storage* stor, struct item* item_data, int amount)
  489. {
  490. struct item_data *id;
  491. int i;
  492. nullpo_ret(sd);
  493. nullpo_ret(stor);
  494. nullpo_ret(item_data);
  495. if(item_data->nameid == 0 || amount <= 0)
  496. return false;
  497. id = itemdb_search(item_data->nameid);
  498. if( id->stack.guildstorage && amount > id->stack.amount ) // item stack limitation
  499. return false;
  500. if (!itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time) { // Check if item is storable. [Skotlex]
  501. clif_displaymessage (sd->fd, msg_txt(sd,264));
  502. return false;
  503. }
  504. if ((item_data->bound == BOUND_ACCOUNT || item_data->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd)) {
  505. clif_displaymessage(sd->fd, msg_txt(sd,294));
  506. return false;
  507. }
  508. if(itemdb_isstackable2(id)) { //Stackable
  509. for(i = 0; i < MAX_GUILD_STORAGE; i++) {
  510. if(compare_item(&stor->u.items_guild[i], item_data)) {
  511. if( amount > MAX_AMOUNT - stor->u.items_guild[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->u.items_guild[i].amount ) )
  512. return false;
  513. stor->u.items_guild[i].amount += amount;
  514. clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount);
  515. stor->dirty = true;
  516. return true;
  517. }
  518. }
  519. }
  520. //Add item
  521. for(i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++);
  522. if(i >= MAX_GUILD_STORAGE)
  523. return false;
  524. memcpy(&stor->u.items_guild[i],item_data,sizeof(stor->u.items_guild[0]));
  525. stor->u.items_guild[i].amount = amount;
  526. stor->amount++;
  527. clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount);
  528. clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE);
  529. stor->dirty = true;
  530. return true;
  531. }
  532. /**
  533. * Attempt to add an item in guild storage, then refresh i
  534. * @param stor : guild_storage
  535. * @param item : item to add
  536. * @param amount : number of item to add
  537. * @return True : success, False : fail
  538. */
  539. bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amount) {
  540. struct item_data *id;
  541. int i;
  542. nullpo_ret(stor);
  543. nullpo_ret(item);
  544. if (item->nameid == 0 || amount <= 0 || !(id = itemdb_exists(item->nameid)))
  545. return false;
  546. if (item->expire_time)
  547. return false;
  548. if (itemdb_isstackable2(id)) { // Stackable
  549. for (i = 0; i < MAX_GUILD_STORAGE; i++) {
  550. if (compare_item(&stor->u.items_guild[i], item)) {
  551. // Set the amount, make it fit with max amount
  552. amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->u.items_guild[i].amount);
  553. if (amount != item->amount)
  554. ShowWarning("storage_guild_additem2: Stack limit reached! Altered amount of item \""CL_WHITE"%s"CL_RESET"\" (%d). '"CL_WHITE"%d"CL_RESET"' -> '"CL_WHITE"%d"CL_RESET"'.\n", id->name, id->nameid, item->amount, amount);
  555. stor->u.items_guild[i].amount += amount;
  556. stor->dirty = true;
  557. return true;
  558. }
  559. }
  560. }
  561. // Add the item
  562. for (i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++);
  563. if (i >= MAX_GUILD_STORAGE)
  564. return false;
  565. memcpy(&stor->u.items_guild[i], item, sizeof(stor->u.items_guild[0]));
  566. stor->u.items_guild[i].amount = amount;
  567. stor->amount++;
  568. stor->dirty = true;
  569. return true;
  570. }
  571. /**
  572. * Attempt to delete an item in guild storage, then refresh it
  573. * @param sd : player
  574. * @param stor : guild_storage
  575. * @param n : index of item in guild storage
  576. * @param amount : number of item to delete
  577. * @return True : success, False : fail
  578. */
  579. bool storage_guild_delitem(struct map_session_data* sd, struct s_storage* stor, int n, int amount)
  580. {
  581. nullpo_retr(1, sd);
  582. nullpo_retr(1, stor);
  583. if(!stor->u.items_guild[n].nameid || stor->u.items_guild[n].amount < amount)
  584. return false;
  585. stor->u.items_guild[n].amount -= amount;
  586. if(!stor->u.items_guild[n].amount) {
  587. memset(&stor->u.items_guild[n],0,sizeof(stor->u.items_guild[0]));
  588. stor->amount--;
  589. clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE);
  590. }
  591. clif_storageitemremoved(sd,n,amount);
  592. stor->dirty = true;
  593. return true;
  594. }
  595. /**
  596. * Attempt to add an item in guild storage from inventory, then refresh it
  597. * @param sd : player
  598. * @param amount : number of item to delete
  599. */
  600. void storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
  601. {
  602. struct s_storage *stor;
  603. nullpo_retv(sd);
  604. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  605. if( !stor->status || stor->amount > MAX_GUILD_STORAGE )
  606. return;
  607. if( index < 0 || index >= MAX_INVENTORY )
  608. return;
  609. if( sd->inventory.u.items_inventory[index].nameid == 0 )
  610. return;
  611. if( amount < 1 || amount > sd->inventory.u.items_inventory[index].amount )
  612. return;
  613. if( stor->lock ) {
  614. storage_guild_storageclose(sd);
  615. return;
  616. }
  617. if(storage_guild_additem(sd,stor,&sd->inventory.u.items_inventory[index],amount))
  618. pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
  619. else {
  620. clif_storageitemremoved(sd,index,0);
  621. clif_dropitem(sd,index,0);
  622. }
  623. }
  624. /**
  625. * Attempt to retrieve an item from guild storage to inventory, then refresh it
  626. * @param sd : player
  627. * @param index : index of item in storage
  628. * @param amount : number of item to get
  629. * @return 1:success, 0:fail
  630. */
  631. void storage_guild_storageget(struct map_session_data* sd, int index, int amount)
  632. {
  633. struct s_storage *stor;
  634. unsigned char flag = 0;
  635. nullpo_retv(sd);
  636. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  637. if(!stor->status)
  638. return;
  639. if(index < 0 || index >= MAX_GUILD_STORAGE)
  640. return;
  641. if(stor->u.items_guild[index].nameid == 0)
  642. return;
  643. if(amount < 1 || amount > stor->u.items_guild[index].amount)
  644. return;
  645. if( stor->lock ) {
  646. storage_guild_storageclose(sd);
  647. return;
  648. }
  649. if((flag = pc_additem(sd,&stor->u.items_guild[index],amount,LOG_TYPE_GSTORAGE)) == 0)
  650. storage_guild_delitem(sd,stor,index,amount);
  651. else { // inform fail
  652. clif_storageitemremoved(sd,index,0);
  653. clif_additem(sd,0,0,flag);
  654. }
  655. }
  656. /**
  657. * Attempt to add an item in guild storage from cart, then refresh it
  658. * @param sd : player
  659. * @param index : index of item in cart
  660. * @param amount : number of item to transfer
  661. */
  662. void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
  663. {
  664. struct s_storage *stor;
  665. nullpo_retv(sd);
  666. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  667. if( !stor->status || stor->amount > MAX_GUILD_STORAGE )
  668. return;
  669. if( index < 0 || index >= MAX_CART )
  670. return;
  671. if( sd->cart.u.items_cart[index].nameid == 0 )
  672. return;
  673. if( amount < 1 || amount > sd->cart.u.items_cart[index].amount )
  674. return;
  675. if(storage_guild_additem(sd,stor,&sd->cart.u.items_cart[index],amount))
  676. pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
  677. else {
  678. clif_storageitemremoved(sd,index,0);
  679. clif_dropitem(sd,index,0);
  680. }
  681. }
  682. /**
  683. * Attempt to retrieve an item from guild storage to cart, then refresh it
  684. * @param sd : player
  685. * @param index : index of item in storage
  686. * @param amount : number of item to transfer
  687. * @return 1:fail, 0:success
  688. */
  689. void storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
  690. {
  691. short flag;
  692. struct s_storage *stor;
  693. nullpo_retv(sd);
  694. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  695. if(!stor->status)
  696. return;
  697. if(index < 0 || index >= MAX_GUILD_STORAGE)
  698. return;
  699. if(stor->u.items_guild[index].nameid == 0)
  700. return;
  701. if(amount < 1 || amount > stor->u.items_guild[index].amount)
  702. return;
  703. if((flag = pc_cart_additem(sd,&stor->u.items_guild[index],amount,LOG_TYPE_GSTORAGE)) == 0)
  704. storage_guild_delitem(sd,stor,index,amount);
  705. else {
  706. clif_storageitemremoved(sd,index,0);
  707. clif_cart_additem_ack(sd,(flag == 1) ? ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
  708. }
  709. }
  710. /**
  711. * Request to save guild storage
  712. * @param account_id : account requesting the save
  713. * @param guild_id : guild to take the guild_storage
  714. * @param flag : 1=char quitting, close the storage
  715. * @return False : fail (no storage), True : success (requested)
  716. */
  717. bool storage_guild_storagesave(uint32 account_id, int guild_id, int flag)
  718. {
  719. struct s_storage *stor = guild2storage2(guild_id);
  720. if (stor) {
  721. if (flag) //Char quitting, close it.
  722. stor->status = false;
  723. if (stor->dirty)
  724. intif_send_guild_storage(account_id,stor);
  725. return true;
  726. }
  727. return false;
  728. }
  729. /**
  730. * ACK save of guild storage
  731. * @param guild_id : guild to use the storage
  732. */
  733. void storage_guild_storagesaved(int guild_id)
  734. {
  735. struct s_storage *stor;
  736. if ((stor = guild2storage2(guild_id)) != NULL) {
  737. if (stor->dirty && !stor->status) // Storage has been correctly saved.
  738. stor->dirty = false;
  739. }
  740. }
  741. /**
  742. * Close storage for player then save it
  743. * @param sd : player
  744. */
  745. void storage_guild_storageclose(struct map_session_data* sd)
  746. {
  747. struct s_storage *stor;
  748. nullpo_retv(sd);
  749. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  750. clif_storageclose(sd);
  751. if (stor->status) {
  752. if (save_settings&CHARSAVE_STORAGE)
  753. chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
  754. else
  755. storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
  756. stor->status = false;
  757. }
  758. sd->state.storage_flag = 0;
  759. }
  760. /**
  761. * Close storage for player then save it
  762. * @param sd
  763. * @param flag
  764. */
  765. void storage_guild_storage_quit(struct map_session_data* sd, int flag)
  766. {
  767. struct s_storage *stor;
  768. nullpo_retv(sd);
  769. nullpo_retv(stor = guild2storage2(sd->status.guild_id));
  770. if (flag) { //Only during a guild break flag is 1 (don't save storage)
  771. clif_storageclose(sd);
  772. if (save_settings&CHARSAVE_STORAGE)
  773. chrif_save(sd,0);
  774. sd->state.storage_flag = 0;
  775. stor->status = false;
  776. return;
  777. }
  778. if (stor->status) {
  779. if (save_settings&CHARSAVE_STORAGE)
  780. chrif_save(sd,0);
  781. else
  782. storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
  783. }
  784. sd->state.storage_flag = 0;
  785. stor->status = false;
  786. }
  787. /**
  788. * Open premium storage
  789. * @param sd Player
  790. **/
  791. void storage_premiumStorage_open(struct map_session_data *sd) {
  792. nullpo_retv(sd);
  793. if (!&sd->premiumStorage)
  794. return;
  795. sd->state.storage_flag = 3;
  796. storage_sortitem(sd->premiumStorage.u.items_storage, sd->premiumStorage.max_amount);
  797. clif_storagelist(sd, sd->premiumStorage.u.items_storage, sd->premiumStorage.max_amount, storage_getName(sd->premiumStorage.stor_id));
  798. clif_updatestorageamount(sd, sd->premiumStorage.amount, sd->premiumStorage.max_amount);
  799. }
  800. /**
  801. * Request to open premium storage
  802. * @param sd Player who request
  803. * @param num Storage number
  804. * @param mode Storage mode @see enum e_storage_mode
  805. * @return 1:Success to request, 0:Failed
  806. * @author [Cydh]
  807. **/
  808. bool storage_premiumStorage_load(struct map_session_data *sd, uint8 num, uint8 mode) {
  809. nullpo_ret(sd);
  810. if (sd->state.storage_flag)
  811. return 0;
  812. if (sd->state.vending || sd->state.buyingstore || sd->state.prevend || sd->state.autotrade)
  813. return 0;
  814. if (sd->state.banking || sd->state.callshop)
  815. return 0;
  816. if (!pc_can_give_items(sd)) { // check is this GM level is allowed to put items to storage
  817. clif_displaymessage(sd->fd, msg_txt(sd,246));
  818. return 0;
  819. }
  820. if (!&sd->premiumStorage || sd->premiumStorage.stor_id != num)
  821. return intif_storage_request(sd, TABLE_STORAGE, num, mode);
  822. else {
  823. sd->premiumStorage.state.put = (mode&STOR_MODE_PUT) ? 1 : 0;
  824. sd->premiumStorage.state.get = (mode&STOR_MODE_GET) ? 1 : 0;
  825. storage_premiumStorage_open(sd);
  826. }
  827. return 1;
  828. }
  829. /**
  830. * Request to save premium storage
  831. * @param sd Player who has the storage
  832. * @author [Cydh]
  833. **/
  834. void storage_premiumStorage_save(struct map_session_data *sd) {
  835. nullpo_retv(sd);
  836. if (!&sd->premiumStorage)
  837. return;
  838. intif_storage_save(sd, &sd->premiumStorage);
  839. }
  840. /**
  841. * Ack of secondary premium has been saved
  842. * @param sd Player who has the storage
  843. **/
  844. void storage_premiumStorage_saved(struct map_session_data *sd) {
  845. if (!sd)
  846. return;
  847. if (&sd->premiumStorage) {
  848. sd->premiumStorage.dirty = 0;
  849. }
  850. if (sd->state.storage_flag == 3) {
  851. sd->state.storage_flag = 0;
  852. clif_storageclose(sd);
  853. }
  854. }
  855. /**
  856. * Request to close premium storage
  857. * @param sd Player who has the storage
  858. * @author [Cydh]
  859. **/
  860. void storage_premiumStorage_close(struct map_session_data *sd) {
  861. nullpo_retv(sd);
  862. if (!&sd->premiumStorage)
  863. return;
  864. if (sd->premiumStorage.dirty) {
  865. intif_storage_save(sd, &sd->premiumStorage);
  866. if (sd->state.storage_flag == 3) {
  867. sd->state.storage_flag = 0;
  868. clif_storageclose(sd);
  869. }
  870. }
  871. else
  872. storage_premiumStorage_saved(sd);
  873. }
  874. /**
  875. * Force save then close the premium storage
  876. * @param sd Player who has the storage
  877. * @author [Cydh]
  878. **/
  879. void storage_premiumStorage_quit(struct map_session_data *sd) {
  880. nullpo_retv(sd);
  881. if (!&sd->premiumStorage)
  882. return;
  883. intif_storage_save(sd, &sd->premiumStorage);
  884. }