Index: src/map/clif.c =================================================================== --- src/map/clif.c (revision 14901) +++ src/map/clif.c (working copy) @@ -158,6 +158,79 @@ } /*========================================== + * Custom vending list (script based) + *------------------------------------------*/ +int clif_vending_script(struct map_session_data* sd, struct npc_data* nd) +{ + int i, j, fd, len; +#if PACKETVER < 20100105 + const int cmd = 0x133; + const int offset = 8; +#else + const int cmd = 0x800; + const int offset = 12; +#endif + + nullpo_retr(0, sd); + nullpo_retr(0, nd); + + ARR_FIND( 0, MAX_VENDING, i, nd->vending[i].nameid > 0 ); + + if( i == MAX_VENDING ) + return 0; + + fd = sd->fd; + len = offset; + + WFIFOHEAD(fd, offset+MAX_VENDING*22); + WFIFOW(fd,0) = cmd; + WFIFOL(fd,4) = sd->bl.id; +#if PACKETVER >= 20100105 + WFIFOL(fd,8) = nd->bl.id; +#endif + + for( i = 0; MAX_VENDING > i; i++ ) + { + int k; + struct item_data* data; + struct npc_item_vend* v; + + if( nd->vending[i].nameid == 0 ) + continue; + + v = &nd->vending[i]; + + data = itemdb_search(v->nameid); + + WFIFOL(fd,offset+ 0+i*22) = v->value; + WFIFOW(fd,offset+ 4+i*22) = 1; + WFIFOW(fd,offset+ 6+i*22) = i + 2; + WFIFOB(fd,offset+ 8+i*22) = itemtype(data->type); + WFIFOW(fd,offset+ 9+i*22) = ( data->view_id > 0 ) ? data->view_id : data->nameid; + WFIFOB(fd,offset+11+i*22) = 1; + WFIFOB(fd,offset+12+i*22) = v->attribute; + WFIFOB(fd,offset+13+i*22) = v->refine; + + for( j = 0; MAX_SLOTS > j; j++ ) + { + if( v->card[j] > 0 && ( k = itemdb_viewid(v->card[j]) ) > 0 ) + WFIFOW(fd,offset+14+(j*2)+i*22) = k; + else + WFIFOW(fd,offset+14+(j*2)+i*22) = v->card[j]; + } + + len += 22; + } + + WFIFOW(fd,2) = len; + WFIFOSET(fd,WFIFOW(fd,2)); + + sd->state.npc_vending = nd->bl.id; + + return 0; +} + +/*========================================== * mapŽI‚Ìport“ǂݏo‚µ *------------------------------------------*/ uint16 clif_getport(void) Index: src/map/clif.h =================================================================== --- src/map/clif.h (revision 14901) +++ src/map/clif.h (working copy) @@ -218,6 +218,8 @@ uint32 clif_refresh_ip(void); uint16 clif_getport(void); +int clif_vending_script(struct map_session_data* sd, struct npc_data* nd); + int clif_authok(struct map_session_data *); int clif_authfail_fd(int fd,int type); int clif_charselectok(int id, uint8 ok); Index: src/map/npc.h =================================================================== --- src/map/npc.h (revision 14901) +++ src/map/npc.h (working copy) @@ -22,6 +22,13 @@ struct npc_item_list { unsigned int nameid,value; }; +struct npc_item_vend { + short nameid; + char refine; + char attribute; + short card[MAX_SLOTS]; + unsigned int value; +}; struct npc_data { struct block_list bl; @@ -36,6 +43,7 @@ int chat_id; int touching_id; unsigned int next_walktime; + struct npc_item_vend vending[MAX_VENDING]; unsigned size : 2; Index: src/map/pc.h =================================================================== --- src/map/pc.h (revision 14901) +++ src/map/pc.h (working copy) @@ -134,6 +134,7 @@ unsigned int vending : 1; unsigned int noks : 3; // [Zeph Kill Steal Protection] unsigned int changemap : 1; + unsigned int npc_vending; // Player has a vending open from a script short pmap; // Previous map on Map Change unsigned short autoloot; unsigned short autolootid; // [Zephyrus] Index: src/map/script.c =================================================================== --- src/map/script.c (revision 14901) +++ src/map/script.c (working copy) @@ -3837,6 +3837,137 @@ // NPC interaction // +/*==================================================* + * vending_add , {, {, {, , , , {, ""}}}}; + *--------------------------------------------------*/ +BUILDIN_FUNC(vending_add) +{ + int i; + struct npc_data* nd; + struct npc_item_vend* vend; + + nd = script_hasdata(st, 10) ? npc_name2id(script_getstr(st, 10)) : map_id2nd(st->oid); + + if( nd == NULL ) + { + ShowWarning("script:vending_add: no script attached\n"); + return 0; + } + + ARR_FIND( 0, MAX_VENDING, i, nd->vending[i].nameid == 0 ); + + if( i == MAX_VENDING ) + { + ShowWarning("script:vending_add: reached maximum vending capacity (%d)\n", MAX_VENDING); + return 0; + } + + vend = &nd->vending[i]; + + if( itemdb_exists(script_getnum(st, 2)) == NULL ) + { + ShowWarning("script:vending_add: unknown item id %d\n", script_getnum(st, 2)); + return 0; + } + + memset( vend, 0, sizeof (struct npc_item_vend) ); + + vend->nameid = script_getnum(st, 2); + vend->value = script_getnum(st, 3); + + FETCH(4, vend->refine); + FETCH(5, vend->attribute); + + for( i = 0; MAX_SLOTS > i; i++ ) + FETCH(6 + i, vend->card[i]); + + script_pushint(st, i + 1); + + return 0; +} + +/*==================================================* + * vending_remove {, ""}; + *--------------------------------------------------*/ +BUILDIN_FUNC(vending_remove) +{ + int i; + struct npc_data* nd; + + nd = script_hasdata(st, 3) ? npc_name2id(script_getstr(st, 3)) : map_id2nd(st->oid); + + if( nd == NULL ) + { + ShowWarning("script:vending_remove: no script attached\n"); + return 0; + } + + i = script_getnum(st, 2); + + if( i > 0 && i <= MAX_VENDING ) + i--; + else + { + ARR_FIND( 0, MAX_VENDING, i, nd->vending[i].nameid == script_getnum(st, 2) ); + + if( i == MAX_VENDING ) + { + ShowWarning("script:vending_remove: couldn't find item %d to remove\n", script_getnum(st, 2)); + return 0; + } + } + + memset( &nd->vending[i], 0, sizeof (struct npc_item_vend) ); + + return 0; +} + +/*==================================================* + * vending_open {""}; + *--------------------------------------------------*/ +BUILDIN_FUNC(vending_open) +{ + struct npc_data* nd; + struct map_session_data* sd = script_rid2sd(st); + + nullpo_retr(0, sd); + + nd = script_hasdata(st, 2) ? npc_name2id(script_getstr(st, 2)) : map_id2nd(st->oid); + + if( nd == NULL ) + { + ShowWarning("script:vending_open: no script attached\n"); + return 0; + } + + clif_vending_script(sd, nd); + + return 0; +} + +/*==================================================* + * vending_reset {""}; + *--------------------------------------------------*/ +BUILDIN_FUNC(vending_reset) +{ + struct npc_data* nd; + struct map_session_data* sd = script_rid2sd(st); + + nullpo_retr(0, sd); + + nd = script_hasdata(st, 2) ? npc_name2id(script_getstr(st, 2)) : map_id2nd(st->oid); + + if( nd == NULL ) + { + ShowWarning("script:vending_reset: no script attached\n"); + return 0; + } + + memset( nd->vending, 0, sizeof (nd->vending) ); + + return 0; +} + /// Appends a message to the npc dialog. /// If a dialog doesn't exist yet, one is created. /// @@ -15329,5 +15460,11 @@ BUILDIN_DEF(checkquest, "i?"), BUILDIN_DEF(changequest, "ii"), BUILDIN_DEF(showevent, "ii"), + + BUILDIN_DEF(vending_add, "ii*"), + BUILDIN_DEF(vending_remove, "i*"), + BUILDIN_DEF(vending_open, "*"), + BUILDIN_DEF(vending_reset, "*"), + {NULL,NULL,NULL}, }; Index: src/map/vending.c =================================================================== --- src/map/vending.c (revision 14901) +++ src/map/vending.c (working copy) @@ -15,6 +15,7 @@ #include "skill.h" #include "battle.h" #include "log.h" +#include "npc.h" #include #include @@ -66,6 +67,108 @@ } /*========================================== + * Purchase item(s) from a script + *------------------------------------------*/ +void vending_purchasereq_script(struct map_session_data* sd, struct npc_data* nd, int uid, const uint8* data, int count) +{ + int i; + int add; + int blank; + int weight; + double zeny; + + nullpo_retv(sd); + nullpo_retv(nd); + + if( sd->state.npc_vending != nd->bl.id || uid != nd->bl.id ) + { + clif_buyvending(sd, 0, 0, 6); + return; + } + + if( count < 1 || count > MAX_VENDING ) + return; + + blank = pc_inventoryblank(sd); + + add = 0; + zeny = 0; + weight = 0; + + for( i = 0; count > i; i++ ) + { + short amount = *(uint16*)(data + 4*i + 0); + short index = *(uint16*)(data + 4*i + 2); + struct item_data* data; + + if( amount <= 0 ) + continue; + + index -= 2; + + if( index < 0 || index >= MAX_VENDING || nd->vending[index].nameid == 0 ) + continue; + + data = itemdb_exists(nd->vending[index].nameid); + + if( data == NULL ) + continue; + + zeny += (double)( nd->vending[index].value * amount ); + + if( zeny > (double)sd->status.zeny || zeny < 0.0 || zeny > (double)MAX_ZENY ) + { + clif_buyvending(sd, index, amount, 1); + return; + } + + weight += data->weight * amount; + + if( weight + sd->weight > sd->max_weight ) + { + clif_buyvending(sd, index, amount, 2); + return; + } + + switch( pc_checkadditem(sd, nd->vending[index].nameid, amount) ) + { + case ADDITEM_OVERAMOUNT: + return; + case ADDITEM_NEW: + add++; + } + } + + if( add > blank ) + return; + + pc_payzeny(sd, (int)zeny); + + for( i = 0; count > i; i++ ) + { + short amount = *(uint16*)(data + 4*i + 0); + short index = *(uint16*)(data + 4*i + 2); + struct item add_item; + + index -= 2; + + memset( &add_item, 0, sizeof(struct item) ); + + add_item.nameid = nd->vending[index].nameid; + add_item.refine = nd->vending[index].refine; + add_item.identify = 1; + add_item.attribute = nd->vending[index].attribute; + + memcpy( add_item.card, nd->vending[index].card, sizeof(nd->vending[index].card) ); + + pc_additem(sd, &add_item, amount); + } + + if( save_settings&2 ) + chrif_save(sd, 0); +} + +/*========================================== * Purchase item(s) from a shop *------------------------------------------*/ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count) @@ -76,6 +179,18 @@ struct map_session_data* vsd = map_id2sd(aid); nullpo_retv(sd); + + if( sd->state.npc_vending == uid ) + {// a script vend has been requests + struct npc_data* nd = map_id2nd(uid); + + if( nd == NULL ) + return; + + vending_purchasereq_script(sd, nd, uid, data, count); + return; + } + if( vsd == NULL || !vsd->state.vending || vsd->bl.id == sd->bl.id ) return; // invalid shop