vending.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "../common/nullpo.h"
  6. #include "clif.h"
  7. #include "itemdb.h"
  8. #include "atcommand.h"
  9. #include "map.h"
  10. #include "chrif.h"
  11. #include "vending.h"
  12. #include "pc.h"
  13. #include "skill.h"
  14. #include "battle.h"
  15. #include "log.h"
  16. #include "irc.h"
  17. /*==========================================
  18. * 露店閉鎖
  19. *------------------------------------------
  20. */
  21. void vending_closevending(struct map_session_data *sd)
  22. {
  23. nullpo_retv(sd);
  24. sd->vender_id=0;
  25. clif_closevendingboard(&sd->bl,0);
  26. if(use_irc && irc_announce_shop_flag)
  27. irc_announce_shop(sd,0);
  28. }
  29. /*==========================================
  30. * 露店アイテムリスト要求
  31. *------------------------------------------
  32. */
  33. void vending_vendinglistreq(struct map_session_data *sd,int id)
  34. {
  35. struct map_session_data *vsd;
  36. nullpo_retv(sd);
  37. if( (vsd=map_id2sd(id)) == NULL )
  38. return;
  39. if(vsd->vender_id==0)
  40. return;
  41. clif_vendinglist(sd,id,vsd->vending);
  42. }
  43. /*==========================================
  44. * 露店アイテム購入
  45. *------------------------------------------
  46. */
  47. void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p)
  48. {
  49. int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING];
  50. double z;
  51. unsigned short amount;
  52. short idx;
  53. struct map_session_data *vsd = map_id2sd(id);
  54. struct vending vending[MAX_VENDING]; // against duplicate packets
  55. nullpo_retv(sd);
  56. if (vsd == NULL)
  57. return;
  58. if (vsd->vender_id == 0)
  59. return;
  60. if (vsd->vender_id == sd->bl.id)
  61. return;
  62. // check number of buying items
  63. if (len < 8 + 4 || len > 8 + 4 * MAX_VENDING) {
  64. clif_buyvending(sd, 0, 32767, 4); // not enough quantity (index and amount are unknown)
  65. return;
  66. }
  67. blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory
  68. // duplicate item in vending to check hacker with multiple packets
  69. memcpy(&vending, &vsd->vending, sizeof(struct vending) * MAX_VENDING); // copy vending list
  70. // some checks
  71. z = 0.;
  72. w = 0;
  73. for(i = 0; 8 + 4 * i < len; i++) {
  74. amount = *(unsigned short*)(p + 4 * i);
  75. idx = *(short*)(p + 2 + 4 * i) - 2;
  76. if (amount <= 0)
  77. return;
  78. // check of item index in the cart
  79. if (idx < 0 || idx >= MAX_CART)
  80. return;
  81. for(j = 0; j < vsd->vend_num; j++) {
  82. if (vsd->vending[j].index == idx) {
  83. vend_list[i] = j;
  84. break;
  85. }
  86. }
  87. if (j == vsd->vend_num)
  88. return; //picked non-existing item
  89. z += ((double)vsd->vending[j].value * (double)amount);
  90. if (z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY) { // fix positiv overflow (buyer)
  91. clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny
  92. return; // zeny s'<
  93. }
  94. if (z + (double)vsd->status.zeny > (double)MAX_ZENY) { // fix positiv overflow (merchand)
  95. clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow
  96. return; // zeny s'<
  97. }
  98. w += itemdb_weight(vsd->status.cart[idx].nameid) * amount;
  99. if (w + sd->weight > sd->max_weight) {
  100. clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight
  101. return;
  102. }
  103. if (vending[j].amount > vsd->status.cart[idx].amount) //Check to see if cart/vend info is in sync.
  104. vending[j].amount = vsd->status.cart[idx].amount;
  105. // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
  106. // here, we check cumulativ amounts
  107. if (vending[j].amount < amount) {
  108. // send more quantity is not a hack (an other player can have buy items just before)
  109. clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity
  110. return;
  111. } else
  112. vending[j].amount -= amount;
  113. switch(pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount)) {
  114. case ADDITEM_EXIST:
  115. break; //We'd add this item to the existing one (in buyers inventory)
  116. case ADDITEM_NEW:
  117. new_++;
  118. if (new_ > blank)
  119. return; //Buyer has no space in his inventory
  120. break;
  121. case ADDITEM_OVERAMOUNT:
  122. return; //too many items
  123. }
  124. }
  125. //Logs (V)ending Zeny [Lupus]
  126. if(log_config.zeny > 0 )
  127. log_zeny(vsd, "V", sd, (int)z);
  128. //Logs
  129. pc_payzeny(sd, (int)z);
  130. pc_getzeny(vsd, (int)z);
  131. for(i = 0; 8 + 4 * i < len; i++) {
  132. amount = *(short*)(p + 4 *i);
  133. idx = *(short*)(p + 2 + 4 * i) - 2;
  134. //if (amount < 0) break; // tested at start of the function
  135. //Logs sold (V)ending items [Lupus]
  136. if(log_config.pick > 0 ) {
  137. log_pick(vsd, "V", 0, vsd->status.cart[idx].nameid, -amount, (struct item*)&vsd->status.cart[idx]);
  138. log_pick( sd, "V", 0, vsd->status.cart[idx].nameid, amount, (struct item*)&vsd->status.cart[idx]);
  139. }
  140. //Logs
  141. // vending item
  142. pc_additem(sd, &vsd->status.cart[idx], amount);
  143. vsd->vending[vend_list[i]].amount -= amount;
  144. pc_cart_delitem(vsd, idx, amount, 0);
  145. clif_vendingreport(vsd, idx, amount);
  146. //print buyer's name
  147. if(battle_config.buyer_name) {
  148. char temp[256];
  149. sprintf(temp, msg_txt(265), sd->status.name);
  150. clif_disp_onlyself(vsd,temp,strlen(temp));
  151. }
  152. }
  153. //Always save BOTH: buyer and customer
  154. if (save_settings&2) {
  155. chrif_save(sd,0);
  156. chrif_save(vsd,0);
  157. }
  158. //check for @AUTOTRADE users [durf]
  159. if (vsd->state.autotrade)
  160. {
  161. //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
  162. for(i = 0; i < vsd->vend_num && vsd->vending[i].amount < 1; i++);
  163. if (i == vsd->vend_num)
  164. {
  165. vending_closevending(vsd);
  166. map_quit(vsd); //They have no reason to stay around anymore, do they?
  167. }
  168. }
  169. }
  170. /*==========================================
  171. * 露店開設
  172. *------------------------------------------
  173. */
  174. void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p)
  175. {
  176. int i, j;
  177. int vending_skill_lvl;
  178. nullpo_retv(sd);
  179. if (map[sd->bl.m].flag.novending) {
  180. clif_displaymessage (sd->fd, msg_txt(276));
  181. return; //Can't vend in novending mapflag maps.
  182. }
  183. //check shopname len
  184. if(message[0] == '\0')
  185. return;
  186. vending_skill_lvl = pc_checkskill(sd, MC_VENDING);
  187. if(!vending_skill_lvl || !pc_iscarton(sd)) { // cart skill and cart check [Valaris]
  188. clif_skill_fail(sd,MC_VENDING,0,0);
  189. return;
  190. }
  191. if (flag) {
  192. // check number of items in shop
  193. if (len < 85 + 8 || len > 85 + 8 * MAX_VENDING || len > 85 + 8 * (2 + vending_skill_lvl)) {
  194. clif_skill_fail(sd, MC_VENDING, 0, 0);
  195. return;
  196. }
  197. for(i = 0, j = 0; (85 + 8 * j < len) && (i < MAX_VENDING); i++, j++) {
  198. sd->vending[i].index = *(short*)(p+8*j)-2;
  199. if (sd->vending[i].index < 0 || sd->vending[i].index >= MAX_CART ||
  200. !itemdb_cantrade(&sd->status.cart[sd->vending[i].index], pc_isGM(sd), pc_isGM(sd)))
  201. {
  202. i--; //Preserve the vending index, skip to the next item.
  203. continue;
  204. }
  205. sd->vending[i].amount = *(short*)(p+2+8*j);
  206. sd->vending[i].value = *(int*)(p+4+8*j);
  207. if(sd->vending[i].value > battle_config.vending_max_value)
  208. sd->vending[i].value=battle_config.vending_max_value;
  209. else if(sd->vending[i].value < 1)
  210. sd->vending[i].value = 1000000; // auto set to 1 million [celest]
  211. // カート内のアイテム数と販売するアイテム数に相違があったら中止
  212. if(pc_cartitem_amount(sd, sd->vending[i].index, sd->vending[i].amount) < 0) { // fixes by Valaris and fritz
  213. clif_skill_fail(sd, MC_VENDING, 0, 0);
  214. return;
  215. }
  216. }
  217. if (i != j)
  218. { //Some items were not vended. [Skotlex]
  219. clif_displaymessage (sd->fd, msg_txt(266));
  220. }
  221. sd->vender_id = sd->bl.id;
  222. sd->vend_num = i;
  223. memcpy(sd->message,message, MESSAGE_SIZE-1);
  224. if (clif_openvending(sd,sd->vender_id,sd->vending) > 0){
  225. pc_stop_walking(sd,1);
  226. clif_showvendingboard(&sd->bl,message,0);
  227. if(use_irc && irc_announce_shop_flag)
  228. irc_announce_shop(sd,1);
  229. } else
  230. sd->vender_id = 0;
  231. }
  232. }