浏览代码

- Cleaned up the npcshop(add/del) item script commands, fixed a possible dangling pointer crash caused by their improper use of realloc. They no longer automatically attach the script to the shop, and they will return true/false based on whether the shop was found or not.
- Added script command npcshopattach to enable attaching/detaching your script from any npc shop.
- Updated doc/script_commands.txt with entries for npcshopitem, npcshopadditem, npcshopdelitem and npcshopattach


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@9769 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 18 年之前
父节点
当前提交
4130bdd3b8
共有 3 个文件被更改,包括 158 次插入60 次删除
  1. 8 0
      Changelog-Trunk.txt
  2. 55 0
      doc/script_commands.txt
  3. 95 60
      src/map/script.c

+ 8 - 0
Changelog-Trunk.txt

@@ -4,6 +4,14 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2007/02/01
+	* Cleaned up the npcshop(add/del)item script commands, fixed a possible
+	  dangling pointer crash caused by their improper use of realloc. They no
+	  longer automatically attach the script to the shop, and they will return
+	  true/false based on whether the shop was found or not.
+	* Added script command npcshopattach to enable attaching/detaching your
+	  script from any npc shop.
+	* Updated doc/script_commands.txt with entries for npcshopitem,
+	  npcshopadditem, npcshopdelitem and npcshopattach [Skotlex]
 	* A followup to r9761, a header include that somehow didn't commit [ultramage]
 	* Item search is now a bit smarter. When no item is found with the same
 	  'aegis name', then the 'normal' name is used instead.

+ 55 - 0
doc/script_commands.txt

@@ -43,6 +43,8 @@
 //= 2.11.20070109 - removed the unused flag argument in guildskill, added an 
 //=       optional argument to setcart,setfalcon,setriding and other cleanups 
 //=       [FlavioJS]
+//= 2.12.20070201 - Added npcshopitem, npcshopadditem, npcshopdelitem and
+//=       npcshopattach [Skotlex]
 //===== Compatible With ===================================
 //= LOL, can be used by anyone hopefully
 //===== Description =======================================
@@ -3595,6 +3597,59 @@ itself).
 
 ---------------------------------------
 
+*npcshopitem "<name>",<itemId>,<Price>{,<itemId>,<Price>{,<itemId>,<Price>{,...}}}
+
+This command lets you override the contents of an existing npc shop. The
+current sell list will be wiped, and only the items specified with the price
+specified will be for sale.
+
+The function returns 1 if shop was updated successfully, or 0 if not found.
+
+Note that you cannot use -1 to specify default selling price!
+
+---------------------------------------
+
+*npcshopadditem "<name>",<itemId>,<Price>{,<itemId>,<Price>{,<itemId>,<Price>{,...}}}
+
+This command will add more items at the end of the selling list for the
+specified npc shop. If you specify an item already for sell, that item will
+appear twice on the sell list.
+
+The function returns 1 if shop was updated successfully, or 0 if not found.
+
+Note that you cannot use -1 to specify default selling price!
+
+---------------------------------------
+
+*npcshopdelitem "<name>",<itemId>{,<itemId>{,<itemId>{,...}}}
+
+This command will remove items from the specified npc shop.
+If the item to remove exists more than once on the shop, all instances will be
+removed.
+
+Note that the function returns 1 even if no items were removed. The return
+value is only to confirm that the shop was indeed found.
+
+---------------------------------------
+
+*npcshopattach "<name>"{,<flag>}
+
+This command will attach the current script to the given npc shop.
+When a script is attached to a shop, the events "OnBuyItem" and "OnSellItem"
+of your script will be executed whenever a player buys/sells from the shop.
+Additionally, the arrays @bought_nameid[], @bought_quantity[] or @sold_nameid[]
+and @sold_quantity[] will be filled up with the items and quantities
+bought/sold.
+
+The optional parameter specifies whether to attach ("1") or detach ("0") from
+the shop (the default is to attach). Note that detaching will detach any npc
+attached to the shop, even if it's from another script, while attaching will
+override any other script that may be already attached.
+
+The function returns 0 if the shop was not found, 1 otherwise.
+
+---------------------------------------
+
 *debugmes "<message>";
 
 This command will send the message to the server console (map-server window). It 

+ 95 - 60
src/map/script.c

@@ -3772,6 +3772,7 @@ int buildin_callshop(struct script_state *st); // [Skotlex]
 int buildin_npcshopitem(struct script_state *st); // [Lance]
 int buildin_npcshopadditem(struct script_state *st);
 int buildin_npcshopdelitem(struct script_state *st);
+int buildin_npcshopattach(struct script_state *st);
 int buildin_equip(struct script_state *st);
 int buildin_autoequip(struct script_state *st);
 int buildin_setbattleflag(struct script_state *st);
@@ -4109,6 +4110,7 @@ struct script_function buildin_func[] = {
 	{buildin_npcshopitem,"npcshopitem","sii*"}, // [Lance]
 	{buildin_npcshopadditem,"npcshopadditem","sii*"},
 	{buildin_npcshopdelitem,"npcshopdelitem","si*"},
+	{buildin_npcshopattach,"npcshopattach","s?"},
 	{buildin_equip,"equip","i"},
 	{buildin_autoequip,"autoequip","ii"},
 	{buildin_setbattleflag,"setbattleflag","ss"},
@@ -11891,32 +11893,33 @@ int buildin_npcshopitem(struct script_state *st)
 	char* npcname = conv_str(st, & (st->stack->stack_data[st->start + 2]));
 	nd = npc_name2id(npcname);
 
-	if(nd && nd->bl.subtype==SHOP){
-		amount = ((st->end-2)/2)+1;
-		// st->end - 2 = nameid + value # ... / 2 = number of items ... + 1 to end it
-		nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
-			sizeof(nd->u.shop_item[0]) * amount);
+	if(!nd || nd->bl.subtype!=SHOP)
+	{	//Not found.
+		push_val(st->stack,C_INT,0);
+		return 0;
+	}
 
-		// Reset sell list.
-		memset(nd->u.shop_item, 0, sizeof(nd->u.shop_item[0]) * amount);
+	// st->end - 2 = nameid + value # ... / 2 = number of items ... + 1 to end it
+	amount = ((st->end-2)/2)+1;
 
-		n = 0;
+	//Reinsert as realloc could change the pointer address.
+	map_deliddb(&nd->bl);
+	nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
+		sizeof(nd->u.shop_item[0]) * amount);
+	map_addiddb(&nd->bl);
 
-		while (st->end > st->start + i) {
-			nd->u.shop_item[n].nameid = conv_num(st, & (st->stack->stack_data[st->start+i]));
-			i++;
-			nd->u.shop_item[n].value = conv_num(st, & (st->stack->stack_data[st->start+i]));
-			i++;
-			n++;
-		}
+	// Reset sell list.
+	memset(nd->u.shop_item, 0, sizeof(nd->u.shop_item[0]) * amount);
 
-		map_addiddb(&nd->bl);
+	n = 0;
 
-		nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
-	} else {
-		ShowError("buildin_npcshopitem: shop not found.\n");
+	while (st->end > st->start + i) {
+		nd->u.shop_item[n].nameid = conv_num(st, & (st->stack->stack_data[st->start+i]));
+		i++;
+		nd->u.shop_item[n].value = conv_num(st, & (st->stack->stack_data[st->start+i]));
+		i++;
+		n++;
 	}
-
 	return 0;
 }
 
@@ -11929,32 +11932,35 @@ int buildin_npcshopadditem(struct script_state *st) {
 	char* npcname = conv_str(st, & (st->stack->stack_data[st->start+2]));
 	nd = npc_name2id(npcname);
 
-	if (nd && nd->bl.subtype==SHOP){
-		amount = ((st->end-2)/2)+1;
-		while (nd->u.shop_item[n].nameid && n < MAX_SHOPITEM)
-			n++;
-
-		nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
-			sizeof(nd->u.shop_item[0]) * (amount+n));
+	if (!nd || nd->bl.subtype!=SHOP)
+	{	//Not found.
+		push_val(st->stack,C_INT,0);
+		return 0;
+	}
+	amount = ((st->end-2)/2)+1;
+	while (nd->u.shop_item[n].nameid && n < MAX_SHOPITEM)
+		n++;
 
-		while(st->end > st->start + i){
-			nd->u.shop_item[n].nameid = conv_num(st, & (st->stack->stack_data[st->start+i]));
-			i++;
-			nd->u.shop_item[n].value = conv_num(st, & (st->stack->stack_data[st->start+i]));
-			i++;
-			n++;
-		}
 
-		// Marks the last of our stuff..
-		nd->u.shop_item[n].value = 0;
-		nd->u.shop_item[n].nameid = 0;
+	//Reinsert as realloc could change the pointer address.
+	map_deliddb(&nd->bl);
+	nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
+		sizeof(nd->u.shop_item[0]) * (amount+n));
+	map_addiddb(&nd->bl);
 
-		map_addiddb(&nd->bl);
-		nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
-	} else {
-		ShowError("buildin_npcshopadditem: shop not found.\n");
+	while(st->end > st->start + i){
+		nd->u.shop_item[n].nameid = conv_num(st, & (st->stack->stack_data[st->start+i]));
+		i++;
+		nd->u.shop_item[n].value = conv_num(st, & (st->stack->stack_data[st->start+i]));
+		i++;
+		n++;
 	}
 
+	// Marks the last of our stuff..
+	nd->u.shop_item[n].value = 0;
+	nd->u.shop_item[n].nameid = 0;
+
+	push_val(st->stack,C_INT,1);
 	return 0;
 }
 
@@ -11968,34 +11974,63 @@ int buildin_npcshopdelitem(struct script_state *st)
 	char* npcname = conv_str(st, & (st->stack->stack_data[st->start+2]));
 	nd = npc_name2id(npcname);
 
-	if (nd && nd->bl.subtype==SHOP) {
-		while (nd->u.shop_item[size].nameid)
-			size++;
+	if (!nd || nd->bl.subtype!=SHOP)
+	{	//Not found.
+		push_val(st->stack,C_INT,0);
+		return 0;
+	}
+
+	while (nd->u.shop_item[size].nameid)
+		size++;
 
-		while (st->end > st->start+i) {
-			for(n=0;nd->u.shop_item[n].nameid && n < MAX_SHOPITEM;n++) {
-				if (nd->u.shop_item[n].nameid == conv_num(st, & (st->stack->stack_data[st->start+i]))) {
-					// We're moving 1 extra empty block. Junk data is eliminated later.
-					memmove(&nd->u.shop_item[n], &nd->u.shop_item[n+1], sizeof(nd->u.shop_item[0])*(size-n));
-				}
+	while (st->end > st->start+i) {
+		for(n=0;nd->u.shop_item[n].nameid && n < MAX_SHOPITEM;n++) {
+			if (nd->u.shop_item[n].nameid == conv_num(st, & (st->stack->stack_data[st->start+i]))) {
+				// We're moving 1 extra empty block. Junk data is eliminated later.
+				memmove(&nd->u.shop_item[n], &nd->u.shop_item[n+1], sizeof(nd->u.shop_item[0])*(size-n));
 			}
-			i++;
 		}
+		i++;
+	}
 
-		size = 0;
+	size = 0;
 
-		while (nd->u.shop_item[size].nameid)
-			size++;
+	while (nd->u.shop_item[size].nameid)
+		size++;
 
-		nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
-			sizeof(nd->u.shop_item[0]) * (size+1));
+	//Reinsert as realloc could change the pointer address.
+	map_deliddb(&nd->bl);
+	nd = (struct npc_data *)aRealloc(nd,sizeof(struct npc_data) +
+		sizeof(nd->u.shop_item[0]) * (size+1));
+	map_addiddb(&nd->bl);
 
-		map_addiddb(&nd->bl);
-		nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
-	} else {
-		ShowError("buildin_npcshopdelitem: shop not found.\n");
+	push_val(st->stack,C_INT,1);
+	return 0;
+}
+
+//Sets a script to attach to an npc.
+int buildin_npcshopattach(struct script_state *st)
+{
+	struct npc_data *nd=NULL;
+	char* npcname = conv_str(st, & (st->stack->stack_data[st->start+2]));
+	int flag = 1;
+
+	if( script_hasdata(st,2) )
+		flag = conv_num(st, script_getdata(st,2));
+
+	nd = npc_name2id(npcname);
+
+	if (!nd || nd->bl.subtype!=SHOP)
+	{	//Not found.
+		push_val(st->stack,C_INT,0);
+		return 0;
 	}
 
+	if (flag)
+		nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
+	else
+		nd->master_nd = NULL;
+	push_val(st->stack,C_INT,1);
 	return 0;
 }