buyingstore.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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" // ARR_FIND
  5. #include "../common/showmsg.h" // ShowWarning
  6. #include "../common/socket.h" // RBUF*
  7. #include "../common/strlib.h" // safestrncpy
  8. #include "atcommand.h" // msg_txt
  9. #include "battle.h" // battle_config.*
  10. #include "buyingstore.h" // struct s_buyingstore
  11. #include "clif.h" // clif_buyingstore_*
  12. #include "log.h" // log_pick_pc, log_zeny
  13. #include "pc.h" // struct map_session_data
  14. #include "chrif.h"
  15. /// constants (client-side restrictions)
  16. #define BUYINGSTORE_MAX_PRICE 99990000
  17. #define BUYINGSTORE_MAX_AMOUNT 9999
  18. /// failure constants for clif functions
  19. enum e_buyingstore_failure
  20. {
  21. BUYINGSTORE_CREATE = 1, // "Failed to open buying store."
  22. BUYINGSTORE_CREATE_OVERWEIGHT = 2, // "Total amount of then possessed items exceeds the weight limit by %d. Please re-enter."
  23. BUYINGSTORE_TRADE_BUYER_ZENY = 3, // "All items within the buy limit were purchased."
  24. BUYINGSTORE_TRADE_BUYER_NO_ITEMS = 4, // "All items were purchased."
  25. BUYINGSTORE_TRADE_SELLER_FAILED = 5, // "The deal has failed."
  26. BUYINGSTORE_TRADE_SELLER_COUNT = 6, // "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy."
  27. BUYINGSTORE_TRADE_SELLER_ZENY = 7, // "The trade failed, because the buyer is lacking required balance."
  28. BUYINGSTORE_CREATE_NO_INFO = 8, // "No sale (purchase) information available."
  29. };
  30. static unsigned int buyingstore_nextid = 0;
  31. static const short buyingstore_blankslots[MAX_SLOTS] = { 0 }; // used when checking whether or not an item's card slots are blank
  32. /// Returns unique buying store id
  33. static unsigned int buyingstore_getuid(void)
  34. {
  35. return ++buyingstore_nextid;
  36. }
  37. bool buyingstore_setup(struct map_session_data* sd, unsigned char slots){
  38. if (!battle_config.feature_buying_store || sd->state.vending || sd->state.buyingstore || sd->state.trading || slots == 0) {
  39. return false;
  40. }
  41. if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) )
  42. {// custom: mute limitation
  43. return false;
  44. }
  45. if( map[sd->bl.m].flag.novending )
  46. {// custom: no vending maps
  47. clif_displaymessage(sd->fd, msg_txt(sd,276)); // "You can't open a shop on this map"
  48. return false;
  49. }
  50. if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
  51. {// custom: no vending cells
  52. clif_displaymessage(sd->fd, msg_txt(sd,204)); // "You can't open a shop on this cell."
  53. return false;
  54. }
  55. if( slots > MAX_BUYINGSTORE_SLOTS )
  56. {
  57. ShowWarning("buyingstore_setup: Requested %d slots, but server supports only %d slots.\n", (int)slots, MAX_BUYINGSTORE_SLOTS);
  58. slots = MAX_BUYINGSTORE_SLOTS;
  59. }
  60. sd->buyingstore.slots = slots;
  61. clif_buyingstore_open(sd);
  62. return true;
  63. }
  64. void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count)
  65. {
  66. unsigned int i, weight, listidx;
  67. struct item_data* id;
  68. if( !result || count == 0 )
  69. {// canceled, or no items
  70. return;
  71. }
  72. if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
  73. {// disabled or invalid input
  74. sd->buyingstore.slots = 0;
  75. clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
  76. return;
  77. }
  78. if( !pc_can_give_items(sd) )
  79. {// custom: GM is not allowed to buy (give zeny)
  80. sd->buyingstore.slots = 0;
  81. clif_displaymessage(sd->fd, msg_txt(sd,246));
  82. clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
  83. return;
  84. }
  85. if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) )
  86. {// custom: mute limitation
  87. return;
  88. }
  89. if( map[sd->bl.m].flag.novending )
  90. {// custom: no vending maps
  91. clif_displaymessage(sd->fd, msg_txt(sd,276)); // "You can't open a shop on this map"
  92. return;
  93. }
  94. if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
  95. {// custom: no vending cells
  96. clif_displaymessage(sd->fd, msg_txt(sd,204)); // "You can't open a shop on this cell."
  97. return;
  98. }
  99. weight = sd->weight;
  100. // check item list
  101. for( i = 0; i < count; i++ )
  102. {// itemlist: <name id>.W <amount>.W <price>.L
  103. unsigned short nameid, amount;
  104. int price, idx;
  105. nameid = RBUFW(itemlist,i*8+0);
  106. amount = RBUFW(itemlist,i*8+2);
  107. price = RBUFL(itemlist,i*8+4);
  108. if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 )
  109. {// invalid input
  110. break;
  111. }
  112. if( price <= 0 || price > BUYINGSTORE_MAX_PRICE )
  113. {// invalid price: unlike vending, items cannot be bought at 0 Zeny
  114. break;
  115. }
  116. if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
  117. {// restrictions: allowed, no character-bound items and at least one must be owned
  118. break;
  119. }
  120. if( sd->status.inventory[idx].amount+amount > BUYINGSTORE_MAX_AMOUNT )
  121. {// too many items of same kind
  122. break;
  123. }
  124. if( i )
  125. {// duplicate check. as the client does this too, only malicious intent should be caught here
  126. ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid );
  127. if( listidx != i )
  128. {// duplicate
  129. ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);
  130. break;
  131. }
  132. }
  133. weight+= id->weight*amount;
  134. sd->buyingstore.items[i].nameid = nameid;
  135. sd->buyingstore.items[i].amount = amount;
  136. sd->buyingstore.items[i].price = price;
  137. }
  138. if( i != count )
  139. {// invalid item/amount/price
  140. sd->buyingstore.slots = 0;
  141. clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
  142. return;
  143. }
  144. if( (sd->max_weight*90)/100 < weight )
  145. {// not able to carry all wanted items without getting overweight (90%)
  146. sd->buyingstore.slots = 0;
  147. clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight);
  148. return;
  149. }
  150. // success
  151. sd->state.buyingstore = true;
  152. sd->buyer_id = buyingstore_getuid();
  153. sd->buyingstore.zenylimit = zenylimit;
  154. sd->buyingstore.slots = i; // store actual amount of items
  155. safestrncpy(sd->message, storename, sizeof(sd->message));
  156. clif_buyingstore_myitemlist(sd);
  157. clif_buyingstore_entry(sd);
  158. }
  159. void buyingstore_close(struct map_session_data* sd)
  160. {
  161. if( sd->state.buyingstore )
  162. {
  163. // invalidate data
  164. sd->state.buyingstore = false;
  165. memset(&sd->buyingstore, 0, sizeof(sd->buyingstore));
  166. // notify other players
  167. clif_buyingstore_disappear_entry(sd);
  168. }
  169. }
  170. void buyingstore_open(struct map_session_data* sd, int account_id)
  171. {
  172. struct map_session_data* pl_sd;
  173. if( !battle_config.feature_buying_store || pc_istrading(sd) )
  174. {// not allowed to sell
  175. return;
  176. }
  177. if( !pc_can_give_items(sd) )
  178. {// custom: GM is not allowed to sell
  179. clif_displaymessage(sd->fd, msg_txt(sd,246));
  180. return;
  181. }
  182. if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore )
  183. {// not online or not buying
  184. return;
  185. }
  186. if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
  187. {// out of view range
  188. return;
  189. }
  190. // success
  191. clif_buyingstore_itemlist(sd, pl_sd);
  192. }
  193. void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count)
  194. {
  195. int zeny = 0;
  196. unsigned int i, weight, listidx, k;
  197. struct map_session_data* pl_sd;
  198. if( count == 0 )
  199. {// nothing to do
  200. return;
  201. }
  202. if( !battle_config.feature_buying_store || pc_istrading(sd) )
  203. {// not allowed to sell
  204. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
  205. return;
  206. }
  207. if( !pc_can_give_items(sd) )
  208. {// custom: GM is not allowed to sell
  209. clif_displaymessage(sd->fd, msg_txt(sd,246));
  210. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
  211. return;
  212. }
  213. if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id )
  214. {// not online, not buying or not same store
  215. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
  216. return;
  217. }
  218. if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
  219. {// out of view range
  220. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
  221. return;
  222. }
  223. searchstore_clearremote(sd);
  224. if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit )
  225. {// buyer lost zeny in the mean time? fix the limit
  226. pl_sd->buyingstore.zenylimit = pl_sd->status.zeny;
  227. }
  228. weight = pl_sd->weight;
  229. // check item list
  230. for( i = 0; i < count; i++ )
  231. {// itemlist: <index>.W <name id>.W <amount>.W
  232. unsigned short nameid, amount;
  233. int index;
  234. index = RBUFW(itemlist,i*6+0)-2;
  235. nameid = RBUFW(itemlist,i*6+2);
  236. amount = RBUFW(itemlist,i*6+4);
  237. if( i )
  238. {// duplicate check. as the client does this too, only malicious intent should be caught here
  239. ARR_FIND( 0, i, k, RBUFW(itemlist,k*6+0)-2 == index );
  240. if( k != i )
  241. {// duplicate
  242. ShowWarning("buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n",
  243. RBUFW(itemlist,k*6+2), RBUFW(itemlist,k*6+4), nameid, amount, sd->status.account_id, sd->status.char_id);
  244. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  245. return;
  246. }
  247. }
  248. if( index < 0 || index >= ARRAYLENGTH(sd->status.inventory) || sd->inventory_data[index] == NULL || sd->status.inventory[index].nameid != nameid || sd->status.inventory[index].amount < amount )
  249. {// invalid input
  250. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  251. return;
  252. }
  253. if( sd->status.inventory[index].expire_time || (sd->status.inventory[index].bound && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
  254. {// non-tradable item
  255. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  256. return;
  257. }
  258. ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
  259. if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 )
  260. {// there is no such item or the buyer has already bought all of them
  261. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  262. return;
  263. }
  264. if( pl_sd->buyingstore.items[listidx].amount < amount )
  265. {// buyer does not need that much of the item
  266. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid);
  267. return;
  268. }
  269. if( pc_checkadditem(pl_sd, nameid, amount) == CHKADDITEM_OVERAMOUNT )
  270. {// buyer does not have enough space for this item
  271. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  272. return;
  273. }
  274. if( amount*(unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight-weight )
  275. {// normally this is not supposed to happen, as the total weight is
  276. // checked upon creation, but the buyer could have gained items
  277. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  278. return;
  279. }
  280. weight+= amount*sd->inventory_data[index]->weight;
  281. if( amount*pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit-zeny )
  282. {// buyer does not have enough zeny
  283. clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_ZENY, nameid);
  284. return;
  285. }
  286. zeny+= amount*pl_sd->buyingstore.items[listidx].price;
  287. }
  288. // process item list
  289. for( i = 0; i < count; i++ )
  290. {// itemlist: <index>.W <name id>.W <amount>.W
  291. unsigned short nameid, amount;
  292. int index;
  293. index = RBUFW(itemlist,i*6+0)-2;
  294. nameid = RBUFW(itemlist,i*6+2);
  295. amount = RBUFW(itemlist,i*6+4);
  296. ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
  297. zeny = amount*pl_sd->buyingstore.items[listidx].price;
  298. // move item
  299. pc_additem(pl_sd, &sd->status.inventory[index], amount, LOG_TYPE_BUYING_STORE);
  300. pc_delitem(sd, index, amount, 1, 0, LOG_TYPE_BUYING_STORE);
  301. pl_sd->buyingstore.items[listidx].amount-= amount;
  302. // pay up
  303. pc_payzeny(pl_sd, zeny, LOG_TYPE_BUYING_STORE, sd);
  304. pc_getzeny(sd, zeny, LOG_TYPE_BUYING_STORE, pl_sd);
  305. pl_sd->buyingstore.zenylimit-= zeny;
  306. // notify clients
  307. clif_buyingstore_delete_item(sd, index, amount, pl_sd->buyingstore.items[listidx].price);
  308. clif_buyingstore_update_item(pl_sd, nameid, amount);
  309. }
  310. if( save_settings&128 ) {
  311. chrif_save(sd, 0);
  312. chrif_save(pl_sd, 0);
  313. }
  314. // check whether or not there is still something to buy
  315. ARR_FIND( 0, pl_sd->buyingstore.slots, i, pl_sd->buyingstore.items[i].amount != 0 );
  316. if( i == pl_sd->buyingstore.slots )
  317. {// everything was bought
  318. clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_NO_ITEMS);
  319. }
  320. else if( pl_sd->buyingstore.zenylimit == 0 )
  321. {// zeny limit reached
  322. clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_ZENY);
  323. }
  324. else
  325. {// continue buying
  326. return;
  327. }
  328. // cannot continue buying
  329. buyingstore_close(pl_sd);
  330. // remove auto-trader
  331. if( pl_sd->state.autotrade )
  332. {
  333. map_quit(pl_sd);
  334. }
  335. }
  336. /// Checks if an item is being bought in given player's buying store.
  337. bool buyingstore_search(struct map_session_data* sd, unsigned short nameid)
  338. {
  339. unsigned int i;
  340. if( !sd->state.buyingstore )
  341. {// not buying
  342. return false;
  343. }
  344. ARR_FIND( 0, sd->buyingstore.slots, i, sd->buyingstore.items[i].nameid == nameid && sd->buyingstore.items[i].amount );
  345. if( i == sd->buyingstore.slots )
  346. {// not found
  347. return false;
  348. }
  349. return true;
  350. }
  351. /// Searches for all items in a buyingstore, that match given ids, price and possible cards.
  352. /// @return Whether or not the search should be continued.
  353. bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_store_search* s)
  354. {
  355. unsigned int i, idx;
  356. struct s_buyingstore_item* it;
  357. if( !sd->state.buyingstore )
  358. {// not buying
  359. return true;
  360. }
  361. for( idx = 0; idx < s->item_count; idx++ )
  362. {
  363. ARR_FIND( 0, sd->buyingstore.slots, i, sd->buyingstore.items[i].nameid == s->itemlist[idx] && sd->buyingstore.items[i].amount );
  364. if( i == sd->buyingstore.slots )
  365. {// not found
  366. continue;
  367. }
  368. it = &sd->buyingstore.items[i];
  369. if( s->min_price && s->min_price > (unsigned int)it->price )
  370. {// too low price
  371. continue;
  372. }
  373. if( s->max_price && s->max_price < (unsigned int)it->price )
  374. {// too high price
  375. continue;
  376. }
  377. if( s->card_count )
  378. {// ignore cards, as there cannot be any
  379. ;
  380. }
  381. if( !searchstore_result(s->search_sd, sd->buyer_id, sd->status.account_id, sd->message, it->nameid, it->amount, it->price, buyingstore_blankslots, 0) )
  382. {// result set full
  383. return false;
  384. }
  385. }
  386. return true;
  387. }