فهرست منبع

* WARNING: New scripting system contains memory leak
TODO: Free all scripts using script_free_code() instead of old methods.

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

Lance 19 سال پیش
والد
کامیت
a7e5993400
11فایلهای تغییر یافته به همراه586 افزوده شده و 111 حذف شده
  1. 2 0
      Changelog-Trunk.txt
  2. 104 0
      src/common/db.c
  3. 14 0
      src/common/db.h
  4. 10 10
      src/map/itemdb.c
  5. 3 3
      src/map/itemdb.h
  6. 2 2
      src/map/map.h
  7. 6 4
      src/map/npc.c
  8. 1 1
      src/map/pc.c
  9. 1 1
      src/map/pet.h
  10. 425 87
      src/map/script.c
  11. 18 3
      src/map/script.h

+ 2 - 0
Changelog-Trunk.txt

@@ -4,6 +4,8 @@ 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.
 
 2006/05/22
+	* WARNING: New scripting system contains memory leak
+	  TODO: Free all scripts using script_free_code() instead of old methods. [Lance]
 	* Excluded idle and auto-trade party members from TK_POWER list. [Lance]
 	* Fixed compilation errors.
 	  Tidy up jobmaster for easy debugging. [Lance]

+ 104 - 0
src/common/db.c

@@ -2342,3 +2342,107 @@ void db_final(void)
 #endif /* DB_ENABLE_STATS */
 }
 
+// Link DB System - jAthena
+void  linkdb_insert( struct linkdb_node** head, void *key, void* data) {
+	struct linkdb_node *node;
+	if( head == NULL ) return ;
+	node = aMalloc( sizeof(struct linkdb_node) );
+	if( *head == NULL ) {
+		// first node
+		*head      = node;
+		node->prev = NULL;
+		node->next = NULL;
+	} else {
+		// link nodes
+		node->next    = *head;
+		node->prev    = (*head)->prev;
+		(*head)->prev = node;
+		(*head)       = node;
+	}
+	node->key  = key;
+	node->data = data;
+}
+
+void* linkdb_search( struct linkdb_node** head, void *key) {
+	int n = 0;
+	struct linkdb_node *node;
+	if( head == NULL ) return NULL;
+	node = *head;
+	while( node ) {
+		if( node->key == key ) {
+			if( node->prev && n > 5 ) {
+				// 処理効率改善の為にheadに移動させる
+				if(node->prev) node->prev->next = node->next;
+				if(node->next) node->next->prev = node->prev;
+				node->next = *head;
+				node->prev = (*head)->prev;
+				(*head)->prev = node;
+				(*head)       = node;
+			}
+			return node->data;
+		}
+		node = node->next;
+		n++;
+	}
+	return NULL;
+}
+
+void* linkdb_erase( struct linkdb_node** head, void *key) {
+	struct linkdb_node *node;
+	if( head == NULL ) return NULL;
+	node = *head;
+	while( node ) {
+		if( node->key == key ) {
+			void *data = node->data;
+			if( node->prev == NULL )
+				*head = node->next;
+			else
+				node->prev->next = node->next;
+			if( node->next )
+				node->next->prev = node->prev;
+			aFree( node );
+			return data;
+		}
+		node = node->next;
+	}
+	return NULL;
+}
+
+void linkdb_replace( struct linkdb_node** head, void *key, void *data ) {
+	int n = 0;
+	struct linkdb_node *node;
+	if( head == NULL ) return ;
+	node = *head;
+	while( node ) {
+		if( node->key == key ) {
+			if( node->prev && n > 5 ) {
+				// 処理効率改善の為にheadに移動させる
+				if(node->prev) node->prev->next = node->next;
+				if(node->next) node->next->prev = node->prev;
+				node->next = *head;
+				node->prev = (*head)->prev;
+				(*head)->prev = node;
+				(*head)       = node;
+			}
+			node->data = data;
+			return ;
+		}
+		node = node->next;
+		n++;
+	}
+	// 見つからないので挿入
+	linkdb_insert( head, key, data );
+}
+
+void  linkdb_final( struct linkdb_node** head ) {
+	struct linkdb_node *node, *node2;
+	if( head == NULL ) return ;
+	node = *head;
+	while( node ) {
+		node2 = node->next;
+		aFree( node );
+		node = node2;
+	}
+	*head = NULL;
+}
+

+ 14 - 0
src/common/db.h

@@ -731,4 +731,18 @@ void db_init(void);
  */
 void db_final(void);
 
+// Link DB System - From jAthena
+struct linkdb_node {
+	struct linkdb_node *next;
+	struct linkdb_node *prev;
+	void               *key;
+	void               *data;
+};
+
+void  linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない
+void  linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する
+void* linkdb_search ( struct linkdb_node** head, void *key);
+void* linkdb_erase  ( struct linkdb_node** head, void *key);
+void  linkdb_final  ( struct linkdb_node** head );
+
 #endif

+ 10 - 10
src/map/itemdb.c

@@ -862,7 +862,7 @@ static int itemdb_read_sqldb(void)
 					// ----------
 					
 					if (id->script)
-						aFree(id->script);
+						script_free_code(id->script);
 					if (sql_row[19] != NULL) {
 						if (sql_row[19][0] == '{')
 							id->script = parse_script((unsigned char *) sql_row[19], 0);
@@ -873,7 +873,7 @@ static int itemdb_read_sqldb(void)
 					} else id->script = NULL;
 	
 					if (id->equip_script)
-						aFree(id->equip_script);
+						script_free_code(id->equip_script);
 					if (sql_row[20] != NULL) {
 						if (sql_row[20][0] == '{')
 							id->equip_script = parse_script((unsigned char *) sql_row[20], 0);
@@ -884,7 +884,7 @@ static int itemdb_read_sqldb(void)
 					} else id->equip_script = NULL;
 	
 					if (id->unequip_script)
-						aFree(id->unequip_script);
+						script_free_code(id->unequip_script);
 					if (sql_row[21] != NULL) {
 						if (sql_row[21][0] == '{')
 							id->unequip_script = parse_script((unsigned char *) sql_row[21], 0);
@@ -1030,7 +1030,7 @@ static int itemdb_readdb(void)
 			id->sex = itemdb_gendercheck(id); //Apply gender filtering.
 
 			if (id->script) {
-				aFree(id->script);
+				script_free_code(id->script);
 				id->script=NULL;
 			}
 			if (id->equip_script) {
@@ -1130,17 +1130,17 @@ static int itemdb_final_sub (DBKey key,void *data,va_list ap)
 	flag = va_arg(ap, int);
 	if (id->script)
 	{
-		aFree(id->script);
+		script_free_code(id->script);
 		id->script = NULL;
 	}
 	if (id->equip_script)
 	{
-		aFree(id->equip_script);
+		script_free_code(id->equip_script);
 		id->equip_script = NULL;
 	}
 	if (id->unequip_script)
 	{
-		aFree(id->unequip_script);
+		script_free_code(id->unequip_script);
 		id->unequip_script = NULL;
 	}
 	// Whether to clear the item data (exception: do not clear the dummy item data
@@ -1162,11 +1162,11 @@ void do_final_itemdb(void)
 	item_db->destroy(item_db, itemdb_final_sub, 1);
 	if (dummy_item) {
 		if (dummy_item->script)
-			aFree(dummy_item->script);
+			script_free_code(dummy_item->script);
 		if (dummy_item->equip_script)
-			aFree(dummy_item->equip_script);
+			script_free_code(dummy_item->equip_script);
 		if (dummy_item->unequip_script)
-			aFree(dummy_item->unequip_script);
+			script_free_code(dummy_item->unequip_script);
 		aFree(dummy_item);
 		dummy_item = NULL;
 	}

+ 3 - 3
src/map/itemdb.h

@@ -35,9 +35,9 @@ struct item_data {
 		unsigned short chance;
 		int id;
 	} mob[MAX_SEARCH]; //Holds the mobs that have the highest drop rate for this item. [Skotlex]
-	unsigned char *script;	//Default script for everything.
-	unsigned char *equip_script;	//Script executed once when equipping.
-	unsigned char *unequip_script;//Script executed once when unequipping.
+	struct script_code *script;	//Default script for everything.
+	struct script_code *equip_script;	//Script executed once when equipping.
+	struct script_code *unequip_script;//Script executed once when unequipping.
 	struct {
 		unsigned available : 1;
 		unsigned value_notdc : 1;

+ 2 - 2
src/map/map.h

@@ -538,7 +538,7 @@ struct map_session_data {
 	int npc_menu;
 	int npc_amount;
 	struct script_stack *stack;
-	unsigned char *npc_script,*npc_scriptroot;
+	struct script_code *npc_script,*npc_scriptroot;
 	int  npc_scriptstate;
 	char npc_str[256];
 	int npc_timer_id; //For player attached npc timers. [Skotlex]
@@ -805,7 +805,7 @@ struct npc_data {
 
 	union {
 		struct {
-			unsigned char *script;
+			struct script_code *script;
 			short xs,ys;
 			int guild_id;
 			int timer,timerid,timeramount,rid;

+ 6 - 4
src/map/npc.c

@@ -1780,7 +1780,8 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin
 {
 	int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0;	// [Valaris] thanks to fov
 	char mapname[MAP_NAME_LENGTH];
-	unsigned char *srcbuf = NULL, *script;
+	unsigned char *srcbuf = NULL;
+	struct script_code *script;
 	int srcsize = 65536;
 	int startline = 0;
 	unsigned char line[1024];
@@ -1838,7 +1839,7 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin
 			script = NULL;
 		} else {
 			// printf("Ok line %d\n",*lines);
-			script = (unsigned char *) parse_script((unsigned char *) srcbuf, startline);
+			script = parse_script((unsigned char *) srcbuf, startline);
 		}
 		if (script == NULL) {
 			// script parse error?
@@ -1857,7 +1858,7 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin
 			ShowError("bad duplicate name (in %s)! (not exist) : %s\n", current_file, srcname);
 			return 0;
 		}
-		script = (unsigned char *)nd2->u.scr.script;
+		script = nd2->u.scr.script;
 		label_dup = nd2->u.scr.label_list;
 		label_dupnum = nd2->u.scr.label_list_num;
 		src_id = nd2->bl.id;
@@ -2027,7 +2028,8 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin
  */
 static int npc_parse_function (char *w1, char *w2, char *w3, char *w4, char *first_line, FILE *fp, int *lines)
 {
-	unsigned char *srcbuf, *script, *p;
+	unsigned char *srcbuf, *p;
+	struct script_code *script;
 	int srcsize = 65536;
 	int startline = 0;
 	char line[1024];

+ 1 - 1
src/map/pc.c

@@ -2661,7 +2661,7 @@ int pc_useitem(struct map_session_data *sd,int n)
 {
 	unsigned int tick = gettick();
 	int amount;
-	unsigned char *script;
+	struct script_code *script;
 
 	nullpo_retr(0, sd);
 

+ 1 - 1
src/map/pet.h

@@ -27,7 +27,7 @@ struct pet_db {
 	int attack_rate;
 	int defence_attack_rate;
 	int change_target_rate;
-	unsigned char *script;
+	struct script_code *script;
 };
 extern struct pet_db pet_db[MAX_PET_DB];
 

+ 425 - 87
src/map/script.c

@@ -124,6 +124,8 @@ char tmp_sql[65535];
 // --------------------------------------------------------
 #endif
 
+static struct linkdb_node *sleep_db;
+
 /*==========================================
  * ローカルプロトタイプ宣言 (必要な物のみ)
  *------------------------------------------
@@ -428,6 +430,10 @@ int buildin_mobtalk(struct script_state *st);
 int buildin_mobemote(struct script_state *st);
 int buildin_mobattach(struct script_state *st);
 // <--- [zBuffer] List of mob control commands
+int buildin_sleep(struct script_state *st);
+int buildin_sleep2(struct script_state *st);
+int buildin_awake(struct script_state *st);
+int buildin_getvariableofnpc(struct script_state *st);
 void push_val(struct script_stack *stack,int type,int val);
 int run_func(struct script_state *st);
 
@@ -763,6 +769,10 @@ struct {
 	{buildin_mobemote,"mobemote","*"},
 	{buildin_mobattach,"mobattach","*"},
 // <--- [zBuffer] List of mob control commands
+{buildin_sleep,"sleep","i"},
+	{buildin_sleep2,"sleep2","i"},
+	{buildin_awake,"awake","s"},
+	{buildin_getvariableofnpc,"getvariableofnpc","is"},
 	{NULL,NULL,NULL},
 };
 
@@ -2162,10 +2172,11 @@ static void read_constdb(void)
  * スクリプトの解析
  *------------------------------------------
  */
-unsigned char* parse_script(unsigned char *src,int line)
+struct script_code* parse_script(unsigned char *src,int line)
 {
 	unsigned char *p, *tmpp;
 	int i;
+	struct script_code *code;
 	static int first = 1;
 
 	if (first) {
@@ -2275,7 +2286,11 @@ unsigned char* parse_script(unsigned char *src,int line)
 #endif
 
 	startptr = NULL; //Clear pointer to prevent future references to a src that may be free'd. [Skotlex]
-	return (unsigned char *) script_buf;
+	code = aCalloc(1, sizeof(struct script_code));
+	code->script_buf  = script_buf;
+	code->script_size = script_size;
+	code->script_vars = NULL;
+	return code;
 }
 
 //
@@ -2330,7 +2345,17 @@ int get_val(struct script_state*st,struct script_data* data)
 					if(sd)
 					data->u.str = pc_readaccountregstr(sd,name);
 				}
- 			}else{
+ 			}else if(prefix=='\'') {
+				struct linkdb_node **n;
+				if( data->ref ) {
+					n = data->ref;
+				} else if( name[1] == '@' ) {
+					n = st->stack->var_function;
+				} else {
+					n = &st->script->script_vars;
+				}
+				data->u.str = linkdb_search(n, (void*)data->u.num );
+			}else{
 				if(sd)
 				data->u.str = pc_readglobalreg_str(sd,name);
  			} // [zBuffer]
@@ -2362,6 +2387,16 @@ int get_val(struct script_state*st,struct script_data* data)
 					if(sd)
 					data->u.num = pc_readaccountreg(sd,name);
 				}
+			}else if(prefix=='\''){
+				struct linkdb_node **n;
+				if( data->ref ) {
+					n = data->ref;
+				} else if( name[1] == '@' ) {
+					n = st->stack->var_function;
+				} else {
+					n = &st->script->script_vars;
+				}
+				data->u.num = (int)linkdb_search(n, (void*)data->u.num);
 			}else{
 				if(sd)
 				data->u.num = pc_readglobalreg(sd,name);
@@ -2374,11 +2409,12 @@ int get_val(struct script_state*st,struct script_data* data)
  * 変数の読み取り2
  *------------------------------------------
  */
-void* get_val2(struct script_state*st,int num)
+void* get_val2(struct script_state*st,int num,struct linkdb_node **ref)
 {
 	struct script_data dat;
 	dat.type=C_NAME;
 	dat.u.num=num;
+	dat.ref = ref;
 	get_val(st,&dat);
 	if( dat.type==C_INT ) return (void*)dat.u.num;
 	else return (void*)dat.u.str;
@@ -2388,7 +2424,7 @@ void* get_val2(struct script_state*st,int num)
  * 変数設定用
  *------------------------------------------
  */
-static int set_reg(struct map_session_data *sd,int num,char *name,void *v)
+static int set_reg(struct script_state*st,struct map_session_data *sd,int num,char *name,void *v,struct linkdb_node** ref)
 {
 	char prefix=*name;
 	char postfix=name[strlen(name)-1];
@@ -2404,7 +2440,24 @@ static int set_reg(struct map_session_data *sd,int num,char *name,void *v)
 				pc_setaccountreg2str(sd,name,str);
 			else
 				pc_setaccountregstr(sd,name,str);
- 		}else{
+ 		}else if(prefix=='\'') {
+			char *p;
+			struct linkdb_node **n;
+			if( ref ) {
+				n = ref;
+			} else if( name[1] == '@' ) {
+				n = st->stack->var_function;
+			} else {
+				n = &st->script->script_vars;
+			}
+			p = linkdb_search(n, (void*)num);
+			if(p) {
+				linkdb_erase(n, (void*)num);
+				aFree(p);
+			}
+			if( ((char*)v)[0] )
+				linkdb_insert(n, (void*)num, aStrdup(v));
+		}else{
 			pc_setglobalreg_str(sd,name,str);
  		} // [zBuffer]
 
@@ -2425,6 +2478,20 @@ static int set_reg(struct map_session_data *sd,int num,char *name,void *v)
 				pc_setaccountreg2(sd,name,val);
 			else
 				pc_setaccountreg(sd,name,val);
+		}else if(prefix == '\'') {
+			struct linkdb_node **n;
+			if( ref ) {
+				n = ref;
+			} else if( name[1] == '@' ) {
+				n = st->stack->var_function;
+			} else {
+				n = &st->script->script_vars;
+			}
+			if( val == 0 ) {
+				linkdb_erase(n, (void*)num);
+			} else {
+				linkdb_replace(n, (void*)num, (void*)val);
+			}
 		}else{
 			pc_setglobalreg(sd,name,val);
 		}
@@ -2434,7 +2501,7 @@ static int set_reg(struct map_session_data *sd,int num,char *name,void *v)
 
 int set_var(struct map_session_data *sd, char *name, void *val)
 {
-    return set_reg(sd, add_str((unsigned char *) name), name, val);
+    return set_reg(NULL, sd, add_str((unsigned char *) name), name, val, NULL);
 }
 
 /*==========================================
@@ -2495,9 +2562,20 @@ void push_val(struct script_stack *stack,int type,int val)
 //		printf("push (%d,%d)-> %d\n",type,val,stack->sp);
 	stack->stack_data[stack->sp].type=type;
 	stack->stack_data[stack->sp].u.num=val;
+	stack->stack_data[stack->sp].ref   = NULL;
 	stack->sp++;
 }
 
+/*==========================================
+ * スタックへ数値+リファレンスをプッシュ
+ *------------------------------------------
+ */
+
+void push_val2(struct script_stack *stack,int type,int val,struct linkdb_node** ref) {
+	push_val(stack,type,val);
+	stack->stack_data[stack->sp-1].ref = ref;
+}
+
 /*==========================================
  * スタックへ文字列をプッシュ
  *------------------------------------------
@@ -2515,6 +2593,7 @@ void push_str(struct script_stack *stack,int type,unsigned char *str)
 //		printf("push (%d,%x)-> %d\n",type,str,stack->sp);
 	stack->stack_data[stack->sp].type=type;
 	stack->stack_data[stack->sp].u.str=(char *) str;
+	stack->stack_data[stack->sp].ref   = NULL;
 	stack->sp++;
 }
 
@@ -2532,7 +2611,10 @@ void push_copy(struct script_stack *stack,int pos)
 		push_str(stack,C_STR,(unsigned char *) aStrdup(stack->stack_data[pos].u.str));
 		break;
 	default:
-		push_val(stack,stack->stack_data[pos].type,stack->stack_data[pos].u.num);
+		push_val2(
+			stack,stack->stack_data[pos].type,stack->stack_data[pos].u.num,
+			stack->stack_data[pos].ref
+		);
 		break;
 	}
 }
@@ -2556,6 +2638,24 @@ void pop_stack(struct script_stack* stack,int start,int end)
 	stack->sp-=end-start;
 }
 
+/*==========================================
+ * スクリプト依存変数、関数依存変数の解放
+ *------------------------------------------
+ */
+void script_free_vars(struct linkdb_node **node) {
+	struct linkdb_node *n = *node;
+	while(n) {
+		char *name   = str_buf + str_data[(int)(n->key)&0x00ffffff].str;
+		char postfix = name[strlen(name)-1];
+		if( postfix == '$' ) {
+			// 文字型変数なので、データ削除
+			aFree(n->data);
+		}
+		n = n->next;
+	}
+	linkdb_final( node );
+}
+
 /*==========================================
  * Free's the whole stack. Invoked when clearing a character. [Skotlex]
  *------------------------------------------
@@ -2570,12 +2670,24 @@ void script_free_stack(struct script_stack* stack)
 			//ShowDebug ("script_free_stack: freeing %p at sp=%d.\n", stack->stack_data[i].u.str, i);
 			aFree(stack->stack_data[i].u.str);
 			stack->stack_data[i].type = C_INT;
+		}else if( i > 0 && stack->stack_data[i].type == C_RETINFO ) {
+			struct linkdb_node** n = (struct linkdb_node**)stack->stack_data[i-1].u.num;
+			script_free_vars( n );
+			aFree( n );
 		}
 	}
+	script_free_vars( stack->var_function );
+	aFree(stack->var_function);
 	aFree (stack->stack_data);
 	aFree (stack);
 }
 
+void script_free_code(struct script_code* code) {
+	script_free_vars( &code->script_vars );
+	aFree( code->script_buf );
+	aFree( code );
+}
+
 int axtoi(char *hexStg) {
 	int n = 0;         // position in string
 	int m = 0;         // position in digit[] to shift
@@ -2657,23 +2769,41 @@ int buildin_goto(struct script_state *st)
  */
 int buildin_callfunc(struct script_state *st)
 {
-	char *scr;
+	struct script_code *scr, *oldscr;
 	char *str=conv_str(st,& (st->stack->stack_data[st->start+2]));
 
-	if( (scr=(char *) strdb_get(userfunc_db,(unsigned char*)str)) ){
+	if( (scr=(struct script_code *) strdb_get(userfunc_db,(unsigned char*)str)) ){
 		int i,j;
+		struct linkdb_node **oldval = st->stack->var_function;
 		for(i=st->start+3,j=0;i<st->end;i++,j++)
 			push_copy(st->stack,i);
 
 		push_val(st->stack,C_INT,j);				// 引数の数をプッシュ
 		push_val(st->stack,C_INT,st->stack->defsp);	// 現在の基準スタックポインタをプッシュ
 		push_val(st->stack,C_INT,(int)st->script);	// 現在のスクリプトをプッシュ
+		push_val(st->stack,C_INT,(int)st->stack->var_function);	// 現在の関数依存変数をプッシュ
 		push_val(st->stack,C_RETINFO,st->pos);		// 現在のスクリプト位置をプッシュ
 
+		oldscr = st->script;
 		st->pos=0;
 		st->script=scr;
-		st->stack->defsp=st->start+4+j;
+		st->stack->defsp=st->start+5+j;
 		st->state=GOTO;
+		st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
+
+		// ' 変数の引き継ぎ
+		for(i = 0; i < j; i++) {
+			struct script_data *s = &st->stack->stack_data[st->stack->sp-6-i];
+			if( s->type == C_NAME && !s->ref ) {
+				char *name = str_buf+str_data[s->u.num&0x00ffffff].str;
+				// '@ 変数の引き継ぎ
+				if( name[0] == '\'' && name[1] == '@' ) {
+					s->ref = oldval;
+				} else if( name[0] == '\'' ) {
+					s->ref = &oldscr->script_vars;
+				}
+			}
+		}
 	}else{
 		ShowWarning("script:callfunc: function not found! [%s]\n",str);
 		st->state=END;
@@ -2694,17 +2824,32 @@ int buildin_callsub(struct script_state *st)
 		st->state=END;
 		return 1;
 	} else {
+		struct linkdb_node **oldval = st->stack->var_function;
 		for(i=st->start+3,j=0;i<st->end;i++,j++)
 			push_copy(st->stack,i);
 
 		push_val(st->stack,C_INT,j);				// 引数の数をプッシュ
 		push_val(st->stack,C_INT,st->stack->defsp);	// 現在の基準スタックポインタをプッシュ
 		push_val(st->stack,C_INT,(int)st->script);	// 現在のスクリプトをプッシュ
+		push_val(st->stack,C_INT,(int)st->stack->var_function);	// 現在の関数依存変数をプッシュ
 		push_val(st->stack,C_RETINFO,st->pos);		// 現在のスクリプト位置をプッシュ
 
 		st->pos=pos;
-		st->stack->defsp=st->start+4+j;
+		st->stack->defsp=st->start+5+j;
 		st->state=GOTO;
+		st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
+
+		// ' 変数の引き継ぎ
+		for(i = 0; i < j; i++) {
+			struct script_data *s = &st->stack->stack_data[st->stack->sp-6-i];
+			if( s->type == C_NAME && !s->ref ) {
+				char *name = str_buf+str_data[s->u.num&0x00ffffff].str;
+				// '@ 変数の引き継ぎ
+				if( name[0] == '\'' && name[1] == '@' ) {
+					s->ref = oldval;
+				}
+			}
+		}
 	}
 	return 0;
 }
@@ -2717,13 +2862,13 @@ int buildin_getarg(struct script_state *st)
 {
 	int num=conv_num(st,& (st->stack->stack_data[st->start+2]));
 	int max,stsp;
-	if( st->stack->defsp<4 || st->stack->stack_data[st->stack->defsp-1].type!=C_RETINFO ){
+	if( st->stack->defsp<5 || st->stack->stack_data[st->stack->defsp-1].type!=C_RETINFO ){
 		ShowWarning("script:getarg without callfunc or callsub!\n");
 		st->state=END;
 		return 1;
 	}
-	max=conv_num(st,& (st->stack->stack_data[st->stack->defsp-4]));
-	stsp=st->stack->defsp - max -4;
+	max=conv_num(st,& (st->stack->stack_data[st->stack->defsp-5]));
+	stsp=st->stack->defsp - max -5;
 	if( num >= max ){
 		ShowWarning("script:getarg arg1(%d) out of range(%d) !\n",num,max);
 		st->state=END;
@@ -3248,7 +3393,7 @@ int buildin_input(struct script_state *st)
 		if( postfix=='$' ){
 			// 文字列
 			if(st->end>st->start+2){ // 引数1個
-				set_reg(sd,num,name,(void*)sd->npc_str);
+				set_reg(st,sd,num,name,(void*)sd->npc_str,st->stack->stack_data[st->start+2].ref);
 			}else{
 				ShowError("buildin_input: string discarded !!\n");
 				return 1;
@@ -3267,10 +3412,10 @@ int buildin_input(struct script_state *st)
 
 		// 数値
 		if(st->end>st->start+2){ // 引数1個
-			set_reg(sd,num,name,(void*)sd->npc_amount);
+			set_reg(st,sd,num,name,(void*)sd->npc_amount,st->stack->stack_data[st->start+2].ref);
 		} else {
 			// ragemu互換のため
-			pc_setreg(sd,add_str((unsigned char *) "l14"),sd->npc_amount);
+			//pc_setreg(sd,add_str((unsigned char *) "l14"),sd->npc_amount);
 		}
 		return 0;
 	}
@@ -3301,18 +3446,18 @@ int buildin_set(struct script_state *st)
 		return 1;
 	}
 
-	if( prefix!='$' )
+	if( prefix!='$' && prefix!='\'' )
 		sd=script_rid2sd(st);
 
 
 	if( postfix=='$' ){
 		// 文字列
 		char *str = conv_str(st,& (st->stack->stack_data[st->start+3]));
-		set_reg(sd,num,name,(void*)str);
+		set_reg(st,sd,num,name,(void*)str,st->stack->stack_data[st->start+2].ref);
 	}else{
 		// 数値
 		int val = conv_num(st,& (st->stack->stack_data[st->start+3]));
-		set_reg(sd,num,name,(void*)val);
+		set_reg(st,sd,num,name,(void*)val,st->stack->stack_data[st->start+2].ref);
 	}
 
 	return 0;
@@ -3330,11 +3475,11 @@ int buildin_setarray(struct script_state *st)
 	char postfix=name[strlen(name)-1];
 	int i,j;
 
-	if( prefix!='$' && prefix!='@' ){
+	if( prefix!='$' && prefix!='@' && prefix!='\''){
 		ShowWarning("buildin_setarray: illegal scope !\n");
 		return 1;
 	}
-	if( prefix!='$' )
+	if( prefix!='$' && prefix!='\'' )
 		sd=script_rid2sd(st);
 
 	for(j=0,i=st->start+3; i<st->end && j<128;i++,j++){
@@ -3343,7 +3488,7 @@ int buildin_setarray(struct script_state *st)
 			v=(void*)conv_str(st,& (st->stack->stack_data[i]));
 		else
 			v=(void*)conv_num(st,& (st->stack->stack_data[i]));
-		set_reg( sd, num+(j<<24), name, v);
+		set_reg(st, sd, num+(j<<24), name, v, st->stack->stack_data[st->start+2].ref);
 	}
 	return 0;
 }
@@ -3375,7 +3520,7 @@ int buildin_cleararray(struct script_state *st)
 		v=(void*)conv_num(st,& (st->stack->stack_data[st->start+3]));
 
 	for(i=0;i<sz;i++)
-		set_reg(sd,num+(i<<24),name,v);
+		set_reg(st,sd,num+(i<<24),name,v,st->stack->stack_data[st->start+2].ref);
 	return 0;
 }
 /*==========================================
@@ -3396,48 +3541,60 @@ int buildin_copyarray(struct script_state *st)
 	int sz=conv_num(st,& (st->stack->stack_data[st->start+4]));
 	int i;
 
-	if( prefix!='$' && prefix!='@' && prefix2!='$' && prefix2!='@' ){
-		ShowWarning("buildin_copyarray: illegal scope !\n");
-		return 1;
+	if( prefix!='$' && prefix!='@' && prefix!='\'' ){
+		printf("buildin_copyarray: illeagal scope !\n");
+		return 0;
+	}
+	if( prefix2!='$' && prefix2!='@' && prefix2!='\'' ) {
+		printf("buildin_copyarray: illeagal scope !\n");
+		return 0;
 	}
 	if( (postfix=='$' || postfix2=='$') && postfix!=postfix2 ){
-		ShowError("buildin_copyarray: type mismatch !\n");
-		return 1;
+		printf("buildin_copyarray: type mismatch !\n");
+		return 0;
 	}
-	if( prefix!='$' || prefix2!='$' )
+	if( (prefix!='$' && prefix != '\'') || (prefix2!='$' && prefix2 != '\'') )
 		sd=script_rid2sd(st);
 
-	// if two array is the same and (num > num2), bottom-up copy is required [Eoe / jA 1116]
 	if((num & 0x00FFFFFF) == (num2 & 0x00FFFFFF) && (num & 0xFF000000) > (num2 & 0xFF000000)) {
+		// 同じ配列で、num > num2 の場合大きい方からコピーしないといけない
 		for(i=sz-1;i>=0;i--)
-			set_reg(sd,num+(i<<24),name, get_val2(st,num2+(i<<24)) );
+			set_reg(
+				st,sd,num+(i<<24),name,
+				get_val2(st,num2+(i<<24),st->stack->stack_data[st->start+3].ref),
+				st->stack->stack_data[st->start+2].ref
+			);
 	} else {
 		for(i=0;i<sz;i++)
-			set_reg(sd,num+(i<<24),name, get_val2(st,num2+(i<<24)) );
+			set_reg(
+				st,sd,num+(i<<24),name,
+				get_val2(st,num2+(i<<24),st->stack->stack_data[st->start+3].ref),
+				st->stack->stack_data[st->start+2].ref
+			);
 	}
-
 	return 0;
 }
 /*==========================================
  * 配列変数のサイズ所得
  *------------------------------------------
  */
-static int getarraysize(struct script_state *st,int num,int postfix)
+static int getarraysize(struct script_state *st,int num,int postfix,struct linkdb_node** ref)
 {
 	int i=(num>>24),c=(i==0? -1:i); // Moded to -1 because even if the first element is 0, it will still report as 1 [Lance]
 	if(postfix == '$'){
 		for(;i<128;i++){
-			void *v=get_val2(st,(num & 0x00FFFFFF)+(i<<24));
+			void *v=get_val2(st,(num & 0x00FFFFFF)+(i<<24),ref);
 			if(*((char*)v)) c=i;
 		}
 	}else{
 		for(;i<128;i++){
-			void *v=get_val2(st,(num & 0x00FFFFFF)+(i<<24));
+			void *v=get_val2(st,(num & 0x00FFFFFF)+(i<<24),ref);
 			if((int)v) c=i;
 		}
 	}
 	return c+1;
 }
+
 int buildin_getarraysize(struct script_state *st)
 {
 	int num=st->stack->stack_data[st->start+2].u.num;
@@ -3445,12 +3602,12 @@ int buildin_getarraysize(struct script_state *st)
 	char prefix=*name;
 	char postfix=name[strlen(name)-1];
 
-	if( prefix!='$' && prefix!='@' ){
+	if( prefix!='$' && prefix!='@' && prefix!='\'' ){
 		ShowWarning("buildin_copyarray: illegal scope !\n");
 		return 1;
 	}
 
-	push_val(st->stack,C_INT,getarraysize(st,num,postfix) );
+	push_val(st->stack,C_INT,getarraysize(st,num,postfix,st->stack->stack_data[st->start+2].ref));
 	return 0;
 }
 /*==========================================
@@ -3465,7 +3622,7 @@ int buildin_deletearray(struct script_state *st)
 	char prefix=*name;
 	char postfix=name[strlen(name)-1];
 	int count=1;
-	int i,sz=getarraysize(st,num,postfix)-(num>>24)-count+1;
+	int i,sz=getarraysize(st,num,postfix,st->stack->stack_data[st->start+2].ref)-(num>>24)-count+1;
 
 
 	if( (st->end > st->start+3) )
@@ -3479,15 +3636,19 @@ int buildin_deletearray(struct script_state *st)
 		sd=script_rid2sd(st);
 
 	for(i=0;i<sz;i++){
-		set_reg(sd,num+(i<<24),name, get_val2(st,num+((i+count)<<24) ) );
+		set_reg(
+			st,sd,num+(i<<24),name,
+			get_val2(st,num+((i+count)<<24),st->stack->stack_data[st->start+2].ref),
+			st->stack->stack_data[st->start+2].ref
+		);
 	}
 
 	if(postfix != '$'){
 		for(;i<(128-(num>>24));i++)
-			set_reg(sd,num+(i<<24),name, 0);
+			set_reg(st,sd,num+(i<<24),name, 0,st->stack->stack_data[st->start+2].ref);
 	} else {
 		for(;i<(128-(num>>24));i++)
-			set_reg(sd,num+(i<<24),name, (void *) "");
+			set_reg(st,sd,num+(i<<24),name, (void *) "",st->stack->stack_data[st->start+2].ref);
 	}
 	return 0;
 }
@@ -9112,7 +9273,7 @@ int buildin_getmapxy(struct script_state *st){
         else
             sd=NULL;
 
-        set_reg(sd,num,name,(void*)mapname);
+        set_reg(st,sd,num,name,(void*)mapname,NULL);
 
      //Set MapX
         num=st->stack->stack_data[st->start+3].u.num;
@@ -9123,7 +9284,7 @@ int buildin_getmapxy(struct script_state *st){
             sd=script_rid2sd(st);
         else
             sd=NULL;
-        set_reg(sd,num,name,(void*)x);
+        set_reg(st,sd,num,name,(void*)x,NULL);
 
 
      //Set MapY
@@ -9136,7 +9297,7 @@ int buildin_getmapxy(struct script_state *st){
         else
             sd=NULL;
 
-        set_reg(sd,num,name,(void*)y);
+        set_reg(st,sd,num,name,(void*)y,NULL);
 
      //Return Success value
         push_val(st->stack,C_INT,0);
@@ -9726,7 +9887,7 @@ int buildin_distance(struct script_state *st){
 // [zBuffer] List of dynamic var commands --->
 void setd_sub(struct map_session_data *sd, char *varname, int elem, void *value)
 {
-	set_reg(sd, add_str((unsigned char *) varname)+(elem<<24), varname, value);
+	set_reg(NULL, sd, add_str((unsigned char *) varname)+(elem<<24), varname, value, NULL);
 	return;
 }
 
@@ -9980,7 +10141,7 @@ int buildin_setitemscript(struct script_state *st)
 
 	if (i_data && script!=NULL && script[0]=='{') {
 		if(i_data->script!=NULL)
-			aFree(i_data->script);
+			script_free_code(i_data->script);
 		i_data->script = parse_script((unsigned char *) script, 0);
 		push_val(st->stack,C_INT,1);
 	} else
@@ -10542,6 +10703,107 @@ int buildin_mobattach(struct script_state *st){
 }
 
 // <--- [zBuffer] List of mob control commands
+
+// sleep <mili sec>
+int buildin_sleep(struct script_state *st) {
+	int tick = conv_num(st,& (st->stack->stack_data[st->start+2]));
+	struct map_session_data *sd = map_id2sd(st->rid);
+	if(sd && sd->npc_id == st->oid) {
+		sd->npc_id = 0;
+	}
+	st->rid = 0;
+	if(tick <= 0) {
+		// 何もしない
+	} else if( !st->sleep.tick ) {
+		// 初回実行
+		st->state = RERUNLINE;
+		st->sleep.tick = tick;
+	} else {
+		// 続行
+		st->sleep.tick = 0;
+	}
+	return 0;
+}
+
+// sleep2 <mili sec>
+int buildin_sleep2(struct script_state *st) {
+	int tick = conv_num(st,& (st->stack->stack_data[st->start+2]));
+	if( tick <= 0 ) {
+		// 0ms の待機時間を指定された
+		push_val(st->stack,C_INT,map_id2sd(st->rid) != NULL);
+	} else if( !st->sleep.tick ) {
+		// 初回実行時
+		st->state = RERUNLINE;
+		st->sleep.tick = tick;
+	} else {
+		push_val(st->stack,C_INT,map_id2sd(st->rid) != NULL);
+		st->sleep.tick = 0;
+	}
+	return 0;
+}
+
+/*==========================================
+ * 指定NPCの全てのsleepを再開する
+ *------------------------------------------
+ */
+int buildin_awake(struct script_state *st)
+{
+	struct npc_data *nd;
+	struct linkdb_node *node = (struct linkdb_node *)sleep_db;
+
+	nd = npc_name2id(conv_str(st,& (st->stack->stack_data[st->start+2])));
+	if(nd == NULL)
+		return 0;
+
+	while( node ) {
+		if( (int)node->key == nd->bl.id) {
+			struct script_state *tst    = node->data;
+			struct map_session_data *sd = map_id2sd(tst->rid);
+
+			if( tst->sleep.timer == -1 ) {
+				node = node->next;
+				continue;
+			}
+			if( sd && sd->char_id != tst->sleep.charid )
+				tst->rid = 0;
+
+			delete_timer(tst->sleep.timer, run_script_timer);
+			node = script_erase_sleepdb(node);
+			tst->sleep.timer = -1;
+			run_script_main(tst);
+		} else {
+			node = node->next;
+		}
+	}
+	return 0;
+}
+
+// getvariableofnpc(<param>, <npc name>);
+int buildin_getvariableofnpc(struct script_state *st)
+{
+	if( st->stack->stack_data[st->start+2].type != C_NAME ) {
+		// 第一引数が変数名じゃない
+		printf("getvariableofnpc: param not name\n");
+		push_val(st->stack,C_INT,0);
+	} else {
+		int num = st->stack->stack_data[st->start+2].u.num;
+		char *var_name = str_buf+str_data[num&0x00ffffff].str;
+		char *npc_name = conv_str(st,& (st->stack->stack_data[st->start+3]));
+		struct npc_data *nd = npc_name2id(npc_name);
+		if( var_name[0] != '\'' || var_name[1] == '@' ) {
+			// ' 変数以外はダメ
+			printf("getvariableofnpc: invalid scope %s\n", var_name);
+			push_val(st->stack,C_INT,0);
+		} else if( nd == NULL || nd->bl.subtype != SCRIPT || !nd->u.scr.script) {
+			// NPC が見つからない or SCRIPT以外のNPC
+			printf("getvariableofnpc: can't find npc %s\n", npc_name);
+			push_val(st->stack,C_INT,0);
+		} else {
+			push_val2(st->stack,C_NAME,num, &nd->u.scr.script->script_vars );
+		}
+	}
+	return 0;
+}
 //
 // 実行部main
 //
@@ -10913,18 +11175,21 @@ int run_func(struct script_state *st)
 		int i;
 
 		pop_stack(st->stack,st->stack->defsp,start_sp);	// 復帰に邪魔なスタック削除
-		if(st->stack->defsp<4 || st->stack->stack_data[st->stack->defsp-1].type!=C_RETINFO){
+		if(st->stack->defsp<5 || st->stack->stack_data[st->stack->defsp-1].type!=C_RETINFO){
 			ShowWarning("script:run_func(return) return without callfunc or callsub!\n");
 			st->state=END;
 			report_src(st);
 			return 1;
 		}
-		i = conv_num(st,& (st->stack->stack_data[st->stack->defsp-4]));					// 引数の数所得
+		script_free_vars( st->stack->var_function );
+		aFree(st->stack->var_function);
+		i = conv_num(st,& (st->stack->stack_data[st->stack->defsp-5]));					// 引数の数所得
 		st->pos=conv_num(st,& (st->stack->stack_data[st->stack->defsp-1]));				// スクリプト位置の復元
-		st->script=(char*)conv_num(st,& (st->stack->stack_data[st->stack->defsp-2]));	// スクリプトを復元
-		st->stack->defsp=conv_num(st,& (st->stack->stack_data[st->stack->defsp-3]));	// 基準スタックポインタを復元
+		st->script=(struct script_code *)conv_num(st,& (st->stack->stack_data[st->stack->defsp-3]));	// スクリプトを復元
+		st->stack->var_function = (struct linkdb_node**)st->stack->stack_data[st->stack->defsp-2].u.num; // 関数依存変数
+		st->stack->defsp=conv_num(st,& (st->stack->stack_data[st->stack->defsp-4]));	// 基準スタックポインタを復元
 
-		pop_stack(st->stack,olddefsp-4-i,olddefsp);		// 要らなくなったスタック(引数と復帰用データ)削除
+		pop_stack(st->stack,olddefsp-5-i,olddefsp);		// 要らなくなったスタック(引数と復帰用データ)削除
 
 		st->state=GOTO;
 	}
@@ -10942,6 +11207,7 @@ int run_script_main(struct script_state *st)
 	int cmdcount=script_config.check_cmdcount;
 	int gotocount=script_config.check_gotocount;
 	struct script_stack *stack=st->stack;
+	TBL_PC *sd=NULL;
 
 	if(st->state == RERUNLINE) {
 		st->state = RUN;
@@ -10953,7 +11219,7 @@ int run_script_main(struct script_state *st)
 		st->state = RUN;
 	}
 	while( st->state == RUN) {
-		c= get_com((unsigned char *) st->script,&st->pos);
+		c= get_com((unsigned char *) st->script->script_buf,&st->pos);
 		switch(c){
 		case C_EOL:
 			if(stack->sp!=stack->defsp){
@@ -10970,19 +11236,19 @@ int run_script_main(struct script_state *st)
 			// rerun_pos=st->pos;
 			break;
 		case C_INT:
-			push_val(stack,C_INT,get_num((unsigned char *) st->script,&st->pos));
+			push_val(stack,C_INT,get_num((unsigned char *) st->script->script_buf,&st->pos));
 			break;
 		case C_POS:
 		case C_NAME:
-			push_val(stack,c,(*(int*)(st->script+st->pos))&0xffffff);
+			push_val(stack,c,(*(int*)(st->script->script_buf+st->pos))&0xffffff);
 			st->pos+=3;
 			break;
 		case C_ARG:
 			push_val(stack,c,0);
 			break;
 		case C_STR:
-			push_str(stack,C_CONSTSTR,(unsigned char *) (st->script+st->pos));
-			while(st->script[st->pos++]);
+			push_str(stack,C_CONSTSTR,(unsigned char *) (st->script->script_buf+st->pos));
+			while(st->script->script_buf[st->pos++]);
 			break;
 		case C_FUNC:
 			run_func(st);
@@ -11041,31 +11307,40 @@ int run_script_main(struct script_state *st)
 			st->state=END;
 		}
 	}
-	switch(st->state){
-	case STOP:
-		break;
-	case END:
-		{
-			struct map_session_data *sd=map_id2sd(st->rid);
-			st->pos=-1;
-			if(sd && (sd->npc_id==st->oid || sd->state.using_fake_npc)){
-				if(sd->state.using_fake_npc){
-					clif_clearchar_id(sd->npc_id, 0, sd->fd);
-					sd->state.using_fake_npc = 0;
+	sd = map_id2sd(st->rid);
+	if(st->sleep.tick > 0) {
+		// スタック情報をsleep_dbに保存
+		unsigned int tick = gettick()+st->sleep.tick;
+		st->sleep.charid = sd ? sd->char_id : 0;
+		st->sleep.timer  = add_timer(tick, run_script_timer, st->sleep.charid, (int)st);
+		linkdb_insert(&sleep_db, (void*)st->oid, st);
+	} else {
+		switch(st->state){
+		case STOP:
+			break;
+		case END:
+			{
+				struct map_session_data *sd=map_id2sd(st->rid);
+				st->pos=-1;
+				if(sd && (sd->npc_id==st->oid || sd->state.using_fake_npc)){
+					if(sd->state.using_fake_npc){
+						clif_clearchar_id(sd->npc_id, 0, sd->fd);
+						sd->state.using_fake_npc = 0;
+					}
+					npc_event_dequeue(sd);
 				}
-				npc_event_dequeue(sd);
 			}
+			break;
+		case RERUNLINE:
+			// Do not call function of commands two time! [ Eoe / jA 1094 ]
+			// For example: select "1", "2", callsub(...);
+			// If current script position is changed, callsub will be called two time.
+			// 
+			// {
+			// 	st->pos=rerun_pos;
+			// }
+			break;
 		}
-		break;
-	case RERUNLINE:
-		// Do not call function of commands two time! [ Eoe / jA 1094 ]
-		// For example: select "1", "2", callsub(...);
-		// If current script position is changed, callsub will be called two time.
-		// 
-		// {
-		// 	st->pos=rerun_pos;
-		// }
-		break;
 	}
 
 	return 0;
@@ -11075,20 +11350,20 @@ int run_script_main(struct script_state *st)
  * スクリプトの実行
  *------------------------------------------
  */
-int run_script(unsigned char *script,int pos,int rid,int oid)
+int run_script(struct script_code *rootscript,int pos,int rid,int oid)
 {
 	struct script_state st;
-	struct map_session_data *sd;
-	unsigned char *rootscript = script;
+	struct map_session_data *sd=NULL;
 
 	//Variables for backing up the previous script and restore it if needed. [Skotlex]
-	unsigned char *bck_script = NULL;
-	unsigned char *bck_scriptroot = NULL;
+	struct script_code *bck_script = NULL;
+	struct script_code *bck_scriptroot = NULL;
 	int bck_scriptstate = 0;
 	struct script_stack *bck_stack = NULL;
 	
-	if (script == NULL || pos < 0)
+	if (rootscript == NULL || pos < 0)
 		return -1;
+
 	memset(&st, 0, sizeof(struct script_state));
 
 	if ((sd = map_id2sd(rid)) && sd->stack && sd->npc_scriptroot == rootscript){
@@ -11108,6 +11383,7 @@ int run_script(unsigned char *script,int pos,int rid,int oid)
 		st.stack->sp_max = 64;
 		st.stack->stack_data = (struct script_data *) aCalloc (st.stack->sp_max,sizeof(st.stack->stack_data[0]));
 		st.stack->defsp = st.stack->sp;
+		st.stack->var_function = aCalloc(1, sizeof(struct linkdb_node*));
 		st.state  = RUN;
 		st.script = rootscript;
 	
@@ -11122,6 +11398,7 @@ int run_script(unsigned char *script,int pos,int rid,int oid)
 	st.pos = pos;
 	st.rid = rid;
 	st.oid = oid;
+	st.sleep.timer = -1;
 	// let's run that stuff
 	run_script_main(&st);
 
@@ -11155,6 +11432,57 @@ int run_script(unsigned char *script,int pos,int rid,int oid)
 	return st.pos;
 }
 
+/*==========================================
+ * 指定ノードをsleep_dbから削除
+ *------------------------------------------
+ */
+/*==========================================
+ * 指定ノードをsleep_dbから削除
+ *------------------------------------------
+ */
+struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n)
+{
+	struct linkdb_node *retnode;
+
+	if( n == NULL)
+		return NULL;
+	if( n->prev == NULL )
+		sleep_db = n->next;
+	else
+		n->prev->next = n->next;
+	if( n->next )
+		n->next->prev = n->prev;
+	retnode = n->next;
+	aFree( n );
+	return retnode;		// 次のノードを返す
+}
+
+
+/*==========================================
+ * sleep用タイマー関数
+ *------------------------------------------
+ */
+int run_script_timer(int tid, unsigned int tick, int id, int data)
+{
+	struct script_state *st     = (struct script_state *)data;
+	struct linkdb_node *node    = (struct linkdb_node *)sleep_db;
+	struct map_session_data *sd = map_id2sd(st->rid);
+
+	if( sd && sd->char_id != id ) {
+		st->rid = 0;
+	}
+	while( node && st->sleep.timer != -1 ) {
+		if( (int)node->key == st->oid && ((struct script_state *)node->data)->sleep.timer == st->sleep.timer ) {
+			script_erase_sleepdb(node);
+			st->sleep.timer = -1;
+			break;
+		}
+		node = node->next;
+	}
+	run_script_main(st);
+	return 0;
+}
+
 
 /*==========================================
  * マップ変数の変更
@@ -11567,6 +11895,16 @@ int do_final_script()
 	mapregstr_db->destroy(mapregstr_db,NULL);
 	scriptlabel_db->destroy(scriptlabel_db,NULL);
 	userfunc_db->destroy(userfunc_db,NULL);
+	if(sleep_db) {
+		struct linkdb_node *n = (struct linkdb_node *)sleep_db;
+		while(n) {
+			struct script_state *st = (struct script_state *)n->data;
+			script_free_stack(st->stack);
+			free(st);
+			n = n->next;
+		}
+		linkdb_final(&sleep_db);
+	}
 
 	if (str_data)
 		aFree(str_data);

+ 18 - 3
src/map/script.h

@@ -35,30 +35,45 @@ struct script_data {
 		int num;
 		char *str;
 	} u;
+	struct linkdb_node** ref; // リファレンス
 };
 
 // Moved defsp from script_state to script_stack since
 // it must be saved when script state is RERUNLINE. [Eoe / jA 1094]
+struct script_code {
+	int script_size;
+	unsigned char* script_buf;
+	struct linkdb_node* script_vars;
+};
 struct script_stack {
 	int sp,sp_max,defsp;
 	struct script_data *stack_data;
+	struct linkdb_node **var_function;	// 関数依存変数
 };
 struct script_state {
 	struct script_stack *stack;
 	int start,end;
 	int pos,state;
 	int rid,oid;
-	unsigned char *script,*new_script;
+	//unsigned char *script,*new_script;
 	int new_pos,new_defsp;
+	struct script_code *script, *scriptroot;
+	struct sleep_data {
+		int tick,timer,charid;
+	} sleep;
 };
 
-unsigned char * parse_script(unsigned char *,int);
-int run_script(unsigned char *,int,int,int);
+struct script_code *parse_script(unsigned char *,int);
+int run_script(struct script_code *rootscript,int pos,int rid,int oid);
 
 int set_var(struct map_session_data *sd, char *name, void *val);
 int conv_num(struct script_state *st,struct script_data *data);
 char* conv_str(struct script_state *st,struct script_data *data);
 void setd_sub(struct map_session_data *sd, char *varname, int elem, void *value);
+int run_script_timer(int tid, unsigned int tick, int id, int data);
+int run_script_main(struct script_state *st);
+struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n);
+void script_free_code(struct script_code* code);
 
 struct dbt* script_get_label_db(void);
 struct dbt* script_get_userfunc_db(void);