From a16fb7c1760039cbea1b7513ce1ba807abbc0b05 Mon Sep 17 00:00:00 2001 From: aleos89 Date: Mon, 29 Feb 2016 20:54:23 -0500 Subject: [PATCH] Updated Item and Point Shop (fixes #843) * Item and Point Shop now works like the NPC Cash Shop. * No longer has issues with player Zeny checks. --- conf/msg_conf/map_msg.conf | 2 +- src/map/clif.c | 24 +++-- src/map/npc.c | 184 ++++++++++++++++++++++--------------- src/map/npc.h | 2 + 4 files changed, 130 insertions(+), 82 deletions(-) diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index b395cf6f3c..a778f7f16e 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -740,7 +740,7 @@ 713: You do not have enough '%s'. 714: Item Shop List: %s (%hu) 715: Point Shop List: '%s' -716: Your '%s' now: %d +716: Your '%s' is now: %d //717: Free diff --git a/src/map/clif.c b/src/map/clif.c index d633e7901f..50ee0004e6 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -15615,7 +15615,7 @@ void clif_parse_cashshop_list_request( int fd, struct map_session_data* sd ){ /// 0287 .W .L .L { .L .L .B .W }* (PACKETVER >= 20070711) void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) { - int fd,i; + int fd, i, cost[2] = { 0, 0 }; #if PACKETVER < 20070711 const int offset = 8; #else @@ -15625,14 +15625,16 @@ void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) nullpo_retv(sd); nullpo_retv(nd); + npc_shop_currency_type(sd, nd, cost, true); + fd = sd->fd; sd->npc_shopid = nd->bl.id; WFIFOHEAD(fd,offset+nd->u.shop.count*11); WFIFOW(fd,0) = 0x287; WFIFOW(fd,2) = offset+nd->u.shop.count*11; - WFIFOL(fd,4) = sd->cashPoints; // Cash Points + WFIFOL(fd,4) = cost[0]; #if PACKETVER >= 20070711 - WFIFOL(fd,8) = sd->kafraPoints; // Kafra Points + WFIFOL(fd,8) = cost[1]; #endif for( i = 0; i < nd->u.shop.count; i++ ) { @@ -15661,15 +15663,25 @@ void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) /// 8 = Some items could not be purchased. void clif_cashshop_ack(struct map_session_data* sd, int error) { - int fd = sd->fd; + int fd, cost[2] = { 0, 0 }; + struct npc_data *nd; + + nullpo_retv(sd); + + fd = sd->fd; + nd = map_id2nd(sd->npc_shopid); + + nullpo_retv(nd); + + npc_shop_currency_type(sd, nd, cost, false); WFIFOHEAD(fd, packet_len(0x289)); WFIFOW(fd,0) = 0x289; - WFIFOL(fd,2) = sd->cashPoints; + WFIFOL(fd,2) = cost[0]; #if PACKETVER < 20070711 WFIFOW(fd,6) = TOW(error); #else - WFIFOL(fd,6) = sd->kafraPoints; + WFIFOL(fd,6) = cost[1]; WFIFOW(fd,10) = TOW(error); #endif WFIFOSET(fd, packet_len(0x289)); diff --git a/src/map/npc.c b/src/map/npc.c index 3eeac5fca3..d62b0f9a42 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1237,11 +1237,11 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) switch(nd->subtype) { case NPCTYPE_SHOP: - case NPCTYPE_ITEMSHOP: - case NPCTYPE_POINTSHOP: clif_npcbuysell(sd,nd->bl.id); break; case NPCTYPE_CASHSHOP: + case NPCTYPE_ITEMSHOP: + case NPCTYPE_POINTSHOP: clif_cashshop_show(sd,nd); break; case NPCTYPE_MARKETSHOP: @@ -1333,7 +1333,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type) if ((nd = npc_checknear(sd,map_id2bl(id))) == NULL) return 1; - if (nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP) { + if (nd->subtype != NPCTYPE_SHOP) { ShowError("no such shop npc : %d\n",id); if (sd->npc_id == id) sd->npc_id=0; @@ -1342,21 +1342,6 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type) if (nd->sc.option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?) return 1; - if (nd->subtype == NPCTYPE_ITEMSHOP) { - char output[CHAT_SIZE_MAX]; - struct item_data *itd = itemdb_exists(nd->u.shop.itemshop_nameid); - memset(output,'\0',sizeof(output)); - if (itd) { - sprintf(output,msg_txt(sd,714),itd->jname,itd->nameid); // Item Shop List: %s (%hu) - clif_broadcast(&sd->bl,output,strlen(output) + 1,BC_BLUE,SELF); - } - } else if (nd->subtype == NPCTYPE_POINTSHOP) { - char output[CHAT_SIZE_MAX]; - memset(output,'\0',sizeof(output)); - sprintf(output,msg_txt(sd,715),nd->u.shop.pointshop_str); // Point Shop List: '%s' - clif_broadcast(&sd->bl,output,strlen(output) + 1,BC_BLUE,SELF); - } - sd->npc_shopid = id; if (type == 0) { @@ -1371,13 +1356,12 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type) *------------------------------------------*/ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list) { - int i, j, amount, new_, w, vt; + int i, j, amount, new_, w, vt, cost[2] = { 0, 0 }; unsigned short nameid; struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid); - if( !nd || nd->subtype != NPCTYPE_CASHSHOP ) + if( !nd || ( nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) ) return 1; - if( sd->state.trading ) return 4; @@ -1426,9 +1410,50 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns if( points > vt ) points = vt; // Payment Process ---------------------------------------------------- - if( sd->kafraPoints < points || sd->cashPoints < (vt - points) ) - return 6; - pc_paycash(sd,vt,points, LOG_TYPE_NPC); + npc_shop_currency_type(sd, nd, cost, false); + + switch(nd->subtype) { + case NPCTYPE_CASHSHOP: + if (cost[1] < points || cost[0] < (vt - points)) + return 6; + pc_paycash(sd, vt, points, LOG_TYPE_NPC); + break; + case NPCTYPE_ITEMSHOP: + { + struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid); + + if (cost[0] < (vt - points)) { + char output[CHAT_SIZE_MAX]; + + memset(output, '\0', sizeof(output)); + + sprintf(output, msg_txt(sd, 712), (id) ? id->jname : "NULL", (id) ? id->nameid : 0); // You do not have enough %s (%hu). + clif_colormes(sd->fd, color_table[COLOR_RED], output); + return 8; + } + if (id) + pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), vt - points, 0, 0, LOG_TYPE_NPC); + else + ShowWarning("Failed to delete item %hu from itemshop NPC '%s' (%s, %d, %d)!\n", nd->u.shop.itemshop_nameid, nd->exname, map[nd->bl.m].name, nd->bl.x, nd->bl.y); + } + break; + case NPCTYPE_POINTSHOP: + { + char output[CHAT_SIZE_MAX]; + + memset(output, '\0', sizeof(output)); + + if (cost[0] < (vt - points)) { + sprintf(output, msg_txt(sd, 713), nd->u.shop.pointshop_str); // You do not have enough '%s'. + clif_colormes(sd->fd, color_table[COLOR_RED], output); + return 8; + } + pc_setreg2(sd, nd->u.shop.pointshop_str, cost[0] - (vt - points)); + sprintf(output, msg_txt(sd, 716), nd->u.shop.pointshop_str, cost[0] - (vt - points)); // Your '%s' is now: %d + clif_disp_onlyself(sd, output, strlen(output) + 1); + } + break; + } // Delivery Process ---------------------------------------------------- for( i = 0; i < count; i++ ) { @@ -1454,6 +1479,59 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns return 0; } +/** + * Returns the shop currency type + * @param sd: Player data + * @param nd: NPC data + * @param cost: Reference to cost variable + * @param display: Display cost type to player? + */ +void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, int cost[2], bool display) +{ + switch(nd->subtype) { + case NPCTYPE_CASHSHOP: + cost[0] = sd->cashPoints; + cost[1] = sd->kafraPoints; + break; + case NPCTYPE_ITEMSHOP: + { + int total = 0, i; + struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid); + + if (id) { // Item Data is checked at script parsing but in case of item_db reload, check again. + if (display) { + char output[CHAT_SIZE_MAX]; + + memset(output, '\0', sizeof(output)); + + sprintf(output, msg_txt(sd, 714), id->jname, id->nameid); // Item Shop List: %s (%hu) + clif_broadcast(&sd->bl, output, strlen(output) + 1, BC_BLUE,SELF); + } + + for (i = 0; i < MAX_INVENTORY; i++) { + if (sd->status.inventory[i].nameid == id->nameid) + total += sd->status.inventory[i].amount; + } + } + + cost[0] = total; + } + break; + case NPCTYPE_POINTSHOP: + if (display) { + char output[CHAT_SIZE_MAX]; + + memset(output, '\0', sizeof(output)); + + sprintf(output, msg_txt(sd, 715), nd->u.shop.pointshop_str); // Point Shop List: '%s' + clif_broadcast(&sd->bl, output, strlen(output) + 1, BC_BLUE,SELF); + } + + cost[0] = pc_readreg2(sd, nd->u.shop.pointshop_str); + break; + } +} + /** * npc_buylist for script-controlled shops. * @param sd Player who bought @@ -1583,8 +1661,7 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list * struct npc_data* nd; struct npc_item_list *shop = NULL; double z; - int i,j,k,w,skill,new_,count = 0; - char output[CHAT_SIZE_MAX]; + int i,j,k,w,skill,new_; uint8 market_index[MAX_INVENTORY]; nullpo_retr(3, sd); @@ -1593,7 +1670,7 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list * nd = npc_checknear(sd,map_id2bl(sd->npc_shopid)); if( nd == NULL ) return 3; - if( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP ) + if( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_MARKETSHOP ) return 3; if (!item_list || !n) return 3; @@ -1666,52 +1743,15 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list * if (nd->master_nd) //Script-based shops. return npc_buylist_sub(sd,n,item_list,nd->master_nd); - switch(nd->subtype) { - case NPCTYPE_SHOP: - case NPCTYPE_MARKETSHOP: - if (z > (double)sd->status.zeny) - return 1; // Not enough Zeny - break; - case NPCTYPE_ITEMSHOP: - for (k = 0; k < MAX_INVENTORY; k++) { - if (sd->status.inventory[k].nameid == nd->u.shop.itemshop_nameid) - count += sd->status.inventory[k].amount; - } - if (z > (double)count) { - struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid); - - sprintf(output,msg_txt(sd,712),id->jname,id->nameid); // You do not have enough %s %d. - clif_colormes(sd->fd,color_table[COLOR_RED],output); - return 1; - } - break; - case NPCTYPE_POINTSHOP: - count = pc_readreg2(sd, nd->u.shop.pointshop_str); - if (z > (double)count) { - sprintf(output,msg_txt(sd,713),nd->u.shop.pointshop_str); // You do not have enough '%s'. - clif_colormes(sd->fd,color_table[COLOR_RED],output); - return 1; - } - break; - } + if (z > (double)sd->status.zeny) + return 1; // Not enough Zeny if( w + sd->weight > sd->max_weight ) return 2; // Too heavy if( pc_inventoryblank(sd) < new_ ) return 3; // Not enough space to store items - switch(nd->subtype) { - case NPCTYPE_SHOP: - case NPCTYPE_MARKETSHOP: - pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL); - break; - case NPCTYPE_ITEMSHOP: - pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), (int)z, 0, 0, LOG_TYPE_NPC); - break; - case NPCTYPE_POINTSHOP: - pc_setreg2(sd, nd->u.shop.pointshop_str, count - (int)z); - break; - } + pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL); for( i = 0; i < n; ++i ) { unsigned short nameid = item_list[i].nameid; @@ -1760,11 +1800,6 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list * } } - if (nd->subtype == NPCTYPE_POINTSHOP) { - sprintf(output,msg_txt(sd,716),nd->u.shop.pointshop_str,count - (int)z); // Your '%s' now: %d - clif_disp_onlyself(sd,output,strlen(output)+1); - } - return 0; } @@ -1839,8 +1874,7 @@ uint8 npc_selllist(struct map_session_data* sd, int n, unsigned short *item_list nullpo_retr(1, sd); nullpo_retr(1, item_list); - if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL - || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) ) + if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL || nd->subtype != NPCTYPE_SHOP ) { return 1; } @@ -2579,7 +2613,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const if (type == NPCTYPE_SHOP || type == NPCTYPE_MARKETSHOP) value = id->value_buy; else value = 0; // Cashshop doesn't have a "buy price" in the item_db } - if (value == 0 && (type == NPCTYPE_SHOP || type == NPCTYPE_ITEMSHOP || type == NPCTYPE_POINTSHOP || type == NPCTYPE_MARKETSHOP)) { // NPC selling items for free! + if (value == 0 && (type == NPCTYPE_SHOP || type == NPCTYPE_MARKETSHOP)) { // NPC selling items for free! ShowWarning("npc_parse_shop: Item %s [%hu] is being sold for FREE in file '%s', line '%d'.\n", id->name, nameid2, filepath, strline(buffer,start-buffer)); } diff --git a/src/map/npc.h b/src/map/npc.h index 54fea4bcaa..50e34d8bfc 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -191,6 +191,8 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m); int npc_instanceinit(struct npc_data* nd); int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amount, int points); +void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, int cost[2], bool display); + extern struct npc_data* fake_nd; int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list);