Browse Source

- 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 years ago
parent
commit
0cf60d9ca1
6 changed files with 170 additions and 88 deletions
  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.
 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.
 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
 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
 2006/12/29
 	* Skill use is now cancelled when you use it while cloaking, and the
 	* Skill use is now cancelled when you use it while cloaking, and the
 	  uncloaking process warps you. [Skotlex]
 	  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
 //= Maeki Rika - A section on general concepts and lots of
 //=              other updates and additions.
 //=              other updates and additions.
 //===== Version ===========================================
 //===== Version ===========================================
-//= 2.8a
+//= 2.9
 //=========================================================
 //=========================================================
 //= 1.0 - First release, filled will as much info as I could
 //= 1.0 - First release, filled will as much info as I could
 //=       remember or figure out, most likely there are errors,
 //=       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
 //= 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
 //=	  explanation of atoi.Gave a better explanation of OnLabels and modified
 //=	  monster explanation due that L_Label isn't working with monster.
 //=	  monster explanation due that L_Label isn't working with monster.
+//= 2.9.20061230 - Updated getitem and guardian  [FlavioJS]
 //===== Compatible With ===================================
 //===== Compatible With ===================================
 //= LOL, can be used by anyone hopefully
 //= LOL, can be used by anyone hopefully
 //===== Description =======================================
 //===== Description =======================================
@@ -1663,16 +1664,16 @@ Example 6: Using complex conditions.
 *getitem <item id>,<amount>{,<character ID>};
 *getitem <item id>,<amount>{,<character ID>};
 *getitem "<item name>",<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 
 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 
 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 
 Giving an item ID of -5 will produce the effects of Worn Out Scroll, which, in 
 current SVN, drops only Jellopies anyway.
 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;
     getitem "RED_POTION",10;
 
 
 Which will do what you'd expect. If it can't find that name in the database, 
 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.
 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 
 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 
 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)
 	if(s->wdata_size+len > s->max_wdata)
 	{	// actually there was a buffer overflow already
 	{	// actually there was a buffer overflow already
 		unsigned char *sin_addr = (unsigned char *)&s->client_addr.sin_addr;
 		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);
 			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",
 		ShowDebug("Likely command that caused it: 0x%x\n",
 			(*(unsigned short*)(s->wdata+s->wdata_size)));
 			(*(unsigned short*)(s->wdata+s->wdata_size)));

+ 2 - 6
src/map/log.c

@@ -15,13 +15,9 @@
 #include "log.h"
 #include "log.h"
 
 
 #ifndef SQL_DEBUG
 #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 
 #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
 #endif
 
 
 struct Log_Config log_config;
 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
 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 {
 extern struct Log_Config {
-	int enable_logs, filter;
+	enum log_what enable_logs;
+	int filter;
 	int sql_logs;
 	int sql_logs;
 	int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
 	int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
 	int branch, drop, mvpdrop, zeny, gm, npc, chat;
 	int branch, drop, mvpdrop, zeny, gm, npc, chat;

+ 120 - 62
src/map/script.c

@@ -53,9 +53,18 @@
 #include "irc.h"
 #include "irc.h"
 #include "pet.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) \
 #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
 #define SCRIPT_BLOCK_SIZE 512
 enum { LABEL_NEXTLINE=1,LABEL_START };
 enum { LABEL_NEXTLINE=1,LABEL_START };
@@ -158,8 +167,8 @@ int get_num(unsigned char *script,int *pos);
 
 
 extern struct script_function {
 extern struct script_function {
 	int (*func)(struct script_state *st);
 	int (*func)(struct script_state *st);
-	char *name;
-	char *arg;
+	const char *name;
+	const char *arg;
 } buildin_func[];
 } buildin_func[];
 
 
 static struct linkdb_node *sleep_db;
 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)
 #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);
 		report_src(st);
 	}
 	}
-	return;
 }
 }
 
 
 /*==========================================
 /*==========================================
@@ -657,7 +667,7 @@ static const char* parse_callfunc(const char *p, int require_paren)
 		}
 		}
 		--syntax.curly_count;
 		--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);
 		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 )
 	if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST )
 		disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
 		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)
 static void add_buildin_func(void)
 {
 {
 	int i,n;
 	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_getarraysize,"getarraysize","i"},
 	{buildin_deletearray,"deletearray","ii"},
 	{buildin_deletearray,"deletearray","ii"},
 	{buildin_getelementofarray,"getelementofarray","ii"},
 	{buildin_getelementofarray,"getelementofarray","ii"},
-	{buildin_getitem,"getitem","ii**"},
+	{buildin_getitem,"getitem","vi?"},
 	{buildin_getitem2,"getitem2","iiiiiiiii*"},
 	{buildin_getitem2,"getitem2","iiiiiiiii*"},
 	{buildin_getnameditem,"getnameditem","is"},
 	{buildin_getnameditem,"getnameditem","is"},
 	{buildin_grouprandomitem,"groupranditem","i"},
 	{buildin_grouprandomitem,"groupranditem","i"},
@@ -3948,7 +3976,7 @@ struct script_function buildin_func[] = {
 	{buildin_soundeffect,"soundeffect","si"},
 	{buildin_soundeffect,"soundeffect","si"},
 	{buildin_soundeffectall,"soundeffectall","si*"},	// SoundEffectAll [Codemaster]
 	{buildin_soundeffectall,"soundeffectall","si*"},	// SoundEffectAll [Codemaster]
 	{buildin_strmobinfo,"strmobinfo","ii"},	// display mob data [Valaris]
 	{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_guardianinfo,"guardianinfo","i"},	// display guardian data [Valaris]
 	{buildin_petskillbonus,"petskillbonus","iiii"}, // [Valaris]
 	{buildin_petskillbonus,"petskillbonus","iiii"}, // [Valaris]
 	{buildin_petrecovery,"petrecovery","ii"}, // [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 buildin_getitem(struct script_state *st)
 {
 {
 	int nameid,amount,flag = 0;
 	int nameid,amount,flag = 0;
-	struct item item_tmp;
+	struct item it;
 	struct map_session_data *sd;
 	struct map_session_data *sd;
 	struct script_data *data;
 	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);
 	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);
 		const char *name=conv_str(st,data);
 		struct item_data *item_data = itemdb_searchname(name);
 		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.
 			return 1; //No item created.
 		}
 		}
 		nameid=item_data->nameid;
 		nameid=item_data->nameid;
-	}else
+	} else if( script_isint(data) )
+	{// <item id>
 		nameid=conv_num(st,data);
 		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
 		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)
 	if(!flag)
-		item_tmp.identify=1;
+		it.identify=1;
 	else
 	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;
 		return 0;
-	if(pet_create_egg(sd, nameid))
+	if( pet_create_egg(sd, nameid) )
 		amount = 1; //This is a pet!
 		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);
 		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]
 	//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);
 		log_pick_pc(sd, "N", nameid, amount, NULL);
 
 
 	return 0;
 	return 0;
@@ -9550,26 +9589,45 @@ int buildin_strmobinfo(struct script_state *st)
 
 
 /*==========================================
 /*==========================================
  * Summon guardians [Valaris]
  * 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 buildin_guardian(struct script_state *st)
 {
 {
 	int class_=0,amount=1,x=0,y=0,guardian=0;
 	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;
 	return 0;
 }
 }