diff options
-rw-r--r-- | Changelog-Trunk.txt | 8 | ||||
-rw-r--r-- | doc/script_commands.txt | 55 | ||||
-rw-r--r-- | src/map/script.c | 155 |
3 files changed, 158 insertions, 60 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 255546fe0..ee9741841 100644 --- a/Changelog-Trunk.txt +++ b/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. diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 102380148..81462e634 100644 --- a/doc/script_commands.txt +++ b/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 diff --git a/src/map/script.c b/src/map/script.c index 2182e5c74..b2dfda578 100644 --- a/src/map/script.c +++ b/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; } |