From de7175c5bc24b6e8f3b87540ae93f40a75df2df2 Mon Sep 17 00:00:00 2001 From: Lance Date: Mon, 22 May 2006 12:15:49 +0000 Subject: * WARNING: New scripting system contains memory leak TODO: Free all scripts using script_free_code() instead of old methods. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@6690 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/common/db.c | 104 +++++++++++ src/common/db.h | 14 ++ src/map/itemdb.c | 20 +-- src/map/itemdb.h | 6 +- src/map/map.h | 4 +- src/map/npc.c | 10 +- src/map/pc.c | 2 +- src/map/pet.h | 2 +- src/map/script.c | 512 +++++++++++++++++++++++++++++++++++++++++++++---------- src/map/script.h | 21 ++- 10 files changed, 584 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/common/db.c b/src/common/db.c index 65abecea7..ebb5b9a30 100644 --- a/src/common/db.c +++ b/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; +} + diff --git a/src/common/db.h b/src/common/db.h index dcc583bfa..0b6fc08c5 100644 --- a/src/common/db.h +++ b/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 diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 4f6079f3a..603f20849 100644 --- a/src/map/itemdb.c +++ b/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; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 35ca82972..b2ffae352 100644 --- a/src/map/itemdb.h +++ b/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; diff --git a/src/map/map.h b/src/map/map.h index 79474cc63..19b039b06 100644 --- a/src/map/map.h +++ b/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; diff --git a/src/map/npc.c b/src/map/npc.c index d503d011a..4278d8d27 100644 --- a/src/map/npc.c +++ b/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]; diff --git a/src/map/pc.c b/src/map/pc.c index db86df518..510e747e6 100644 --- a/src/map/pc.c +++ b/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); diff --git a/src/map/pet.h b/src/map/pet.h index 9517fb37b..8278ce9d8 100644 --- a/src/map/pet.h +++ b/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]; diff --git a/src/map/script.c b/src/map/script.c index 4e184f322..413468eb7 100644 --- a/src/map/script.c +++ b/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;iend;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;iend;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; iend && 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;istack->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;istack->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;istack->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 +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 +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(, ); +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); diff --git a/src/map/script.h b/src/map/script.h index 61803da89..109ab7690 100644 --- a/src/map/script.h +++ b/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); -- cgit v1.2.3-60-g2f50