storage.cpp 27 KB

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