فهرست منبع

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.

aleos89 9 سال پیش
والد
کامیت
a16fb7c176
4فایلهای تغییر یافته به همراه130 افزوده شده و 82 حذف شده
  1. 1 1
      conf/msg_conf/map_msg.conf
  2. 18 6
      src/map/clif.c
  3. 109 75
      src/map/npc.c
  4. 2 0
      src/map/npc.h

+ 1 - 1
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
 

+ 18 - 6
src/map/clif.c

@@ -15615,7 +15615,7 @@ void clif_parse_cashshop_list_request( int fd, struct map_session_data* sd ){
 /// 0287 <packet len>.W <cash point>.L <kafra point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.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));

+ 109 - 75
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));
 		}

+ 2 - 0
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);