diff options
Diffstat (limited to 'src/map/vending.c')
-rw-r--r-- | src/map/vending.c | 534 |
1 files changed, 267 insertions, 267 deletions
diff --git a/src/map/vending.c b/src/map/vending.c index 0f8ceaa30..9b4b797e0 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -1,267 +1,267 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
-
-#include <stdio.h>
-#include <string.h>
-
-#include "../common/nullpo.h"
-#include "clif.h"
-#include "itemdb.h"
-#include "atcommand.h"
-#include "map.h"
-#include "chrif.h"
-#include "vending.h"
-#include "pc.h"
-#include "skill.h"
-#include "battle.h"
-#include "log.h"
-
-#include "irc.h"
-
-/*==========================================
- * 露店閉鎖
- *------------------------------------------
-*/
-void vending_closevending(struct map_session_data *sd)
-{
- nullpo_retv(sd);
-
- sd->vender_id=0;
- clif_closevendingboard(&sd->bl,0);
- if(use_irc && irc_announce_shop_flag)
- irc_announce_shop(sd,0);
-}
-
-/*==========================================
- * 露店アイテムリスト要求
- *------------------------------------------
- */
-void vending_vendinglistreq(struct map_session_data *sd,int id)
-{
- struct map_session_data *vsd;
-
- nullpo_retv(sd);
-
- if( (vsd=map_id2sd(id)) == NULL )
- return;
- if(vsd->vender_id==0)
- return;
- clif_vendinglist(sd,id,vsd->vending);
-}
-
-/*==========================================
- * 露店アイテム購入
- *------------------------------------------
- */
-void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p)
-{
- int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING];
- double z;
- unsigned short amount;
- short idx;
- struct map_session_data *vsd = map_id2sd(id);
- struct vending vending[MAX_VENDING]; // against duplicate packets
-
- nullpo_retv(sd);
-
- if (vsd == NULL)
- return;
- if (vsd->vender_id == 0)
- return;
- if (vsd->vender_id == sd->bl.id)
- return;
-
- // check number of buying items
- if (len < 8 + 4 || len > 8 + 4 * MAX_VENDING) {
- clif_buyvending(sd, 0, 32767, 4); // not enough quantity (index and amount are unknown)
- return;
- }
-
- blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory
-
- // duplicate item in vending to check hacker with multiple packets
- memcpy(&vending, &vsd->vending, sizeof(struct vending) * MAX_VENDING); // copy vending list
-
- // some checks
- z = 0.;
- w = 0;
- for(i = 0; 8 + 4 * i < len; i++) {
- amount = *(unsigned short*)(p + 4 * i);
- idx = *(short*)(p + 2 + 4 * i) - 2;
-
- if (amount <= 0)
- return;
-
- // check of item index in the cart
- if (idx < 0 || idx >= MAX_CART)
- return;
-
- for(j = 0; j < vsd->vend_num; j++) {
- if (vsd->vending[j].index == idx) {
- vend_list[i] = j;
- break;
- }
- }
- if (j == vsd->vend_num)
- return; //picked non-existing item
-
- z += ((double)vsd->vending[j].value * (double)amount);
- if (z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY) { // fix positiv overflow (buyer)
- clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny
- return; // zeny s'<
- }
- if (z + (double)vsd->status.zeny > (double)MAX_ZENY) { // fix positiv overflow (merchand)
- clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow
- return; // zeny s'<
- }
- w += itemdb_weight(vsd->status.cart[idx].nameid) * amount;
- if (w + sd->weight > sd->max_weight) {
- clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight
- return;
- }
-
- if (vending[j].amount > vsd->status.cart[idx].amount) //Check to see if cart/vend info is in sync.
- vending[j].amount = vsd->status.cart[idx].amount;
-
- // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
- // here, we check cumulativ amounts
- if (vending[j].amount < amount) {
- // send more quantity is not a hack (an other player can have buy items just before)
- clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity
- return;
- } else
- vending[j].amount -= amount;
-
- switch(pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount)) {
- case ADDITEM_EXIST:
- break; //We'd add this item to the existing one (in buyers inventory)
- case ADDITEM_NEW:
- new_++;
- if (new_ > blank)
- return; //Buyer has no space in his inventory
- break;
- case ADDITEM_OVERAMOUNT:
- return; //too many items
- }
- }
-
- //Logs (V)ending Zeny [Lupus]
- if(log_config.zeny > 0 )
- log_zeny(vsd, "V", sd, (int)z);
- //Logs
-
- pc_payzeny(sd, (int)z);
- pc_getzeny(vsd, (int)z);
-
- for(i = 0; 8 + 4 * i < len; i++) {
- amount = *(short*)(p + 4 *i);
- idx = *(short*)(p + 2 + 4 * i) - 2;
- //if (amount < 0) break; // tested at start of the function
-
- //Logs sold (V)ending items [Lupus]
- if(log_config.enable_logs&0x4) {
- log_pick_pc(vsd, "V", vsd->status.cart[idx].nameid, -amount, (struct item*)&vsd->status.cart[idx]);
- log_pick_pc( sd, "V", vsd->status.cart[idx].nameid, amount, (struct item*)&vsd->status.cart[idx]);
- }
- //Logs
-
- // vending item
- pc_additem(sd, &vsd->status.cart[idx], amount);
- vsd->vending[vend_list[i]].amount -= amount;
- pc_cart_delitem(vsd, idx, amount, 0);
- clif_vendingreport(vsd, idx, amount);
-
- //print buyer's name
- if(battle_config.buyer_name) {
- char temp[256];
- sprintf(temp, msg_txt(265), sd->status.name);
- clif_disp_onlyself(vsd,temp,strlen(temp));
- }
- }
-
- //Always save BOTH: buyer and customer
- if (save_settings&2) {
- chrif_save(sd,0);
- chrif_save(vsd,0);
- }
- //check for @AUTOTRADE users [durf]
- if (vsd->state.autotrade)
- {
- //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
- for(i = 0; i < vsd->vend_num && vsd->vending[i].amount < 1; i++);
- if (i == vsd->vend_num)
- {
- vending_closevending(vsd);
- map_quit(vsd); //They have no reason to stay around anymore, do they?
- }
- }
-}
-
-/*==========================================
- * 露店開設
- *------------------------------------------
- */
-void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p)
-{
- int i, j;
- int vending_skill_lvl;
- nullpo_retv(sd);
-
- if (map[sd->bl.m].flag.novending) {
- clif_displaymessage (sd->fd, msg_txt(276));
- return; //Can't vend in novending mapflag maps.
- }
-
- //check shopname len
- if(message[0] == '\0')
- return;
-
- vending_skill_lvl = pc_checkskill(sd, MC_VENDING);
- if(!vending_skill_lvl || !pc_iscarton(sd)) { // cart skill and cart check [Valaris]
- clif_skill_fail(sd,MC_VENDING,0,0);
- return;
- }
-
- if (flag) {
- // check number of items in shop
- if (len < 85 + 8 || len > 85 + 8 * MAX_VENDING || len > 85 + 8 * (2 + vending_skill_lvl)) {
- clif_skill_fail(sd, MC_VENDING, 0, 0);
- return;
- }
- for(i = 0, j = 0; (85 + 8 * j < len) && (i < MAX_VENDING); i++, j++) {
- sd->vending[i].index = *(short*)(p+8*j)-2;
- if (sd->vending[i].index < 0 || sd->vending[i].index >= MAX_CART ||
- !itemdb_cantrade(&sd->status.cart[sd->vending[i].index], pc_isGM(sd), pc_isGM(sd)))
- {
- i--; //Preserve the vending index, skip to the next item.
- continue;
- }
- sd->vending[i].amount = *(short*)(p+2+8*j);
- sd->vending[i].value = *(int*)(p+4+8*j);
- if(sd->vending[i].value > battle_config.vending_max_value)
- sd->vending[i].value=battle_config.vending_max_value;
- else if(sd->vending[i].value < 1)
- sd->vending[i].value = 1000000; // auto set to 1 million [celest]
- // カート内のアイテム数と販売するアイテム数に相違があったら中止
- if(pc_cartitem_amount(sd, sd->vending[i].index, sd->vending[i].amount) < 0) { // fixes by Valaris and fritz
- clif_skill_fail(sd, MC_VENDING, 0, 0);
- return;
- }
- }
- if (i != j)
- { //Some items were not vended. [Skotlex]
- clif_displaymessage (sd->fd, msg_txt(266));
- }
- sd->vender_id = sd->bl.id;
- sd->vend_num = i;
- memcpy(sd->message,message, MESSAGE_SIZE-1);
- if (clif_openvending(sd,sd->vender_id,sd->vending) > 0){
- pc_stop_walking(sd,1);
- clif_showvendingboard(&sd->bl,message,0);
- if(use_irc && irc_announce_shop_flag)
- irc_announce_shop(sd,1);
- } else
- sd->vender_id = 0;
- }
-}
-
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include <stdio.h> +#include <string.h> + +#include "../common/nullpo.h" +#include "clif.h" +#include "itemdb.h" +#include "atcommand.h" +#include "map.h" +#include "chrif.h" +#include "vending.h" +#include "pc.h" +#include "skill.h" +#include "battle.h" +#include "log.h" + +#include "irc.h" + +/*========================================== + * 露店閉鎖 + *------------------------------------------ +*/ +void vending_closevending(struct map_session_data *sd) +{ + nullpo_retv(sd); + + sd->vender_id=0; + clif_closevendingboard(&sd->bl,0); + if(use_irc && irc_announce_shop_flag) + irc_announce_shop(sd,0); +} + +/*========================================== + * 露店アイテムリスト要求 + *------------------------------------------ + */ +void vending_vendinglistreq(struct map_session_data *sd,int id) +{ + struct map_session_data *vsd; + + nullpo_retv(sd); + + if( (vsd=map_id2sd(id)) == NULL ) + return; + if(vsd->vender_id==0) + return; + clif_vendinglist(sd,id,vsd->vending); +} + +/*========================================== + * 露店アイテム購入 + *------------------------------------------ + */ +void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p) +{ + int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING]; + double z; + unsigned short amount; + short idx; + struct map_session_data *vsd = map_id2sd(id); + struct vending vending[MAX_VENDING]; // against duplicate packets + + nullpo_retv(sd); + + if (vsd == NULL) + return; + if (vsd->vender_id == 0) + return; + if (vsd->vender_id == sd->bl.id) + return; + + // check number of buying items + if (len < 8 + 4 || len > 8 + 4 * MAX_VENDING) { + clif_buyvending(sd, 0, 32767, 4); // not enough quantity (index and amount are unknown) + return; + } + + blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory + + // duplicate item in vending to check hacker with multiple packets + memcpy(&vending, &vsd->vending, sizeof(struct vending) * MAX_VENDING); // copy vending list + + // some checks + z = 0.; + w = 0; + for(i = 0; 8 + 4 * i < len; i++) { + amount = *(unsigned short*)(p + 4 * i); + idx = *(short*)(p + 2 + 4 * i) - 2; + + if (amount <= 0) + return; + + // check of item index in the cart + if (idx < 0 || idx >= MAX_CART) + return; + + for(j = 0; j < vsd->vend_num; j++) { + if (vsd->vending[j].index == idx) { + vend_list[i] = j; + break; + } + } + if (j == vsd->vend_num) + return; //picked non-existing item + + z += ((double)vsd->vending[j].value * (double)amount); + if (z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY) { // fix positiv overflow (buyer) + clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny + return; // zeny s'< + } + if (z + (double)vsd->status.zeny > (double)MAX_ZENY) { // fix positiv overflow (merchand) + clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow + return; // zeny s'< + } + w += itemdb_weight(vsd->status.cart[idx].nameid) * amount; + if (w + sd->weight > sd->max_weight) { + clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight + return; + } + + if (vending[j].amount > vsd->status.cart[idx].amount) //Check to see if cart/vend info is in sync. + vending[j].amount = vsd->status.cart[idx].amount; + + // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples). + // here, we check cumulativ amounts + if (vending[j].amount < amount) { + // send more quantity is not a hack (an other player can have buy items just before) + clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity + return; + } else + vending[j].amount -= amount; + + switch(pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount)) { + case ADDITEM_EXIST: + break; //We'd add this item to the existing one (in buyers inventory) + case ADDITEM_NEW: + new_++; + if (new_ > blank) + return; //Buyer has no space in his inventory + break; + case ADDITEM_OVERAMOUNT: + return; //too many items + } + } + + //Logs (V)ending Zeny [Lupus] + if(log_config.zeny > 0 ) + log_zeny(vsd, "V", sd, (int)z); + //Logs + + pc_payzeny(sd, (int)z); + pc_getzeny(vsd, (int)z); + + for(i = 0; 8 + 4 * i < len; i++) { + amount = *(short*)(p + 4 *i); + idx = *(short*)(p + 2 + 4 * i) - 2; + //if (amount < 0) break; // tested at start of the function + + //Logs sold (V)ending items [Lupus] + if(log_config.enable_logs&0x4) { + log_pick_pc(vsd, "V", vsd->status.cart[idx].nameid, -amount, (struct item*)&vsd->status.cart[idx]); + log_pick_pc( sd, "V", vsd->status.cart[idx].nameid, amount, (struct item*)&vsd->status.cart[idx]); + } + //Logs + + // vending item + pc_additem(sd, &vsd->status.cart[idx], amount); + vsd->vending[vend_list[i]].amount -= amount; + pc_cart_delitem(vsd, idx, amount, 0); + clif_vendingreport(vsd, idx, amount); + + //print buyer's name + if(battle_config.buyer_name) { + char temp[256]; + sprintf(temp, msg_txt(265), sd->status.name); + clif_disp_onlyself(vsd,temp,strlen(temp)); + } + } + + //Always save BOTH: buyer and customer + if (save_settings&2) { + chrif_save(sd,0); + chrif_save(vsd,0); + } + //check for @AUTOTRADE users [durf] + if (vsd->state.autotrade) + { + //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex] + for(i = 0; i < vsd->vend_num && vsd->vending[i].amount < 1; i++); + if (i == vsd->vend_num) + { + vending_closevending(vsd); + map_quit(vsd); //They have no reason to stay around anymore, do they? + } + } +} + +/*========================================== + * 露店開設 + *------------------------------------------ + */ +void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p) +{ + int i, j; + int vending_skill_lvl; + nullpo_retv(sd); + + if (map[sd->bl.m].flag.novending) { + clif_displaymessage (sd->fd, msg_txt(276)); + return; //Can't vend in novending mapflag maps. + } + + //check shopname len + if(message[0] == '\0') + return; + + vending_skill_lvl = pc_checkskill(sd, MC_VENDING); + if(!vending_skill_lvl || !pc_iscarton(sd)) { // cart skill and cart check [Valaris] + clif_skill_fail(sd,MC_VENDING,0,0); + return; + } + + if (flag) { + // check number of items in shop + if (len < 85 + 8 || len > 85 + 8 * MAX_VENDING || len > 85 + 8 * (2 + vending_skill_lvl)) { + clif_skill_fail(sd, MC_VENDING, 0, 0); + return; + } + for(i = 0, j = 0; (85 + 8 * j < len) && (i < MAX_VENDING); i++, j++) { + sd->vending[i].index = *(short*)(p+8*j)-2; + if (sd->vending[i].index < 0 || sd->vending[i].index >= MAX_CART || + !itemdb_cantrade(&sd->status.cart[sd->vending[i].index], pc_isGM(sd), pc_isGM(sd))) + { + i--; //Preserve the vending index, skip to the next item. + continue; + } + sd->vending[i].amount = *(short*)(p+2+8*j); + sd->vending[i].value = *(int*)(p+4+8*j); + if(sd->vending[i].value > battle_config.vending_max_value) + sd->vending[i].value=battle_config.vending_max_value; + else if(sd->vending[i].value < 1) + sd->vending[i].value = 1000000; // auto set to 1 million [celest] + // カート内のアイテム数と販売するアイテム数に相違があったら中止 + if(pc_cartitem_amount(sd, sd->vending[i].index, sd->vending[i].amount) < 0) { // fixes by Valaris and fritz + clif_skill_fail(sd, MC_VENDING, 0, 0); + return; + } + } + if (i != j) + { //Some items were not vended. [Skotlex] + clif_displaymessage (sd->fd, msg_txt(266)); + } + sd->vender_id = sd->bl.id; + sd->vend_num = i; + memcpy(sd->message,message, MESSAGE_SIZE-1); + if (clif_openvending(sd,sd->vender_id,sd->vending) > 0){ + pc_stop_walking(sd,1); + clif_showvendingboard(&sd->bl,message,0); + if(use_irc && irc_announce_shop_flag) + irc_announce_shop(sd,1); + } else + sd->vender_id = 0; + } +} + |