Преглед изворни кода

- Updated getitem and guardian entries in script_commands.txt.
- Fixed getitem trying to get <character ID> from the wrong argument.
- Now getitem can be run on scripts without a player attached if <character ID> is specified.
- Now the two last arguments of guardian are optional and independant of each other ("<event label>" and <guardian index>). This way the previous implementation and script_commands definition are still valid code.
- Now buildin function names and argument definitions are checked for validity before adding the function to the script engine.
Argument definitions follow the pattern:
(v|s|i|l)*\?*\*?
v - value (string or int)
s - string
i - int
l - label
? - one optional parameter
* - unknown number of optional parameters

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

FlavioJS пре 18 година
родитељ
комит
0cf60d9ca1
6 измењених фајлова са 170 додато и 88 уклоњено
  1. 14 2
      Changelog-Trunk.txt
  2. 17 16
      doc/script_commands.txt
  3. 1 1
      src/common/socket.c
  4. 2 6
      src/map/log.c
  5. 16 1
      src/map/log.h
  6. 120 62
      src/map/script.c

+ 14 - 2
Changelog-Trunk.txt

@@ -3,9 +3,21 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2006/12/31
+	* Updated getitem and guardian entries in script_commands.txt.
+	* Fixed getitem trying to get <character ID> from the wrong argument.
+	* Now getitem can be run on scripts without a player attached if 
+	  <character ID> is specified.
+	* Now the two last arguments of guardian are optional and independant of 
+	  each other ("<event label>" and <guardian index>). This way the previous 
+	  implementation and script_commands definition are still valid code.
+	* Now buildin function names and argument definitions are checked for 
+	  validity before adding the function to the script engine.
+	  Argument definitions follow the pattern: (v|s|i|l)*\?*\*? [FlavioJS]
 2006/12/30
-	* Reverted the packet structure changes to mmo_char_send006b in r9588 and 
-	  corrected the bug that I was originally fixing. [FlavioJS]
+	* Reverted the packet structure changes to mmo_char_send006b in r9588 (was 
+	  using the wrong exe for the final tests) except for the bug that I was 
+	  originally fixing. [FlavioJS]
 2006/12/29
 	* Skill use is now cancelled when you use it while cloaking, and the
 	  uncloaking process warps you. [Skotlex]

+ 17 - 16
doc/script_commands.txt

@@ -9,7 +9,7 @@
 //= Maeki Rika - A section on general concepts and lots of
 //=              other updates and additions.
 //===== Version ===========================================
-//= 2.8a
+//= 2.9
 //=========================================================
 //= 1.0 - First release, filled will as much info as I could
 //=       remember or figure out, most likely there are errors,
@@ -37,6 +37,7 @@
 //= 2.8 - Deleted a copy of the nude command. Added axtoi command (needing a clearer
 //=	  explanation of atoi.Gave a better explanation of OnLabels and modified
 //=	  monster explanation due that L_Label isn't working with monster.
+//= 2.9.20061230 - Updated getitem and guardian  [FlavioJS]
 //===== Compatible With ===================================
 //= LOL, can be used by anyone hopefully
 //===== Description =======================================
@@ -1663,16 +1664,16 @@ Example 6: Using complex conditions.
 *getitem <item id>,<amount>{,<character ID>};
 *getitem "<item name>",<amount>{,<character ID>};
 
-This command will give a specific amount of specified items to the invoking 
-character. If an optional character ID is specified, and that character is 
-currently online, items will be created in their inventory instead. If they are 
-not online, nothing will happen.
+This command will give a specific amount of specified items to the target 
+character. If the character is not online, nothing will happen.
+If <character ID> is not specified, items will be created in the invoking 
+character inventory instead.
 
-In the first and most commonly used version of this command, tems are referred 
-to by their database ID number found inside 'db/item_db.txt'.
+In the first and most commonly used version of this command, items are 
+referred to by their database ID number found inside 'db/item_db.txt'.
 
-    getitem 502,10 // The person will recieve 10 apples
-    getitem 617,1  // The person will recieve 1 Old Violet Box
+    getitem 502,10 // The person will receive 10 apples
+    getitem 617,1  // The person will receive 1 Old Violet Box
 
 Giving an item ID of -1 will give a specified number of random items from the 
 list of those that fall out of Old Blue Box. Unlike in all other cases, these 
@@ -1687,19 +1688,19 @@ Giving an item ID of -4 will produce the effects of Gift Box.
 Giving an item ID of -5 will produce the effects of Worn Out Scroll, which, in 
 current SVN, drops only Jellopies anyway.
 
-Calling this command with a negative item ID to create a random item will create 
-an entry in the log file for those if such logging is enabled.
+This transaction is logged if the log script generated transactions option is 
+enabled.
 
-You may also create an item by it's name in the 'english name' field in the item 
-database:
+You may also create an item by it's name in the 'english name' field in the 
+item database:
 
     getitem "RED_POTION",10;
 
 Which will do what you'd expect. If it can't find that name in the database, 
 apples will be created anyway. It is often a VERY GOOD IDEA to use it like this.
 
-This used in pretty much all NPC scripts that have to do with items and quite a 
-few item scripts. For more examples check just about any official script.
+This is used in pretty much all NPC scripts that have to do with items and 
+quite a few item scripts. For more examples check just about any official script.
 
 ---------------------------------------
 
@@ -4306,7 +4307,7 @@ per 'db/mob_db.txt'. Type is the kind of information returned. Valid types are:
 
 ---------------------------------------
 
-*guardian "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>"};
+*guardian "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>"}{,<guardian index>};
 
 This command is roughly equivalent to 'monster', but is meant to be used with 
 castle guardian monsters and will only work with them. It will set the guardian 

+ 1 - 1
src/common/socket.c

@@ -571,7 +571,7 @@ int WFIFOSET(int fd,int len)
 	if(s->wdata_size+len > s->max_wdata)
 	{	// actually there was a buffer overflow already
 		unsigned char *sin_addr = (unsigned char *)&s->client_addr.sin_addr;
-		ShowFatalError("socket: Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %d byteson a %d/%d bytes buffer.\n", fd,
+		ShowFatalError("socket: Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %d bytes on a %d/%d bytes buffer.\n", fd,
 			sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3], len, s->wdata_size, s->max_wdata);
 		ShowDebug("Likely command that caused it: 0x%x\n",
 			(*(unsigned short*)(s->wdata+s->wdata_size)));

+ 2 - 6
src/map/log.c

@@ -15,13 +15,9 @@
 #include "log.h"
 
 #ifndef SQL_DEBUG
-
-#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
-
+	#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
 #else 
-
-#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
-
+	#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
 #endif
 
 struct Log_Config log_config;

+ 16 - 1
src/map/log.h

@@ -29,8 +29,23 @@ int log_config_read(char *cfgName);
 
 int should_log_item(int filter, int nameid, int amount); //log filter check
 
+enum log_what {
+	LOG_ALL                 = 0xFFF,
+	LOG_TRADES              = 0x002,
+	LOG_VENDING             = 0x004,
+	LOG_PLAYER_ITEMS        = 0x008, // dropped/picked
+	LOG_MONTER_ITEMS        = 0x010, // dropped/looted
+	LOG_NPC_TRANSACTIONS    = 0x020, // npc shops?
+	LOG_SCRIPT_TRANSACTIONS = 0x040,
+	LOG_STOLEN_ITEMS        = 0x080, // stolen from mobs
+	LOG_USED_ITEMS          = 0x100, // used by player
+	LOG_MVP_PRIZE           = 0x200,
+	LOG_COMMAND_ITEMS       = 0x400  // created/deleted through @/# commands
+};
+
 extern struct Log_Config {
-	int enable_logs, filter;
+	enum log_what enable_logs;
+	int filter;
 	int sql_logs;
 	int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
 	int branch, drop, mvpdrop, zeny, gm, npc, chat;

+ 120 - 62
src/map/script.c

@@ -53,9 +53,18 @@
 #include "irc.h"
 #include "pet.h"
 
+
+///////////////////////////////////////////////////////////////////////////////
+/// Returns the stack_data at the target index
+#define script_getdata(st,i) &((st)->stack->stack_data[(st)->start+(i)])
+/// Returns if the stack contains data at the target index
+#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) )
+#define script_isstring(data) ( (data)->type == C_STR || (data)->type == C_CONSTSTR )
+#define script_isint(data) ( (data)->type == C_INT )
+
 #define FETCH(n, t) \
-		if(st->end>st->start+(n)) \
-			(t)=conv_num(st,&(st->stack->stack_data[st->start+(n)]));
+		if( script_hasdata(st,n) ) \
+			(t)=conv_num(st,script_getdata(st,n));
 
 #define SCRIPT_BLOCK_SIZE 512
 enum { LABEL_NEXTLINE=1,LABEL_START };
@@ -158,8 +167,8 @@ int get_num(unsigned char *script,int *pos);
 
 extern struct script_function {
 	int (*func)(struct script_state *st);
-	char *name;
-	char *arg;
+	const char *name;
+	const char *arg;
 } buildin_func[];
 
 static struct linkdb_node *sleep_db;
@@ -270,12 +279,13 @@ static void disp_error_message2(const char *mes,const char *pos,int report)
 }
 #define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
 
-static void check_event(struct script_state *st, const char *event){
-	if(event != NULL && event[0] != '\0' && !stristr(event,"::On")){
-		ShowError("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n",event);
+/// Checks event parameter validity
+static void check_event(struct script_state *st, const char *evt)
+{
+	if( evt != NULL && *evt != '\0' && !stristr(evt,"::On") ){
+		ShowError("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n",evt);
 		report_src(st);
 	}
-	return;
 }
 
 /*==========================================
@@ -657,7 +667,7 @@ static const char* parse_callfunc(const char *p, int require_paren)
 		}
 		--syntax.curly_count;
 	}
-	if( *arg && *arg != '*' )
+	if( *arg && *arg != '?' && *arg != '*' )
 		disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script_config.warn_func_mismatch_paramnum);
 	if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST )
 		disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
@@ -1528,11 +1538,29 @@ const char* parse_syntax_close_sub(const char* p,int* flag) {
 static void add_buildin_func(void)
 {
 	int i,n;
-	for(i=0;buildin_func[i].func;i++){
-		n=add_str(buildin_func[i].name);
-		str_data[n].type=C_FUNC;
-		str_data[n].val=i;
-		str_data[n].func=buildin_func[i].func;
+	const char* p;
+	for( i=0; buildin_func[i].func; i++ ){
+		/// arg must follow the pattern: (v|s|i|l)*\?*\*?
+		/// 'v' - value (either string or int)
+		/// 's' - string
+		/// 'i' - int
+		/// 'l' - label
+		/// '?' - one optional parameter
+		/// '*' - unknown number of optional parameters
+		p=buildin_func[i].arg;
+		while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'l' ) ++p;
+		while( *p == '?' ) ++p;
+		if( *p == '*' ) ++p;
+		if( *p != 0){
+			ShowWarning("add_buildin_func: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin_func[i].name, buildin_func[i].arg);
+		} else if( *skip_word(buildin_func[i].name) != 0 ){
+			ShowWarning("add_buildin_func: ignoring function with invalid name \"%s\" (must be a word).\n", buildin_func[i].name);
+		} else {
+			n=add_str(buildin_func[i].name);
+			str_data[n].type=C_FUNC;
+			str_data[n].val=i;
+			str_data[n].func=buildin_func[i].func;
+		}
 	}
 }
 
@@ -3778,7 +3806,7 @@ struct script_function buildin_func[] = {
 	{buildin_getarraysize,"getarraysize","i"},
 	{buildin_deletearray,"deletearray","ii"},
 	{buildin_getelementofarray,"getelementofarray","ii"},
-	{buildin_getitem,"getitem","ii**"},
+	{buildin_getitem,"getitem","vi?"},
 	{buildin_getitem2,"getitem2","iiiiiiiii*"},
 	{buildin_getnameditem,"getnameditem","is"},
 	{buildin_grouprandomitem,"groupranditem","i"},
@@ -3948,7 +3976,7 @@ struct script_function buildin_func[] = {
 	{buildin_soundeffect,"soundeffect","si"},
 	{buildin_soundeffectall,"soundeffectall","si*"},	// SoundEffectAll [Codemaster]
 	{buildin_strmobinfo,"strmobinfo","ii"},	// display mob data [Valaris]
-	{buildin_guardian,"guardian","siisii*i"},	// summon guardians
+	{buildin_guardian,"guardian","siisii??"},	// summon guardians
 	{buildin_guardianinfo,"guardianinfo","i"},	// display guardian data [Valaris]
 	{buildin_petskillbonus,"petskillbonus","iiii"}, // [Valaris]
 	{buildin_petrecovery,"petrecovery","ii"}, // [Valaris]
@@ -5282,66 +5310,77 @@ int buildin_checkweight(struct script_state *st)
 }
 
 /*==========================================
- *
+ * getitem <item id>,<amount>{,<character ID>};
+ * getitem "<item name>",<amount>{,<character ID>};
  *------------------------------------------
  */
 int buildin_getitem(struct script_state *st)
 {
 	int nameid,amount,flag = 0;
-	struct item item_tmp;
+	struct item it;
 	struct map_session_data *sd;
 	struct script_data *data;
 
-	sd = script_rid2sd(st);
-
-	data=&(st->stack->stack_data[st->start+2]);
+	data=script_getdata(st,2);
 	get_val(st,data);
-	if( data->type==C_STR || data->type==C_CONSTSTR ){
+	if( script_isstring(data) )
+	{// "<item name>"
 		const char *name=conv_str(st,data);
 		struct item_data *item_data = itemdb_searchname(name);
-		if( item_data == NULL) {
-			ShowWarning("buildin_getitem: Nonexistant item %s requested.\n", name);
+		if( item_data == NULL ){
+			ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
+			report_src(st);
 			return 1; //No item created.
 		}
 		nameid=item_data->nameid;
-	}else
+	} else if( script_isint(data) )
+	{// <item id>
 		nameid=conv_num(st,data);
+		//Violet Box, Blue Box, etc - random item pick
+		if( nameid < 0 ) {
+			nameid=itemdb_searchrandomid(-nameid);
+			flag = 1;
+		}
+		if( nameid <= 0 || !itemdb_exists(nameid) ){
+			ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
+			report_src(st);
+			return 1; //No item created.
+		}
+	} else {
+		ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type);
+		report_src(st);
+		return 1;
+	}
 
-	if ( ( amount=conv_num(st,& (st->stack->stack_data[st->start+3])) ) <= 0)
+	// <amount>
+	if( (amount=conv_num(st, script_getdata(st,3))) <= 0)
 		return 0; //return if amount <=0, skip the useles iteration
 
-	//Violet Box, Blue Box, etc - random item pick
-	if(nameid <0) {
-		nameid=itemdb_searchrandomid(-nameid);
-		flag = 1;
-	}
-
-	if(nameid <= 0 || !itemdb_exists(nameid)) {
-		ShowWarning("buildin_getitem: Nonexistant item %d requested.\n", nameid);
-		return 1; //No item created.
-	}
-		
-	malloc_set(&item_tmp,0,sizeof(item_tmp));
-	item_tmp.nameid=nameid;
+	malloc_set(&it,0,sizeof(it));
+	it.nameid=nameid;
 	if(!flag)
-		item_tmp.identify=1;
+		it.identify=1;
 	else
-		item_tmp.identify=itemdb_isidentified(nameid);
-	if( st->end>st->start+5 ) //アイテムを指定したIDに渡す
-		sd=map_id2sd(conv_num(st,& (st->stack->stack_data[st->start+5])));
-	if(sd == NULL) //アイテムを渡す相手がいなかったらお帰り
+		it.identify=itemdb_isidentified(nameid);
+	if( script_hasdata(st,4) )
+	{// <character ID>
+		sd=map_id2sd(conv_num(st,script_getdata(st,4)));
+	} else
+	{// attached player
+		sd=script_rid2sd(st);
+	}
+	if( sd == NULL ) // no target
 		return 0;
-	if(pet_create_egg(sd, nameid))
+	if( pet_create_egg(sd, nameid) )
 		amount = 1; //This is a pet!
-	else
-	if((flag = pc_additem(sd,&item_tmp,amount))) {
+	else if( (flag=pc_additem(sd,&it,amount)) ){
 		clif_additem(sd,0,0,flag);
-		if (pc_candrop(sd, &item_tmp))
-			map_addflooritem(&item_tmp,amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
+		if( pc_candrop(sd,&it) )
+			map_addflooritem(&it,amount,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
 	}
 
 	//Logs items, got from (N)PC scripts [Lupus]
-	if(log_config.enable_logs&0x40)
+	if(log_config.enable_logs&LOG_SCRIPT_TRANSACTIONS)
 		log_pick_pc(sd, "N", nameid, amount, NULL);
 
 	return 0;
@@ -9550,26 +9589,45 @@ int buildin_strmobinfo(struct script_state *st)
 
 /*==========================================
  * Summon guardians [Valaris]
+ * guardian "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>"}{,<guardian index>};
  *------------------------------------------
  */
 int buildin_guardian(struct script_state *st)
 {
 	int class_=0,amount=1,x=0,y=0,guardian=0;
-	char *str,*map,*event="";
+	char *str,*map,*evt="";
+	struct script_data *data;
 
-	map	=conv_str(st,& (st->stack->stack_data[st->start+2]));
-	x	=conv_num(st,& (st->stack->stack_data[st->start+3]));
-	y	=conv_num(st,& (st->stack->stack_data[st->start+4]));
-	str	=conv_str(st,& (st->stack->stack_data[st->start+5]));
-	class_=conv_num(st,& (st->stack->stack_data[st->start+6]));
-	amount=conv_num(st,& (st->stack->stack_data[st->start+7]));
-	event=conv_str(st,& (st->stack->stack_data[st->start+8]));
-	if( st->end>st->start+9 )
-		guardian=conv_num(st,& (st->stack->stack_data[st->start+9]));
+	map	  =conv_str(st,script_getdata(st,2));
+	x	  =conv_num(st,script_getdata(st,3));
+	y	  =conv_num(st,script_getdata(st,4));
+	str	  =conv_str(st,script_getdata(st,5));
+	class_=conv_num(st,script_getdata(st,6));
+	amount=conv_num(st,script_getdata(st,7));
+
+	if( script_hasdata(st,9) )
+	{// "<event label>",<guardian index>
+		evt=conv_str(st,script_getdata(st,8));
+		guardian=conv_num(st,script_getdata(st,9));
+	} else if( script_hasdata(st,8) ){
+		data=script_getdata(st,8);
+		get_val(st,data);
+		if( script_isstring(data) )
+		{// "<event label>"
+			evt=conv_str(st,script_getdata(st,8));
+		} else if( script_isint(data) )
+		{// <guardian index>
+			guardian=conv_num(st,script_getdata(st,8));
+		} else {
+			ShowError("buildin_guardian: invalid data type for argument #8 (%d).", data->type);
+			report_src(st);
+			return 1;
+		}
+	}
 
-	check_event(st, event);
+	check_event(st, evt);
 
-	mob_spawn_guardian(map_id2sd(st->rid),map,x,y,str,class_,amount,event,guardian);
+	mob_spawn_guardian(map_id2sd(st->rid),map,x,y,str,class_,amount,evt,guardian);
 
 	return 0;
 }