* Fixed various trading/vending glitches

- fixed vending_tax not working at all (integer division in r10182)
- undid change from r8273 where pc_getzeny() treated zeny overflow as an error condition; officially, the value is just bounded to MAX_ZENY
- fixed stupid code that, instead of properly checking and filtering invalid items during shop setup, opted to 'hide' these items from the vending list instead...
- removed some custom error message packets related to vending
- fixed a glitch where the server would open a shop with no items when all entered items were tagged as invalid
- split zeny handling from trade_tradeadditem() into a separate func (trade_tradeaddzeny())
- removed loads of redundant code from vending.c

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11344 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
ultramage 2007-10-01 14:55:35 +00:00
parent 2c61369250
commit 6a2e87e03b
9 changed files with 501 additions and 468 deletions

View File

@ -3,6 +3,20 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/10/01
* Fixed various trading/vending glitches [ultramage]
- fixed vending_tax not working at all (integer division in r10182)
- undid change from r8273 where pc_getzeny() treated zeny overflow as
an error condition; officially, the value is just bounded to MAX_ZENY
(this fixes stuff like shops that you can't buy items from).
- fixed stupid code that, instead of properly checking and filtering
invalid items during shop setup, opted to 'hide' these items from
the vending list instead...
- removed some custom error message packets related to vending
- fixed a glitch where the server would open a shop with no items
when all entered items were tagged as invalid
- split zeny handling from trade_tradeadditem() into a separate func
- removed loads of redundant code from vending.c
2007/09/30 2007/09/30
* Removed redundant 'subnet' s_subnet structure variable. [ultramage] * Removed redundant 'subnet' s_subnet structure variable. [ultramage]
2007/09/28 2007/09/28

View File

@ -3348,59 +3348,51 @@ void clif_leavechat(struct chat_data* cd, struct map_session_data* sd, bool flag
} }
/*========================================== /*==========================================
* * Opens a trade request window from char 'name'
* R 00e5 <nick>.24B
*------------------------------------------*/ *------------------------------------------*/
int clif_traderequest(struct map_session_data* sd, const char* name) void clif_traderequest(struct map_session_data* sd, const char* name)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xe5)); WFIFOHEAD(fd,packet_len(0xe5));
WFIFOW(fd,0) = 0xe5; WFIFOW(fd,0) = 0xe5;
safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH);
strcpy((char*)WFIFOP(fd,2),name);
WFIFOSET(fd,packet_len(0xe5)); WFIFOSET(fd,packet_len(0xe5));
return 0;
} }
/*========================================== /*==========================================
* *
*------------------------------------------*/ *------------------------------------------*/
int clif_tradestart(struct map_session_data *sd,int type) void clif_tradestart(struct map_session_data* sd, int type)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xe7)); WFIFOHEAD(fd,packet_len(0xe7));
WFIFOW(fd,0) = 0xe7; WFIFOW(fd,0) = 0xe7;
WFIFOB(fd,2) = type; WFIFOB(fd,2) = type;
WFIFOSET(fd,packet_len(0xe7)); WFIFOSET(fd,packet_len(0xe7));
return 0;
} }
/*========================================== /*==========================================
* *
*------------------------------------------*/ *------------------------------------------*/
int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,int index,int amount) void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd, int index, int amount)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd); nullpo_retv(tsd);
nullpo_retr(0, tsd);
fd = tsd->fd; fd = tsd->fd;
WFIFOHEAD(fd,packet_len(0xe9)); WFIFOHEAD(fd,packet_len(0xe9));
WFIFOW(fd,0) = 0xe9; WFIFOW(fd,0) = 0xe9;
WFIFOL(fd,2) = amount; WFIFOL(fd,2) = amount;
if(index==0){ if( index == 0 )
{
WFIFOW(fd,6) = 0; // type id WFIFOW(fd,6) = 0; // type id
WFIFOB(fd,8) = 0; //identify flag WFIFOB(fd,8) = 0; //identify flag
WFIFOB(fd,9) = 0; // attribute WFIFOB(fd,9) = 0; // attribute
@ -3410,7 +3402,8 @@ int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,i
WFIFOW(fd,15)= 0; //card (4w) WFIFOW(fd,15)= 0; //card (4w)
WFIFOW(fd,17)= 0; //card (4w) WFIFOW(fd,17)= 0; //card (4w)
} }
else{ else
{
index -= 2; //index fix index -= 2; //index fix
if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0) if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
WFIFOW(fd,6) = sd->inventory_data[index]->view_id; WFIFOW(fd,6) = sd->inventory_data[index]->view_id;
@ -3422,18 +3415,15 @@ int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,i
clif_addcards(WFIFOP(fd, 11), &sd->status.inventory[index]); clif_addcards(WFIFOP(fd, 11), &sd->status.inventory[index]);
} }
WFIFOSET(fd,packet_len(0xe9)); WFIFOSET(fd,packet_len(0xe9));
return 0;
} }
/*========================================== /*==========================================
* / * /
*------------------------------------------*/ *------------------------------------------*/
int clif_tradeitemok(struct map_session_data *sd,int index,int fail) void clif_tradeitemok(struct map_session_data* sd, int index, int fail)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xea)); WFIFOHEAD(fd,packet_len(0xea));
@ -3441,61 +3431,50 @@ int clif_tradeitemok(struct map_session_data *sd,int index,int fail)
WFIFOW(fd,2) = index; WFIFOW(fd,2) = index;
WFIFOB(fd,4) = fail; WFIFOB(fd,4) = fail;
WFIFOSET(fd,packet_len(0xea)); WFIFOSET(fd,packet_len(0xea));
return 0;
} }
/*========================================== /*==========================================
* ok押し * ok押し
*------------------------------------------*/ *------------------------------------------*/
int clif_tradedeal_lock(struct map_session_data *sd,int fail) void clif_tradedeal_lock(struct map_session_data* sd, int fail)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xec)); WFIFOHEAD(fd,packet_len(0xec));
WFIFOW(fd,0) = 0xec; WFIFOW(fd,0) = 0xec;
WFIFOB(fd,2) = fail; // 0=you 1=the other person WFIFOB(fd,2) = fail; // 0=you 1=the other person
WFIFOSET(fd,packet_len(0xec)); WFIFOSET(fd,packet_len(0xec));
return 0;
} }
/*========================================== /*==========================================
* *
*------------------------------------------*/ *------------------------------------------*/
int clif_tradecancelled(struct map_session_data *sd) void clif_tradecancelled(struct map_session_data* sd)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xee)); WFIFOHEAD(fd,packet_len(0xee));
WFIFOW(fd,0) = 0xee; WFIFOW(fd,0) = 0xee;
WFIFOSET(fd,packet_len(0xee)); WFIFOSET(fd,packet_len(0xee));
return 0;
} }
/*========================================== /*==========================================
* *
*------------------------------------------*/ *------------------------------------------*/
int clif_tradecompleted(struct map_session_data *sd,int fail) void clif_tradecompleted(struct map_session_data* sd, int fail)
{ {
int fd; int fd;
nullpo_retv(sd);
nullpo_retr(0, sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xf0)); WFIFOHEAD(fd,packet_len(0xf0));
WFIFOW(fd,0) = 0xf0; WFIFOW(fd,0) = 0xf0;
WFIFOB(fd,2) = fail; WFIFOB(fd,2) = fail;
WFIFOSET(fd,packet_len(0xf0)); WFIFOSET(fd,packet_len(0xf0));
return 0;
} }
/*========================================== /*==========================================
@ -3639,12 +3618,14 @@ int clif_storageclose(struct map_session_data *sd)
void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd) void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
{ {
int len; int len;
if(dstsd->chatID){ if(dstsd->chatID)
{
struct chat_data *cd; struct chat_data *cd;
cd=(struct chat_data*)map_id2bl(dstsd->chatID); cd=(struct chat_data*)map_id2bl(dstsd->chatID);
if(cd && cd->usersd[0]==dstsd) if(cd && cd->usersd[0]==dstsd)
clif_dispchat(cd,sd->fd); clif_dispchat(cd,sd->fd);
} }
if(dstsd->vender_id) if(dstsd->vender_id)
clif_showvendingboard(&dstsd->bl,dstsd->message,sd->fd); clif_showvendingboard(&dstsd->bl,dstsd->message,sd->fd);
@ -5461,35 +5442,37 @@ int clif_cart_delitem(struct map_session_data *sd,int n,int amount)
} }
/*========================================== /*==========================================
* * Opens the shop creation menu.
* R 012d <num>.w
* 'num' is the number of allowed item slots
*------------------------------------------*/ *------------------------------------------*/
int clif_openvendingreq(struct map_session_data *sd,int num) void clif_openvendingreq(struct map_session_data* sd, int num)
{ {
int fd; int fd;
nullpo_retr(0, sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x12d)); WFIFOHEAD(fd,packet_len(0x12d));
WFIFOW(fd,0) = 0x12d; WFIFOW(fd,0) = 0x12d;
WFIFOW(fd,2) = num; WFIFOW(fd,2) = num;
WFIFOSET(fd,packet_len(0x12d)); WFIFOSET(fd,packet_len(0x12d));
return 0;
} }
/*========================================== /*==========================================
* * Displays a vending board to target/area
* R 0131 <ID>.l <message>.80B
*------------------------------------------*/ *------------------------------------------*/
int clif_showvendingboard(struct block_list* bl, const char* message, int fd) void clif_showvendingboard(struct block_list* bl, const char* message, int fd)
{ {
unsigned char buf[128]; unsigned char buf[128];
nullpo_retr(0, bl); nullpo_retv(bl);
WBUFW(buf,0) = 0x131; WBUFW(buf,0) = 0x131;
WBUFL(buf,2) = bl->id; WBUFL(buf,2) = bl->id;
strncpy((char*)WBUFP(buf,6),message,80); safestrncpy((char*)WBUFP(buf,6), message, 80);
if( fd ) { if( fd ) {
WFIFOHEAD(fd,packet_len(0x131)); WFIFOHEAD(fd,packet_len(0x131));
memcpy(WFIFOP(fd,0),buf,packet_len(0x131)); memcpy(WFIFOP(fd,0),buf,packet_len(0x131));
@ -5497,17 +5480,16 @@ int clif_showvendingboard(struct block_list* bl, const char* message, int fd)
} else { } else {
clif_send(buf,packet_len(0x131),bl,AREA_WOS); clif_send(buf,packet_len(0x131),bl,AREA_WOS);
} }
return 0;
} }
/*========================================== /*==========================================
* * Removes a vending board from screen
*------------------------------------------*/ *------------------------------------------*/
int clif_closevendingboard(struct block_list* bl,int fd) void clif_closevendingboard(struct block_list* bl, int fd)
{ {
unsigned char buf[16]; unsigned char buf[16];
nullpo_retr(0, bl); nullpo_retv(bl);
WBUFW(buf,0) = 0x132; WBUFW(buf,0) = 0x132;
WBUFL(buf,2) = bl->id; WBUFL(buf,2) = bl->id;
@ -5518,64 +5500,59 @@ int clif_closevendingboard(struct block_list* bl,int fd)
} else { } else {
clif_send(buf,packet_len(0x132),bl,AREA_WOS); clif_send(buf,packet_len(0x132),bl,AREA_WOS);
} }
return 0;
} }
/*==========================================
*
*------------------------------------------*/
int clif_vendinglist(struct map_session_data *sd,int id,struct vending *vending)
{
struct item_data *data;
int i,n,index,fd;
struct map_session_data *vsd;
unsigned char *buf;
nullpo_retr(0, sd); /*==========================================
nullpo_retr(0, vending); * Sends a list of items in a shop
nullpo_retr(0, vsd=map_id2sd(id)); * R 0133 <len>.w <ID>.l {<value>.l <amount>.w <index>.w <type>.B <item ID>.w <identify flag>.B <attribute?>.B <refine>.B <card>.4w}.22B
*------------------------------------------*/
void clif_vendinglist(struct map_session_data* sd, int id, struct s_vending* vending)
{
int i,fd;
int count;
struct map_session_data* vsd;
nullpo_retv(sd);
nullpo_retv(vending);
nullpo_retv(vsd=map_id2sd(id));
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd, 8+vsd->vend_num*22); count = vsd->vend_num;
buf = WFIFOP(fd,0);
for(i=0,n=0;i<vsd->vend_num;i++){ WFIFOHEAD(fd, 8+count*22);
if(vending[i].amount<=0) WFIFOW(fd,0) = 0x133;
continue; WFIFOW(fd,2) = 8+count*22;
WBUFL(buf,8+n*22)=vending[i].value; WFIFOL(fd,4) = id;
WBUFW(buf,12+n*22)=vending[i].amount; for( i = 0; i < count; i++ )
WBUFW(buf,14+n*22)=(index=vending[i].index)+2; {
if(vsd->status.cart[index].nameid <= 0 || vsd->status.cart[index].amount <= 0) int index = vending[i].index;
continue; struct item_data* data = itemdb_search(vsd->status.cart[index].nameid);
data = itemdb_search(vsd->status.cart[index].nameid); WFIFOL(fd, 8+i*22) = vending[i].value;
WBUFB(buf,16+n*22)=itemtype(data->type); WFIFOW(fd,12+i*22) = vending[i].amount;
if(data->view_id > 0) WFIFOW(fd,14+i*22) = vending[i].index + 2;
WBUFW(buf,17+n*22)=data->view_id; WFIFOB(fd,16+i*22) = itemtype(data->type);
else WFIFOW(fd,17+i*22) = ( data->view_id > 0 ) ? data->view_id : vsd->status.cart[index].nameid;
WBUFW(buf,17+n*22)=vsd->status.cart[index].nameid; WFIFOB(fd,19+i*22) = vsd->status.cart[index].identify;
WBUFB(buf,19+n*22)=vsd->status.cart[index].identify; WFIFOB(fd,20+i*22) = vsd->status.cart[index].attribute;
WBUFB(buf,20+n*22)=vsd->status.cart[index].attribute; WFIFOB(fd,21+i*22) = vsd->status.cart[index].refine;
WBUFB(buf,21+n*22)=vsd->status.cart[index].refine; clif_addcards(WFIFOP(fd, 22+i*22), &vsd->status.cart[index]);
clif_addcards(WBUFP(buf, 22+n*22), &vsd->status.cart[index]);
n++;
} }
if(n > 0){
WBUFW(buf,0)=0x133;
WBUFW(buf,2)=8+n*22;
WBUFL(buf,4)=id;
WFIFOSET(fd,WFIFOW(fd,2)); WFIFOSET(fd,WFIFOW(fd,2));
} }
return 0;
}
/*========================================== /*==========================================
* * Shop purchase failure
* R 0135 <index>.w <amount>.w <fail>.B
* fail=1 - not enough zeny
* fail=2 - overweight
* fail=4 - out of stock
* fail=5 - "cannot use an npc shop while in a trade"
*------------------------------------------*/ *------------------------------------------*/
int clif_buyvending(struct map_session_data *sd,int index,int amount,int fail) void clif_buyvending(struct map_session_data* sd, int index, int amount, int fail)
{ {
int fd; int fd;
nullpo_retr(0, sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x135)); WFIFOHEAD(fd,packet_len(0x135));
@ -5584,61 +5561,52 @@ int clif_buyvending(struct map_session_data *sd,int index,int amount,int fail)
WFIFOW(fd,4) = amount; WFIFOW(fd,4) = amount;
WFIFOB(fd,6) = fail; WFIFOB(fd,6) = fail;
WFIFOSET(fd,packet_len(0x135)); WFIFOSET(fd,packet_len(0x135));
return 0;
} }
/*========================================== /*==========================================
* * Shop creation success
* R 0136 <len>.w <ID>.l {<value>.l <index>.w <amount>.w <type>.B <item ID>.w <identify flag>.B <attribute?>.B <refine>.B <card>.4w}.22B*
*------------------------------------------*/ *------------------------------------------*/
int clif_openvending(struct map_session_data *sd,int id,struct vending *vending) void clif_openvending(struct map_session_data* sd, int id, struct s_vending* vending)
{ {
struct item_data *data; int i,fd;
int i,n,index,fd; int count;
unsigned char *buf;
nullpo_retr(0, sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd, 8+sd->vend_num*22); count = sd->vend_num;
buf = WFIFOP(fd,0);
for(i = 0, n = 0; i < sd->vend_num; i++) { WFIFOHEAD(fd, 8+count*22);
if (sd->vend_num > 2+pc_checkskill(sd,MC_VENDING)) return 0; WFIFOW(fd,0) = 0x136;
WBUFL(buf,8+n*22)=vending[i].value; WFIFOW(fd,2) = 8+count*22;
WBUFW(buf,12+n*22)=(index=vending[i].index)+2; WFIFOL(fd,4) = id;
WBUFW(buf,14+n*22)=vending[i].amount; for( i = 0; i < count; i++ )
if(sd->status.cart[index].nameid <= 0 || sd->status.cart[index].amount <= 0 || !sd->status.cart[index].identify || {
sd->status.cart[index].attribute==1) // Prevent unidentified and broken items from being sold [Valaris] int index = vending[i].index;
continue; struct item_data* data = itemdb_search(sd->status.cart[index].nameid);
data = itemdb_search(sd->status.cart[index].nameid); WFIFOL(fd, 8+i*22) = vending[i].value;
WBUFB(buf,16+n*22)=itemtype(data->type); WFIFOW(fd,12+i*22) = vending[i].index + 2;
if(data->view_id > 0) WFIFOW(fd,14+i*22) = vending[i].amount;
WBUFW(buf,17+n*22)=data->view_id; WFIFOB(fd,16+i*22) = itemtype(data->type);
else WFIFOW(fd,17+i*22) = ( data->view_id > 0 ) ? data->view_id : sd->status.cart[index].nameid;
WBUFW(buf,17+n*22)=sd->status.cart[index].nameid; WFIFOB(fd,19+i*22) = sd->status.cart[index].identify;
WBUFB(buf,19+n*22)=sd->status.cart[index].identify; WFIFOB(fd,20+i*22) = sd->status.cart[index].attribute;
WBUFB(buf,20+n*22)=sd->status.cart[index].attribute; WFIFOB(fd,21+i*22) = sd->status.cart[index].refine;
WBUFB(buf,21+n*22)=sd->status.cart[index].refine; clif_addcards(WFIFOP(fd,22+count*22), &sd->status.cart[index]);
clif_addcards(WBUFP(buf, 22+n*22), &sd->status.cart[index]);
n++;
} }
if(n > 0) {
WBUFW(buf,0)=0x136;
WBUFW(buf,2)=8+n*22;
WBUFL(buf,4)=id;
WFIFOSET(fd,WFIFOW(fd,2)); WFIFOSET(fd,WFIFOW(fd,2));
} }
return n;
}
/*========================================== /*==========================================
* * Inform merchant that someone has bought an item.
* R 0137 <index>.w <amount>.w
*------------------------------------------*/ *------------------------------------------*/
int clif_vendingreport(struct map_session_data *sd,int index,int amount) void clif_vendingreport(struct map_session_data* sd, int index, int amount)
{ {
int fd; int fd;
nullpo_retr(0, sd); nullpo_retv(sd);
fd = sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x137)); WFIFOHEAD(fd,packet_len(0x137));
@ -5646,8 +5614,6 @@ int clif_vendingreport(struct map_session_data *sd,int index,int amount)
WFIFOW(fd,2) = index+2; WFIFOW(fd,2) = index+2;
WFIFOW(fd,4) = amount; WFIFOW(fd,4) = amount;
WFIFOSET(fd,packet_len(0x137)); WFIFOSET(fd,packet_len(0x137));
return 0;
} }
/*========================================== /*==========================================
* *
@ -9345,7 +9311,13 @@ void clif_parse_TradeAck(int fd,struct map_session_data *sd)
*------------------------------------------*/ *------------------------------------------*/
void clif_parse_TradeAddItem(int fd,struct map_session_data *sd) void clif_parse_TradeAddItem(int fd,struct map_session_data *sd)
{ {
trade_tradeadditem(sd,RFIFOW(fd,2),RFIFOL(fd,4)); int index = RFIFOW(fd,2);
int amount = RFIFOL(fd,4);
if( index == 0 )
trade_tradeaddzeny(sd, amount);
else
trade_tradeadditem(sd, index, amount);
} }
/*========================================== /*==========================================
@ -10220,28 +10192,46 @@ void clif_parse_CloseVending(int fd, struct map_session_data *sd)
void clif_parse_VendingListReq(int fd, struct map_session_data* sd) void clif_parse_VendingListReq(int fd, struct map_session_data* sd)
{ {
vending_vendinglistreq(sd,RFIFOL(fd,2)); vending_vendinglistreq(sd,RFIFOL(fd,2));
if( sd->npc_id ) if( sd->npc_id )
npc_event_dequeue(sd); npc_event_dequeue(sd);
} }
/*========================================== /*==========================================
* * Shop item(s) purchase request
* S 0134 <len>.w <ID>.l {<amount>.w <index>.w}.4B*
*------------------------------------------*/ *------------------------------------------*/
void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) void clif_parse_PurchaseReq(int fd, struct map_session_data* sd)
{ {
vending_purchasereq(sd, RFIFOW(fd,2), RFIFOL(fd,4), RFIFOP(fd,8)); int len = (int)RFIFOW(fd,2) - 8;
int id = (int)RFIFOL(fd,4);
const uint8* data = (uint8*)RFIFOP(fd,8);
vending_purchasereq(sd, id, data, len/4);
} }
/*========================================== /*==========================================
* * Confirm or cancel the shop preparation window
* S 01b2 <len>.w <message>.80B <flag>.B {<index>.w <amount>.w <value>.l}.8B*
* flag: 0=cancel, 1=confirm
*------------------------------------------*/ *------------------------------------------*/
void clif_parse_OpenVending(int fd, struct map_session_data* sd) void clif_parse_OpenVending(int fd, struct map_session_data* sd)
{ {
if (pc_istrading(sd)) short len = (short)RFIFOW(fd,2) - 85;
return; const char* message = (char*)RFIFOP(fd,4);
bool flag = (bool)RFIFOB(fd,84);
const uint8* data = (uint8*)RFIFOP(fd,85);
if (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOROOM) if (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOROOM)
return; return;
vending_openvending(sd, RFIFOW(fd,2), (char*)RFIFOP(fd,4), RFIFOB(fd,84), RFIFOP(fd,85)); if (map[sd->bl.m].flag.novending) {
clif_displaymessage (sd->fd, msg_txt(276)); // "You can't open shop on this map"
return;
}
if( message[0] == '\0' ) // invalid input
return;
vending_openvending(sd, message, flag, data, len/8);
} }
/*========================================== /*==========================================

View File

@ -19,7 +19,7 @@ struct npc_data;
struct chat_data; struct chat_data;
struct flooritem_data; struct flooritem_data;
struct skill_unit; struct skill_unit;
struct vending; struct s_vending;
struct party; struct party;
struct party_data; struct party_data;
struct guild; struct guild;
@ -166,13 +166,13 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd);
void clif_hotkeys_send(struct map_session_data *sd); void clif_hotkeys_send(struct map_session_data *sd);
// trade // trade
int clif_traderequest(struct map_session_data* sd, const char* name); void clif_traderequest(struct map_session_data* sd, const char* name);
int clif_tradestart(struct map_session_data *sd,int type); void clif_tradestart(struct map_session_data* sd, int type);
int clif_tradeadditem(struct map_session_data *sd,struct map_session_data *tsd,int index,int amount); void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd, int index, int amount);
int clif_tradeitemok(struct map_session_data *sd,int index,int fail); void clif_tradeitemok(struct map_session_data* sd, int index, int fail);
int clif_tradedeal_lock(struct map_session_data *sd,int fail); void clif_tradedeal_lock(struct map_session_data* sd, int fail);
int clif_tradecancelled(struct map_session_data *sd); void clif_tradecancelled(struct map_session_data* sd);
int clif_tradecompleted(struct map_session_data *sd,int fail); void clif_tradecompleted(struct map_session_data* sd, int fail);
// storage // storage
#include "storage.h" #include "storage.h"
@ -266,13 +266,13 @@ int clif_mvp_exp(struct map_session_data *sd,unsigned long exp);
void clif_changed_dir(struct block_list *bl, int area); void clif_changed_dir(struct block_list *bl, int area);
// vending // vending
int clif_openvendingreq(struct map_session_data *sd,int num); void clif_openvendingreq(struct map_session_data* sd, int num);
int clif_showvendingboard(struct block_list* bl, const char* message, int fd); void clif_showvendingboard(struct block_list* bl, const char* message, int fd);
int clif_closevendingboard(struct block_list* bl,int fd); void clif_closevendingboard(struct block_list* bl,int fd);
int clif_vendinglist(struct map_session_data *sd,int id,struct vending *vending); void clif_vendinglist(struct map_session_data* sd,int id, struct s_vending* vending);
int clif_buyvending(struct map_session_data *sd,int index,int amount,int fail); void clif_buyvending(struct map_session_data* sd, int index, int amount, int fail);
int clif_openvending(struct map_session_data *sd,int id,struct vending *vending); void clif_openvending(struct map_session_data* sd, int id, struct s_vending* vending);
int clif_vendingreport(struct map_session_data *sd,int index,int amount); void clif_vendingreport(struct map_session_data* sd, int index, int amount);
int clif_movetoattack(struct map_session_data *sd,struct block_list *bl); int clif_movetoattack(struct map_session_data *sd,struct block_list *bl);

View File

@ -397,7 +397,7 @@ struct status_change {
unsigned int option;// effect state unsigned int option;// effect state
}; };
struct vending { struct s_vending {
short index; short index;
unsigned short amount; unsigned short amount;
unsigned int value; unsigned int value;
@ -771,7 +771,7 @@ struct map_session_data {
int vender_id; int vender_id;
int vend_num; int vend_num;
char message[MESSAGE_SIZE]; char message[MESSAGE_SIZE];
struct vending vending[MAX_VENDING]; struct s_vending vending[MAX_VENDING];
struct pet_data *pd; struct pet_data *pd;
struct homun_data *hd; // [blackhole89] struct homun_data *hd; // [blackhole89]

View File

@ -70,33 +70,32 @@ static const char hate_var[3][NAME_LENGTH] = {"PC_HATE_MOB_SUN","PC_HATE_MOB_MOO
int pc_isGM(struct map_session_data* sd) int pc_isGM(struct map_session_data* sd)
{ {
int i; int i;
nullpo_retr(0, sd); nullpo_retr(0, sd);
if( sd->bl.type != BL_PC ) if( sd->bl.type != BL_PC )
return 0; return 0;
for(i = 0; i < GM_num; i++) ARR_FIND( 0, GM_num, i, gm_account[i].account_id == sd->status.account_id );
if (gm_account[i].account_id == sd->status.account_id) return ( i < GM_num ) ? gm_account[i].level : 0;
return gm_account[i].level;
return 0;
} }
int pc_set_gm_level(int account_id, int level) int pc_set_gm_level(int account_id, int level)
{ {
int i; int i;
for (i = 0; i < GM_num; i++) {
if (account_id == gm_account[i].account_id) { ARR_FIND( 0, GM_num, i, account_id == gm_account[i].account_id );
if( i < GM_num )
{
gm_account[i].level = level; gm_account[i].level = level;
return 0;
} }
else
{
gm_account = (struct gm_account *) aRealloc(gm_account, (GM_num + 1) * sizeof(struct gm_account));
gm_account[GM_num].account_id = account_id;
gm_account[GM_num].level = level;
GM_num++;
} }
GM_num++;
gm_account = (struct gm_account *) aRealloc(gm_account, sizeof(struct gm_account) * GM_num);
gm_account[GM_num - 1].account_id = account_id;
gm_account[GM_num - 1].level = level;
return 0; return 0;
} }
@ -2736,17 +2735,19 @@ int pc_getzeny(struct map_session_data *sd,int zeny)
if( zeny < 0 ) if( zeny < 0 )
return pc_payzeny(sd, -zeny); return pc_payzeny(sd, -zeny);
if (sd->status.zeny > MAX_ZENY -zeny) if( zeny > MAX_ZENY - sd->status.zeny )
return 1; //Overflow zeny = MAX_ZENY - sd->status.zeny;
sd->status.zeny += zeny; sd->status.zeny += zeny;
clif_updatestatus(sd,SP_ZENY); clif_updatestatus(sd,SP_ZENY);
if(zeny > 0 && sd->state.showzeny){ if( zeny > 0 && sd->state.showzeny )
{
char output[255]; char output[255];
sprintf(output, "Gained %dz.", zeny); sprintf(output, "Gained %dz.", zeny);
clif_disp_onlyself(sd,output,strlen(output)); clif_disp_onlyself(sd,output,strlen(output));
} }
return 0; return 0;
} }
@ -3224,12 +3225,14 @@ int pc_cartitem_amount(struct map_session_data *sd,int idx,int amount)
struct item* item_data; struct item* item_data;
nullpo_retr(-1, sd); nullpo_retr(-1, sd);
nullpo_retr(-1, item_data=&sd->status.cart[idx]);
if( item_data->nameid==0 || !item_data->amount) item_data = &sd->status.cart[idx];
if( item_data->nameid == 0 || item_data->amount == 0 )
return -1; return -1;
return item_data->amount - amount; return item_data->amount - amount;
} }
/*========================================== /*==========================================
* <EFBFBD>J?<EFBFBD>g©ç<EFBFBD>A<EFBFBD>C<EFBFBD>e<EFBFBD><EFBFBD>Ú® * <EFBFBD>J?<EFBFBD>g©ç<EFBFBD>A<EFBFBD>C<EFBFBD>e<EFBFBD><EFBFBD>Ú®
*------------------------------------------*/ *------------------------------------------*/

View File

@ -310,19 +310,21 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd)
} }
/*========================================== /*==========================================
* Adds an item/qty to the trade window [rewrite by Skotlex] * Adds an item/qty to the trade window
*------------------------------------------*/ *------------------------------------------*/
void trade_tradeadditem(struct map_session_data *sd, int index, int amount) void trade_tradeadditem(struct map_session_data *sd, int index, int amount)
{ {
struct map_session_data *target_sd; struct map_session_data *target_sd;
struct item *item; struct item *item;
int trade_i, trade_weight; int trade_i, trade_weight;
int src_lv, dst_lv;
nullpo_retv(sd); nullpo_retv(sd);
if( !sd->state.trading || sd->state.deal_locked > 0 ) if( !sd->state.trading || sd->state.deal_locked > 0 )
return; //Can't add stuff. return; //Can't add stuff.
if ((target_sd = map_id2sd(sd->trade_partner)) == NULL) { if( (target_sd = map_id2sd(sd->trade_partner)) == NULL )
{
trade_tradecancel(sd); trade_tradecancel(sd);
return; return;
} }
@ -333,19 +335,8 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount)
return; return;
} }
if (index == 0) index -= 2; // 0 is for zeny, 1 is unknown. Gravity, go figure...
{ //Adding Zeny
if (amount >= 0 && amount <= sd->status.zeny && // check amount
(amount <= MAX_ZENY - target_sd->status.zeny)) // fix positiv overflow
{ //Check Ok
sd->deal.zeny = amount;
clif_tradeadditem(sd, target_sd, 0, amount);
} else //Send overweight when trying to add too much zeny? Hope they get the idea...
clif_tradeitemok(sd, 0, 1);
return;
}
index = index -2; //Why the actual index used is -2?
//Item checks... //Item checks...
if( index < 0 || index >= MAX_INVENTORY ) if( index < 0 || index >= MAX_INVENTORY )
return; return;
@ -353,24 +344,19 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount)
return; return;
item = &sd->status.inventory[index]; item = &sd->status.inventory[index];
trade_i = pc_isGM(sd); //Recycling the variables to check for trad restrict. src_lv = pc_isGM(sd);
trade_weight = pc_isGM(target_sd); dst_lv = pc_isGM(target_sd);
if (!itemdb_cantrade(item, trade_i, trade_weight) && //Can't trade if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade
(pc_get_partner(sd) != target_sd || (pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade
!itemdb_canpartnertrade(item, trade_i, trade_weight))) //Can't partner-trade
{ {
clif_displaymessage (sd->fd, msg_txt(260)); clif_displaymessage (sd->fd, msg_txt(260));
clif_tradeitemok(sd, index+2, 1); clif_tradeitemok(sd, index+2, 1);
return; return;
} }
for(trade_i = 0; trade_i < 10; trade_i++) //Locate a trade position
{ //Locate a trade position ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
if (sd->deal.item[trade_i].index == index || if( trade_i == 10 ) //No space left
sd->deal.item[trade_i].amount == 0)
break;
}
if (trade_i >= 10) //No space left
{ {
clif_tradeitemok(sd, index+2, 1); clif_tradeitemok(sd, index+2, 1);
return; return;
@ -391,14 +377,43 @@ void trade_tradeadditem(struct map_session_data *sd, int index, int amount)
trade_weight = sd->inventory_data[index]->weight * amount; trade_weight = sd->inventory_data[index]->weight * amount;
} }
sd->deal.item[trade_i].amount += amount; sd->deal.item[trade_i].amount += amount;
} else { //New deal item }
else
{ //New deal item
sd->deal.item[trade_i].index = index; sd->deal.item[trade_i].index = index;
sd->deal.item[trade_i].amount = amount; sd->deal.item[trade_i].amount = amount;
} }
sd->deal.weight += trade_weight; sd->deal.weight += trade_weight;
clif_tradeitemok(sd, index+2, 0); // Return the index as it was received clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
clif_tradeadditem(sd, target_sd, index+2, amount); //index fix clif_tradeadditem(sd, target_sd, index+2, amount);
}
/*==========================================
* Adds the specified amount of zeny to the trade window
*------------------------------------------*/
void trade_tradeaddzeny(struct map_session_data* sd, int amount)
{
struct map_session_data* target_sd;
nullpo_retv(sd);
if( !sd->state.trading || sd->state.deal_locked > 0 )
return; //Can't add stuff.
if( (target_sd = map_id2sd(sd->trade_partner)) == NULL )
{
trade_tradecancel(sd);
return;
}
if( amount < 0 || amount > sd->status.zeny || amount > MAX_ZENY - target_sd->status.zeny )
{ // invalid values, no appropriate packet for it => abort
trade_tradecancel(sd);
return;
}
sd->deal.zeny = amount;
clif_tradeadditem(sd, target_sd, 0, amount);
} }
/*========================================== /*==========================================
@ -511,36 +526,41 @@ void trade_tradecommit(struct map_session_data *sd)
} }
// trade is accepted and correct. // trade is accepted and correct.
for(trade_i = 0; trade_i < 10; trade_i++) { for( trade_i = 0; trade_i < 10; trade_i++ )
{
int n; int n;
if (sd->deal.item[trade_i].amount) { if (sd->deal.item[trade_i].amount)
{
n = sd->deal.item[trade_i].index; n = sd->deal.item[trade_i].index;
flag = pc_additem(tsd, &sd->status.inventory[n], sd->deal.item[trade_i].amount); flag = pc_additem(tsd, &sd->status.inventory[n], sd->deal.item[trade_i].amount);
if (flag == 0) { if (flag == 0)
{
//Logs (T)rade [Lupus] //Logs (T)rade [Lupus]
if(log_config.enable_logs&0x2) { if(log_config.enable_logs&0x2)
{
log_pick_pc(sd, "T", sd->status.inventory[n].nameid, -(sd->deal.item[trade_i].amount), &sd->status.inventory[n]); log_pick_pc(sd, "T", sd->status.inventory[n].nameid, -(sd->deal.item[trade_i].amount), &sd->status.inventory[n]);
log_pick_pc(tsd, "T", sd->status.inventory[n].nameid, sd->deal.item[trade_i].amount, &sd->status.inventory[n]); log_pick_pc(tsd, "T", sd->status.inventory[n].nameid, sd->deal.item[trade_i].amount, &sd->status.inventory[n]);
} }
//Logs
pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1); pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1);
} else } else
clif_additem(sd, n, sd->deal.item[trade_i].amount, 0); clif_additem(sd, n, sd->deal.item[trade_i].amount, 0);
sd->deal.item[trade_i].index = 0; sd->deal.item[trade_i].index = 0;
sd->deal.item[trade_i].amount = 0; sd->deal.item[trade_i].amount = 0;
} }
if (tsd->deal.item[trade_i].amount) { if (tsd->deal.item[trade_i].amount)
{
n = tsd->deal.item[trade_i].index; n = tsd->deal.item[trade_i].index;
flag = pc_additem(sd, &tsd->status.inventory[n], tsd->deal.item[trade_i].amount); flag = pc_additem(sd, &tsd->status.inventory[n], tsd->deal.item[trade_i].amount);
if (flag == 0) { if (flag == 0)
{
//Logs (T)rade [Lupus] //Logs (T)rade [Lupus]
if(log_config.enable_logs&0x2) { if(log_config.enable_logs&0x2)
{
log_pick_pc(tsd, "T", tsd->status.inventory[n].nameid, -(tsd->deal.item[trade_i].amount), &tsd->status.inventory[n]); log_pick_pc(tsd, "T", tsd->status.inventory[n].nameid, -(tsd->deal.item[trade_i].amount), &tsd->status.inventory[n]);
log_pick_pc(sd, "T", tsd->status.inventory[n].nameid, tsd->deal.item[trade_i].amount, &tsd->status.inventory[n]); log_pick_pc(sd, "T", tsd->status.inventory[n].nameid, tsd->deal.item[trade_i].amount, &tsd->status.inventory[n]);
} }
//Logs
pc_delitem(tsd, n, tsd->deal.item[trade_i].amount, 1); pc_delitem(tsd, n, tsd->deal.item[trade_i].amount, 1);
} else } else
clif_additem(tsd, n, tsd->deal.item[trade_i].amount, 0); clif_additem(tsd, n, tsd->deal.item[trade_i].amount, 0);
@ -548,21 +568,21 @@ void trade_tradecommit(struct map_session_data *sd)
tsd->deal.item[trade_i].amount = 0; tsd->deal.item[trade_i].amount = 0;
} }
} }
if (sd->deal.zeny || tsd->deal.zeny) {
if (sd->deal.zeny) { if( sd->deal.zeny || tsd->deal.zeny )
sd->status.zeny -= sd->deal.zeny; {
tsd->status.zeny += sd->deal.zeny; sd->status.zeny += tsd->deal.zeny - sd->deal.zeny;
if (log_config.zeny) tsd->status.zeny += sd->deal.zeny - tsd->deal.zeny;
log_zeny(tsd, "T", sd, sd->deal.zeny);//Logs Zeny (T)rade [Lupus]
//Logs Zeny (T)rade [Lupus]
if( sd->deal.zeny && log_config.zeny )
log_zeny(tsd, "T", sd, sd->deal.zeny);
if( tsd->deal.zeny && log_config.zeny )
log_zeny(sd, "T", tsd, tsd->deal.zeny);
sd->deal.zeny = 0; sd->deal.zeny = 0;
}
if (tsd->deal.zeny) {
tsd->status.zeny -= tsd->deal.zeny;
sd->status.zeny += tsd->deal.zeny;
if (log_config.zeny)
log_zeny(sd, "T", tsd, tsd->deal.zeny);//Logs Zeny (T)rade [Lupus]
tsd->deal.zeny = 0; tsd->deal.zeny = 0;
}
clif_updatestatus(sd, SP_ZENY); clif_updatestatus(sd, SP_ZENY);
clif_updatestatus(tsd, SP_ZENY); clif_updatestatus(tsd, SP_ZENY);
} }
@ -577,6 +597,7 @@ void trade_tradecommit(struct map_session_data *sd)
clif_tradecompleted(sd, 0); clif_tradecompleted(sd, 0);
clif_tradecompleted(tsd, 0); clif_tradecompleted(tsd, 0);
// save both player to avoid crash: they always have no advantage/disadvantage between the 2 players // save both player to avoid crash: they always have no advantage/disadvantage between the 2 players
if (save_settings&1) if (save_settings&1)
{ {

View File

@ -10,6 +10,7 @@ struct map_session_data;
void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd); void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd);
void trade_tradeack(struct map_session_data *sd,int type); void trade_tradeack(struct map_session_data *sd,int type);
void trade_tradeadditem(struct map_session_data *sd,int index,int amount); void trade_tradeadditem(struct map_session_data *sd,int index,int amount);
void trade_tradeaddzeny(struct map_session_data *sd,int amount);
void trade_tradeok(struct map_session_data *sd); void trade_tradeok(struct map_session_data *sd);
void trade_tradecancel(struct map_session_data *sd); void trade_tradecancel(struct map_session_data *sd);
void trade_tradecommit(struct map_session_data *sd); void trade_tradecommit(struct map_session_data *sd);

View File

@ -2,6 +2,8 @@
// For more information, see LICENCE in the main folder // For more information, see LICENCE in the main folder
#include "../common/nullpo.h" #include "../common/nullpo.h"
#include "../common/strlib.h"
#include "../common/utils.h"
#include "clif.h" #include "clif.h"
#include "itemdb.h" #include "itemdb.h"
#include "atcommand.h" #include "atcommand.h"
@ -20,7 +22,7 @@
/*========================================== /*==========================================
* * Close shop
*------------------------------------------*/ *------------------------------------------*/
void vending_closevending(struct map_session_data* sd) void vending_closevending(struct map_session_data* sd)
{ {
@ -28,12 +30,13 @@ void vending_closevending(struct map_session_data *sd)
sd->vender_id = 0; sd->vender_id = 0;
clif_closevendingboard(&sd->bl,0); clif_closevendingboard(&sd->bl,0);
if( use_irc && irc_announce_shop_flag ) if( use_irc && irc_announce_shop_flag )
irc_announce_shop(sd,0); irc_announce_shop(sd,0);
} }
/*========================================== /*==========================================
* * Request a shop's item list
*------------------------------------------*/ *------------------------------------------*/
void vending_vendinglistreq(struct map_session_data* sd, int id) void vending_vendinglistreq(struct map_session_data* sd, int id)
{ {
@ -44,55 +47,45 @@ void vending_vendinglistreq(struct map_session_data *sd,int id)
if( (vsd = map_id2sd(id)) == NULL ) if( (vsd = map_id2sd(id)) == NULL )
return; return;
if( vsd->vender_id == 0 ) if( vsd->vender_id == 0 )
return; return; // not vending
clif_vendinglist(sd, id, vsd->vending); clif_vendinglist(sd, id, vsd->vending);
} }
/*========================================== /*==========================================
* * Purchase item(s) from a shop
*------------------------------------------*/ *------------------------------------------*/
void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p) void vending_purchasereq(struct map_session_data* sd, int id, const uint8* data, int count)
{ {
int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING]; int i, j, w, new_ = 0, blank, vend_list[MAX_VENDING];
double z; double z;
unsigned short amount; unsigned short amount;
short idx; short idx;
struct s_vending vending[MAX_VENDING]; // against duplicate packets
struct map_session_data* vsd = map_id2sd(id); struct map_session_data* vsd = map_id2sd(id);
struct vending vending[MAX_VENDING]; // against duplicate packets
nullpo_retv(sd); nullpo_retv(sd);
if (vsd == NULL) if( vsd == NULL || vsd->vender_id == 0 || vsd->vender_id == sd->bl.id )
return; return; // invalid shop
if (vsd->vender_id == 0) if( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) )
return; return; // shop too far away
if (vsd->vender_id == sd->bl.id) if( count < 1 || count > MAX_VENDING || count > vsd->vend_num )
return; return; // invalid amount of purchased items
if (sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE)
) {
clif_buyvending(sd, 0, 32767, 4); // too far [Lupus]
//probably... we should add either a hack log / or a proper message. But normal player won't see ie anyway
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 blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory
// duplicate item in vending to check hacker with multiple packets // duplicate item in vending to check hacker with multiple packets
memcpy(&vending, &vsd->vending, sizeof(struct vending) * MAX_VENDING); // copy vending list memcpy(&vending, &vsd->vending, sizeof(vsd->vending)); // copy vending list
// some checks // some checks
z = 0.; z = 0.; // zeny counter
w = 0; w = 0; // weight counter
for(i = 0; 8 + 4 * i < len; i++) { for( i = 0; i < count; i++ )
amount = *(unsigned short*)(p + 4 * i); {
idx = *(short*)(p + 2 + 4 * i) - 2; amount = *(uint16*)(data + 4*i + 0);
idx = *(uint16*)(data + 4*i + 2);
idx -= 2;
if( amount <= 0 ) if( amount <= 0 )
return; return;
@ -101,40 +94,38 @@ void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned cha
if( idx < 0 || idx >= MAX_CART ) if( idx < 0 || idx >= MAX_CART )
return; return;
for(j = 0; j < vsd->vend_num; j++) { ARR_FIND( 0, vsd->vend_num, j, vsd->vending[j].index == idx );
if (vsd->vending[j].index == idx) {
vend_list[i] = j;
break;
}
}
if( j == vsd->vend_num ) if( j == vsd->vend_num )
return; //picked non-existing item return; //picked non-existing item
else
vend_list[i] = j;
z += ((double)vsd->vending[j].value * (double)amount); z += ((double)vsd->vending[j].value * (double)amount);
if (z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY) { // fix positiv overflow (buyer) if( z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY )
{
clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny clif_buyvending(sd, idx, amount, 1); // you don't have enough zeny
return; // zeny s'< return;
}
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; w += itemdb_weight(vsd->status.cart[idx].nameid) * amount;
if (w + sd->weight > sd->max_weight) { if( w + sd->weight > sd->max_weight )
{
clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight
return; return;
} }
if (vending[j].amount > vsd->status.cart[idx].amount) //Check to see if cart/vend info is in sync. //Check to see if cart/vend info is in sync.
if( vending[j].amount > vsd->status.cart[idx].amount )
vending[j].amount = vsd->status.cart[idx].amount; 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). // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
// here, we check cumulativ amounts // here, we check cumulative amounts
if (vending[j].amount < amount) { if( vending[j].amount < amount )
{
// send more quantity is not a hack (an other player can have buy items just before) // 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 clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity
return; return;
} else }
vending[j].amount -= amount; vending[j].amount -= amount;
switch( pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount) ) { switch( pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount) ) {
@ -153,24 +144,23 @@ void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned cha
//Logs (V)ending Zeny [Lupus] //Logs (V)ending Zeny [Lupus]
if( log_config.zeny > 0 ) if( log_config.zeny > 0 )
log_zeny(vsd, "V", sd, (int)z); log_zeny(vsd, "V", sd, (int)z);
//Logs
pc_payzeny(sd, (int)z); pc_payzeny(sd, (int)z);
if( battle_config.vending_tax ) if( battle_config.vending_tax )
z = z*(1 - battle_config.vending_tax/10000); z -= z * (battle_config.vending_tax/10000.);
pc_getzeny(vsd, (int)z); pc_getzeny(vsd, (int)z);
for(i = 0; 8 + 4 * i < len; i++) { for( i = 0; i < count; i++ )
amount = *(short*)(p + 4 *i); {
idx = *(short*)(p + 2 + 4 * i) - 2; amount = *(uint16*)(data + 4*i + 0);
//if (amount < 0) break; // tested at start of the function idx = *(uint16*)(data + 4*i + 2);
idx -= 2;
//Logs sold (V)ending items [Lupus] //Logs sold (V)ending items [Lupus]
if(log_config.enable_logs&0x4) { 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(vsd, "V", vsd->status.cart[idx].nameid, -amount, &vsd->status.cart[idx]);
log_pick_pc( sd, "V", vsd->status.cart[idx].nameid, amount, (struct item*)&vsd->status.cart[idx]); log_pick_pc( sd, "V", vsd->status.cart[idx].nameid, amount, &vsd->status.cart[idx]);
} }
//Logs
// vending item // vending item
pc_additem(sd, &vsd->status.cart[idx], amount); pc_additem(sd, &vsd->status.cart[idx], amount);
@ -179,7 +169,8 @@ void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned cha
clif_vendingreport(vsd, idx, amount); clif_vendingreport(vsd, idx, amount);
//print buyer's name //print buyer's name
if(battle_config.buyer_name) { if( battle_config.buyer_name )
{
char temp[256]; char temp[256];
sprintf(temp, msg_txt(265), sd->status.name); sprintf(temp, msg_txt(265), sd->status.name);
clif_disp_onlyself(vsd,temp,strlen(temp)); clif_disp_onlyself(vsd,temp,strlen(temp));
@ -187,17 +178,20 @@ void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned cha
} }
//Always save BOTH: buyer and customer //Always save BOTH: buyer and customer
if (save_settings&2) { if( save_settings&2 )
{
chrif_save(sd,0); chrif_save(sd,0);
chrif_save(vsd,0); chrif_save(vsd,0);
} }
//check for @AUTOTRADE users [durf] //check for @AUTOTRADE users [durf]
if( vsd->state.autotrade ) if( vsd->state.autotrade )
{ {
//Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex] //see if there is anything left in the shop
for(i = 0; i < vsd->vend_num && vsd->vending[i].amount < 1; i++); ARR_FIND( 0, vsd->vend_num, i, vsd->vending[i].amount > 0 );
if( i == vsd->vend_num ) if( i == vsd->vend_num )
{ {
//Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
vending_closevending(vsd); vending_closevending(vsd);
map_quit(vsd); //They have no reason to stay around anymore, do they? map_quit(vsd); //They have no reason to stay around anymore, do they?
} }
@ -205,69 +199,78 @@ void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned cha
} }
/*========================================== /*==========================================
* * Open shop
* data := {<index>.w <amount>.w <value>.l}[count]
*------------------------------------------*/ *------------------------------------------*/
void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p) void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count)
{ {
int i, j; int i, j;
int vending_skill_lvl; int vending_skill_lvl;
nullpo_retv(sd); nullpo_retv(sd);
if (map[sd->bl.m].flag.novending) { if( !flag ) // cancelled
clif_displaymessage (sd->fd, msg_txt(276)); return; // nothing to do
return; //Can't vend in novending mapflag maps.
}
//check shopname len if (pc_istrading(sd))
if(message[0] == '\0') return; // can't have 2 shops at once
return;
vending_skill_lvl = pc_checkskill(sd, MC_VENDING); vending_skill_lvl = pc_checkskill(sd, MC_VENDING);
if(!vending_skill_lvl || !pc_iscarton(sd)) { // cart skill and cart check [Valaris] // skill level and cart check
if( !vending_skill_lvl || !pc_iscarton(sd) )
{
clif_skill_fail(sd, MC_VENDING, 0, 0); clif_skill_fail(sd, MC_VENDING, 0, 0);
return; return;
} }
if (flag) {
// check number of items in shop // check number of items in shop
if (len < 85 + 8 || len > 85 + 8 * MAX_VENDING || len > 85 + 8 * (2 + vending_skill_lvl)) { if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl )
{ // invalid item count
clif_skill_fail(sd, MC_VENDING, 0, 0); clif_skill_fail(sd, MC_VENDING, 0, 0);
return; return;
} }
for(i = 0, j = 0; (85 + 8 * j < len) && (i < MAX_VENDING); i++, j++) {
sd->vending[i].index = *(short*)(p+8*j)-2; // filter out invalid items
if (sd->vending[i].index < 0 || sd->vending[i].index >= MAX_CART || i = 0;
!itemdb_cantrade(&sd->status.cart[sd->vending[i].index], pc_isGM(sd), pc_isGM(sd))) for( j = 0; j < count; j++ )
{ {
i--; //Preserve the vending index, skip to the next item. int index = *(uint16*)(data + 8*j + 0);
unsigned int amount = *(uint16*)(data + 8*j + 2);
unsigned int value = *(uint32*)(data + 8*j + 4);
index -= 2; // offset adjustment (client says that the first cart position is 2)
if( index < 0 || index >= MAX_CART // invalid position
|| pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity
//NOTE: official server does not do any of the following checks!
|| !sd->status.cart[index].identify // unidentified item
|| sd->status.cart[index].attribute == 1 // broken item
|| !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item
continue; continue;
sd->vending[i].index = index;
sd->vending[i].amount = amount;
sd->vending[i].value = cap_value(value, 1, (unsigned int)battle_config.vending_max_value);
i++; // item successfully added
} }
sd->vending[i].amount = *(short*)(p+2+8*j);
sd->vending[i].value = *(int*)(p+4+8*j); if( i != j )
if(sd->vending[i].value > (unsigned int)battle_config.vending_max_value) clif_displaymessage (sd->fd, msg_txt(266)); //"Some of your items cannot be vended and were removed from the shop."
sd->vending[i].value = (unsigned int)battle_config.vending_max_value;
else if(sd->vending[i].value < 1) if( i == 0 )
sd->vending[i].value = 1000000; // auto set to 1 million [celest] { // no valid item found
// カート内のアイテム数と販売するアイテム数に相違があったら中止 clif_skill_fail(sd, MC_VENDING, 0, 0); // custom reply packet
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; return;
} }
}
if (i != j)
{ //Some items were not vended. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(266));
}
sd->vender_id = sd->bl.id; sd->vender_id = sd->bl.id;
sd->vend_num = i; sd->vend_num = i;
memcpy(sd->message,message, MESSAGE_SIZE); safestrncpy(sd->message, message, MESSAGE_SIZE);
sd->message[MESSAGE_SIZE-1] = '\0';
if (clif_openvending(sd,sd->vender_id,sd->vending) > 0){
pc_stop_walking(sd,1); pc_stop_walking(sd,1);
clif_openvending(sd,sd->vender_id,sd->vending);
clif_showvendingboard(&sd->bl,message,0); clif_showvendingboard(&sd->bl,message,0);
if( use_irc && irc_announce_shop_flag ) if( use_irc && irc_announce_shop_flag )
irc_announce_shop(sd,1); irc_announce_shop(sd,1);
} else
sd->vender_id = 0;
}
} }

View File

@ -4,12 +4,13 @@
#ifndef _VENDING_H_ #ifndef _VENDING_H_
#define _VENDING_H_ #define _VENDING_H_
#include "../common/cbasetypes.h"
//#include "map.h" //#include "map.h"
struct map_session_data; struct map_session_data;
void vending_closevending(struct map_session_data* sd); void vending_closevending(struct map_session_data* sd);
void vending_openvending(struct map_session_data *sd,int len,char *message,int flag,unsigned char *p); void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count);
void vending_vendinglistreq(struct map_session_data* sd, int id); void vending_vendinglistreq(struct map_session_data* sd, int id);
void vending_purchasereq(struct map_session_data *sd,int len,int id,unsigned char *p); void vending_purchasereq(struct map_session_data* sd, int id, const uint8* data, int count);
#endif /* _VENDING_H_ */ #endif /* _VENDING_H_ */