diff options
-rw-r--r-- | Changelog-Trunk.txt | 6 | ||||
-rw-r--r-- | src/common/strlib.c | 20 | ||||
-rw-r--r-- | src/common/strlib.h | 4 | ||||
-rw-r--r-- | src/map/atcommand.c | 5 | ||||
-rw-r--r-- | src/map/clif.c | 15 | ||||
-rw-r--r-- | src/map/clif.h | 2 | ||||
-rw-r--r-- | src/map/map.h | 2 | ||||
-rw-r--r-- | src/map/npc.c | 892 | ||||
-rw-r--r-- | src/map/npc.h | 5 | ||||
-rw-r--r-- | src/map/script.c | 20 | ||||
-rw-r--r-- | src/map/script.h | 7 |
11 files changed, 490 insertions, 488 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index cd434a8e3..5ccc9516a 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,12 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2007/10/17 + * Reworked the parsing at npc.c. + - Fixes npc.c discarding the '}' at the end of file, when there is no + newline. (uncovered as a side-effect of r11487) + * Empty script functions always have code now (won't report as missing + when you try to call them). + * Changed userfunc_db to not limit the name to 50 characters. [FlavioJS] * Ground skill now can trigger every 20ms [Playtester] - Firewall, Fire Formation and Heat now can do 50 hits a second - this was proven to be official behavior, but it will raise CPU usage diff --git a/src/common/strlib.c b/src/common/strlib.c index c0a6238f9..d0b312f0a 100644 --- a/src/common/strlib.c +++ b/src/common/strlib.c @@ -316,6 +316,26 @@ size_t safestrnlen(const char* string, size_t maxlen) return ( string != NULL ) ? strnlen(string, maxlen) : 0; } +/// Returns the line of the target position in the string. +/// Lines start at 1. +int strline(const char* str, size_t pos) +{ + const char* target; + int line; + + if( str == NULL || pos == 0 ) + return 1; + + target = str+pos; + for( line = 1; ; ++line ) + { + str = strchr(str, '\n'); + if( str == NULL || target <= str ) + break;// found target line + ++str;// skip newline + } + return line; +} ///////////////////////////////////////////////////////////////////// // StringBuf - dynamic string diff --git a/src/common/strlib.h b/src/common/strlib.h index fd24b4b24..4df5a51d2 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -37,6 +37,10 @@ char* safestrncpy(char* dst, const char* src, size_t n); /// doesn't crash on null pointer size_t safestrnlen(const char* string, size_t maxlen); +/// Returns the line of the target position in the string. +/// Lines start at 1. +int strline(const char* str, size_t pos); + /// StringBuf - dynamic string struct StringBuf { diff --git a/src/map/atcommand.c b/src/map/atcommand.c index d5a3442e7..d5a51e933 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -6321,7 +6321,7 @@ int atcommand_npcmove(const int fd, struct map_session_data* sd, const char* com int atcommand_addwarp(const int fd, struct map_session_data* sd, const char* command, const char* message) { char w1[64], w3[64], w4[64]; - int x,y,ret; + int x,y,ret=0; nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%23s %d %d[^\n]", atcmd_player_name, &x, &y) < 3) { @@ -6333,7 +6333,8 @@ int atcommand_addwarp(const int fd, struct map_session_data* sd, const char* com sprintf(w3,"%s%d%d%d%d", atcmd_player_name,sd->bl.x, sd->bl.y, x, y); sprintf(w4,"1,1,%s.gat,%d,%d", atcmd_player_name, x, y); - ret = npc_parse_warp(w1, "warp", w3, w4); + // FIXME check if it failed [FlavioJS] + npc_parse_warp(w1, "warp", w3, w4, NULL, NULL, "console"); sprintf(atcmd_output, "New warp NPC => %s",w3); diff --git a/src/map/clif.c b/src/map/clif.c index 58db07b2a..1e3bcca1f 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -5492,10 +5492,15 @@ void clif_vendingreport(struct map_session_data* sd, int index, int amount) WFIFOW(fd,4) = amount; WFIFOSET(fd,packet_len(0x137)); } -/*========================================== - * パーティ作成完了 - *------------------------------------------*/ -int clif_party_created(struct map_session_data *sd,int flag) + +/// Result of organizing a party. +/// S 00FA <result>.B +/// +/// result=0 : opens party window and shows MsgStringTable[77]="party successfully organized" +/// result=1 : MsgStringTable[78]="party name already exists" +/// result=2 : MsgStringTable[79]="already in a party" +/// result=other : nothing +int clif_party_created(struct map_session_data *sd,int result) { int fd; @@ -5504,7 +5509,7 @@ int clif_party_created(struct map_session_data *sd,int flag) fd=sd->fd; WFIFOHEAD(fd,packet_len(0xfa)); WFIFOW(fd,0)=0xfa; - WFIFOB(fd,2)=flag; + WFIFOB(fd,2)=result; WFIFOSET(fd,packet_len(0xfa)); return 0; } diff --git a/src/map/clif.h b/src/map/clif.h index d809b854d..8406bd9f7 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -270,7 +270,7 @@ void clif_vendingreport(struct map_session_data* sd, int index, int amount); int clif_movetoattack(struct map_session_data *sd,struct block_list *bl); // party -int clif_party_created(struct map_session_data *sd,int flag); +int clif_party_created(struct map_session_data *sd,int result); int clif_party_member_info(struct party_data *p, struct map_session_data *sd); int clif_party_info(struct party_data *p, struct map_session_data *sd); int clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd); diff --git a/src/map/map.h b/src/map/map.h index 2fbb7ffed..c3a90cb81 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -850,7 +850,7 @@ struct npc_data { struct npc_label_list *label_list; int src_id; } scr; - struct npc_item_list shop_item[1]; + struct npc_item_list shop_item[1];// dynamic array, allocated with extra entries (last one has nameid 0) struct { short xs,ys; short x,y; diff --git a/src/map/npc.c b/src/map/npc.c index 35515e33c..29eff176b 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -47,7 +47,6 @@ static int npc_script=0; static int npc_mob=0; static int npc_delay_mob=0; static int npc_cache_mob=0; -const char *current_file = NULL; int npc_get_new_npc_id(void){ return npc_id++; } static struct dbt *ev_db; @@ -1420,31 +1419,32 @@ void npc_delsrcfile(const char* name) } } -/*========================================== - * warp行解析 - *------------------------------------------*/ -int npc_parse_warp(char* w1, char* w2, char* w3, char* w4) +/// Parses a warp npc. +const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { int x, y, xs, ys, to_x, to_y, m; - int i; - char mapname[MAP_NAME_LENGTH_EXT], to_mapname[MAP_NAME_LENGTH_EXT]; + unsigned short i; + char mapname[32], to_mapname[32]; struct npc_data *nd; - // 引数の個数チェック - if (sscanf(w1, "%15[^,],%d,%d", mapname, &x, &y) != 3 || - sscanf(w4, "%d,%d,%15[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5) { - ShowError("bad warp line : %s\n", w3); - return 1; + // w1=<from map name>,<fromX>,<fromY>,<facing> + // w4=<spanx>,<spany>,<to map name>,<toX>,<toY> + if( sscanf(w1, "%31[^,],%d,%d", mapname, &x, &y) != 3 + || sscanf(w4, "%d,%d,%31[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5 ) + { + ShowError("npc_parse_warp: Invalid warp definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue } m = map_mapname2mapid(mapname); i = mapindex_name2id(to_mapname); - if (!i) { - ShowError("bad warp line (destination map not found): %s\n", w3); - return 1; + if( i == 0 ) + { + ShowError("npc_parse_warp: Unknown destination map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), to_mapname, w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue } - - nd = (struct npc_data *) aCalloc (1, sizeof(struct npc_data)); + + CREATE(nd, struct npc_data, 1); nd->bl.id = npc_get_new_npc_id(); nd->n = map_addnpc(m, nd); @@ -1452,16 +1452,16 @@ int npc_parse_warp(char* w1, char* w2, char* w3, char* w4) nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; - strncpy(nd->name, w3, NAME_LENGTH); - strncpy(nd->exname, w3, NAME_LENGTH); + safestrncpy(nd->name, w3, sizeof(nd->name)); + safestrncpy(nd->exname, w3, sizeof(nd->exname)); if (!battle_config.warp_point_debug) nd->class_ = WARP_CLASS; else nd->class_ = WARP_DEBUG_CLASS; nd->speed = 200; - - nd->u.warp.mapindex = (short)i; + + nd->u.warp.mapindex = i; xs += 2; ys += 2; nd->u.warp.x = to_x; @@ -1479,83 +1479,83 @@ int npc_parse_warp(char* w1, char* w2, char* w3, char* w4) clif_spawn(&nd->bl); strdb_put(npcname_db, nd->name, nd); - return 0; + return strchr(start,'\n');// continue } -/*========================================== - * shop行解析 - *------------------------------------------*/ -static int npc_parse_shop(char* w1, char* w2, char* w3, char* w4) +/// Parses a shop npc. +static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { #define MAX_SHOPITEM 100 + struct npc_item_list items[MAX_SHOPITEM]; char *p; - int x, y, dir, m, pos = 0; + int x, y, dir, m, i; struct npc_data *nd; - if (strcmp(w1, "-") == 0) { + if( strcmp(w1,"-") == 0 ) + {// 'floating' shop? x = 0; y = 0; dir = 0; m = -1; - } else { - // 引数の個数チェック - char mapname[MAP_NAME_LENGTH_EXT]; - if (sscanf(w1, "%15[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 || strchr(w4, ',') == NULL) { - ShowError("bad shop line : %s\n", w3); - return 1; + } + else + {// w1=<map name>,<x>,<y>,<facing> + char mapname[32]; + if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 + || strchr(w4, ',') == NULL ) + { + ShowError("npc_parse_shop: Invalid shop definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue } m = map_mapname2mapid(mapname); } - nd = (struct npc_data *) aCalloc (1, sizeof(struct npc_data) + sizeof(nd->u.shop_item[0]) * (MAX_SHOPITEM + 1)); - p = strchr(w4, ','); - - while (p && pos < MAX_SHOPITEM) + p = strchr(w4,','); + for( i = 0; i < ARRAYLENGTH(items) && p; ++i ) { int nameid, value; - struct item_data *id; - p++; - if (sscanf(p, "%d:%d", &nameid, &value) != 2) + struct item_data* id; + if( sscanf(p, ",%d:%d", &nameid, &value) != 2 ) + { + ShowError("npc_parse_shop: Invalid item definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); break; - nd->u.shop_item[pos].nameid = nameid; + } id = itemdb_search(nameid); - if (value < 0) + if( value < 0 ) value = id->value_buy; - nd->u.shop_item[pos].value = value; - // check for bad prices that can possibly cause exploits - if (value/124. < id->value_sell/75.) { //Clened up formula to prevent overflows. - if (value < id->value_sell) - ShowWarning ("Item %s [%d] buying price (%d) is less than selling price (%d) at %s\n", - id->name, id->nameid, value, id->value_sell, current_file); - else - ShowWarning ("Item %s [%d] discounted buying price (%d) is less than overcharged selling price (%d) at %s\n", - id->name, id->nameid, value/100*75, id->value_sell/100*124, current_file); + if( value*0.75 < id->value_sell*1.24 ) + {// Expoit possible: you can buy and sell back with profit + ShowWarning("npc_parse_shop: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n", + id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer)); } //for logs filters, atcommands and iteminfo script command - if (id->maxchance<=0) + if( id->maxchance <= 0 ) id->maxchance = 10000; //10000 (100% drop chance)would show that the item's sold in NPC Shop - pos++; - p = strchr(p, ','); + items[i].nameid = nameid; + items[i].value = value; + p = strchr(p+1,','); } - if (pos == 0) { - aFree(nd); - return 1; + if( i == 0 ) + { + ShowWarning("npc_parse_shop: Ignoring empty shop in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// continue } - nd->u.shop_item[pos++].nameid = 0; + nd = (struct npc_data *) aCalloc (1, sizeof(struct npc_data) + sizeof(nd->u.shop_item[0])*(i)); + memcpy(&nd->u.shop_item, items, sizeof(struct npc_item_list)*i); + nd->u.shop_item[i].nameid = 0; nd->bl.prev = nd->bl.next = NULL; nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; nd->bl.id = npc_get_new_npc_id(); - safestrncpy(nd->name, w3, NAME_LENGTH); + safestrncpy(nd->name, w3, sizeof(nd->name)); nd->class_ = m==-1?-1:atoi(w4); nd->speed = 200; - - nd = (struct npc_data *)aRealloc(nd, sizeof(struct npc_data) + sizeof(nd->u.shop_item[0]) * pos); - npc_shop++; + ++npc_shop; nd->bl.type = BL_NPC; nd->bl.subtype = SHOP; - if (m >= 0) { + if( m >= 0 ) + {// normal shop npc nd->n = map_addnpc(m,nd); map_addblock(&nd->bl); status_set_viewdata(&nd->bl, nd->class_); @@ -1564,11 +1564,12 @@ static int npc_parse_shop(char* w1, char* w2, char* w3, char* w4) nd->ud.dir = dir; clif_spawn(&nd->bl); } else - // we skip map_addnpc, but still add it to the list of ID's + {// 'floating' shop? map_addiddb(&nd->bl); - strdb_put(npcname_db, nd->name,nd); + } + strdb_put(npcname_db, nd->name, nd); - return 0; + return strchr(start,'\n');// continue } /*========================================== @@ -1576,256 +1577,218 @@ static int npc_parse_shop(char* w1, char* w2, char* w3, char* w4) *------------------------------------------*/ int npc_convertlabel_db(DBKey key, void* data, va_list ap) { - const char *lname = (const char*)key.str; - int pos = (int)data; - struct npc_data *nd; - struct npc_label_list *lst; - int num; + const char* lname = (const char*)key.str; + int lpos = (int)data; + struct npc_label_list** label_list; + int* label_list_num; + const char* filepath; + struct npc_label_list* label; const char *p; int len; nullpo_retr(0, ap); - nullpo_retr(0, nd = va_arg(ap,struct npc_data *)); + nullpo_retr(0, label_list = va_arg(ap,struct npc_label_list**)); + nullpo_retr(0, label_list_num = va_arg(ap,int*)); + nullpo_retr(0, filepath = va_arg(ap,const char*)); - lst = nd->u.scr.label_list; - num = nd->u.scr.label_list_num; - if (!lst) { - lst = (struct npc_label_list *) aCallocA (1, sizeof(struct npc_label_list)); - num = 0; + if( *label_list == NULL ) + { + *label_list = (struct npc_label_list *) aCallocA (1, sizeof(struct npc_label_list)); + *label_list_num = 0; } else - lst = (struct npc_label_list *) aRealloc (lst, sizeof(struct npc_label_list)*(num+1)); + *label_list = (struct npc_label_list *) aRealloc (*label_list, sizeof(struct npc_label_list)*(*label_list_num+1)); + label = *label_list+*label_list_num; // In case of labels not terminated with ':', for user defined function support p = lname; while( ISALNUM(*p) || *p == '_' ) - p++; + ++p; len = p-lname; // here we check if the label fit into the buffer - if (len > 23) { - ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, current_file); + if( len > 23 ) + { + ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, filepath); exit(EXIT_FAILURE); } - safestrncpy(lst[num].name, lname, NAME_LENGTH); - lst[num].pos = pos; - nd->u.scr.label_list = lst; - nd->u.scr.label_list_num = num+1; + safestrncpy(label->name, lname, sizeof(label->name)); + label->pos = lpos; + ++(*label_list_num); return 0; } -/*========================================== - * parses a script line - *------------------------------------------*/ -static void npc_parse_script_line(char* p, int* curly_count, int line) +// Skip the contents of a script. +static const char* npc_skip_script(const char* start, const char* buffer, const char* filepath) { - int i = strlen(p),j; - int string_flag = 0; - static int comment_flag = 0; - for(j = 0; j < i; j++) + const char* p; + int curly_count; + + if( start == NULL ) + return NULL;// nothing to skip + + // initial bracket (assumes the previous part is ok) + p = strchr(start,'{'); + if( p == NULL ) { - if(comment_flag) { - if(p[j] == '*' && p[j+1] == '/') { // end of multiline comment - (*curly_count)--; - comment_flag = 0; - j++; - } - } else if(string_flag) { - if(p[j] == '"') { - string_flag = 0; - } else if(p[j] == '\\' && (unsigned char)(p[j-1])<=0x7e) { // escape - j++; - } - } else { - if(p[j] == '"') { - string_flag = 1; - } else if(p[j] == '}') { - if(*curly_count == 0) { - break; - } else { - (*curly_count)--; + ShowError("npc_skip_script: Missing left curly in file '%s', line'%d'.", filepath, strline(buffer,start-buffer)); + return NULL;// can't continue + } + + // skip everything + for( curly_count = 1; curly_count > 0 ; ) + { + p = skip_space(p+1) ; + if( *p == '}' ) + {// right curly + --curly_count; + } + else if( *p == '{' ) + {// left curly + ++curly_count; + } + else if( *p == '"' ) + {// string + for( ++p; *p != '"' ; ++p ) + { + if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) + ++p;// escape sequence (not part of a multibyte character) + else if( *p == '\0' ) + { + script_error(buffer, filepath, 0, "Unexpected end of string.", p); + return NULL;// can't continue + } + else if( *p == '\n' ) + { + script_error(buffer, filepath, 0, "Unexpected newline at string.", p); + return NULL;// can't continue } - } else if(p[j] == '{') { - (*curly_count)++; - } else if(p[j] == '/' && p[j+1] == '/') { // comment - break; - } else if(p[j] == '/' && p[j+1] == '*') { // multiline comment start - (*curly_count)++; - comment_flag = 1; - j++; } } + else if( *p == '\0' ) + {// end of buffer + ShowError("Missing %d right curlys at file '%s', line '%d'.\n", curly_count, filepath, strline(buffer,p-buffer)); + return NULL;// can't continue + } } - if(string_flag) { - printf("Missing '\"' at file %s line %d\n", current_file, line); - exit(EXIT_FAILURE); - } -} -// Like npc_parse_script, except it's sole use is to skip the contents of a script. [Skotlex] -static int npc_skip_script(char* w1, char* w2, char* w3, char* w4, char* first_line, FILE* fp, int* lines) -{ - char *srcbuf = NULL; - int srcsize = 65536; - int startline = 0; - char line[1024]; - int curly_count = 0; - - srcbuf = (char *)aMallocA(srcsize*sizeof(char)); - if (strchr(first_line, '{')) { - strcpy(srcbuf, strchr(first_line, '{')); - startline = *lines; - } else - srcbuf[0] = 0; - npc_parse_script_line(srcbuf,&curly_count,*lines); - while (curly_count > 0) { - fgets(line, sizeof(line), fp); - (*lines)++; - npc_parse_script_line(line,&curly_count,*lines); - if (feof(fp)) - break; - if (strlen(srcbuf) + strlen(line) + 1 >= (size_t)srcsize) { - srcsize += 65536; - srcbuf = (char *)aRealloc(srcbuf, srcsize); - memset(srcbuf + srcsize - 65536, '\0', 65536); - } - if (srcbuf[0] != '{') { - if (strchr(line, '{')) { - strcpy(srcbuf, strchr(line, '{')); - startline = *lines; - } - } else - strcat(srcbuf, line); - } - if(curly_count > 0) - ShowError("Missing right curly at file %s, line %d\n",current_file, *lines); - aFree(srcbuf); - return 0; + return p+1;// return after the last '}' } -static int npc_parse_script(char* w1, char* w2, char* w3, char* w4, char* first_line, FILE* fp, int* lines, const char* file) +static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0; // [Valaris] thanks to fov - char mapname[MAP_NAME_LENGTH_EXT]; - char *srcbuf = NULL; + char mapname[32]; struct script_code *script; - int srcsize = 65536; - int startline = 0; - char line[1024]; int i; - struct npc_data *nd, *dnd; - DB label_db; char *p; - struct npc_label_list *label_dup = NULL; - int label_dupnum = 0; - int src_id = 0; - if (strcmp(w1, "-") == 0) { - x = 0; y = 0; m = -1; - } else { - // 引数の個数チェック - if (sscanf(w1, "%15[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 || - (strcmp(w2, "script") == 0 && strchr(w4,',') == NULL)) { - ShowError("bad script line (in file %s): %s\n", file, w3); - return 1; + struct npc_label_list* label_list; + int label_list_num; + int src_id; + struct npc_data* nd; + struct npc_data* dnd; + + if( strcmp(w1, "-") == 0 ) + {// floating npc + x = 0; + y = 0; + m = -1; + } + else + {// npc in a map + if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 + || (strcmp(w2, "script") == 0 && strchr(w4,',') == NULL) ) + { + ShowError("npc_parse_script: unkown format for a script in file '%s', line '%d'. Skipping the rest of file...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return NULL;// unknown format, don't continue } m = map_mapname2mapid(mapname); } - if (strcmp(w2, "script") == 0){ - // parsing script with curly - int curly_count = 0; - srcbuf = (char *)aMallocA(srcsize*sizeof(char)); - if (strchr(first_line, '{')) { - strcpy(srcbuf, strchr(first_line, '{')); - startline = *lines; - } else - srcbuf[0] = 0; - npc_parse_script_line(srcbuf,&curly_count,*lines); - while (curly_count > 0) { - fgets(line, sizeof(line), fp); - (*lines)++; - npc_parse_script_line(line,&curly_count,*lines); - if (feof(fp)) - break; - if (strlen(srcbuf) + strlen(line) + 1 >= (size_t)srcsize) { - srcsize += 65536; - srcbuf = (char *)aRealloc(srcbuf, srcsize); - memset(srcbuf + srcsize - 65536, '\0', 65536); - } - if (srcbuf[0] != '{') { - if (strchr(line, '{')) { - strcpy(srcbuf, strchr(line, '{')); - startline = *lines; - } - } else - strcat(srcbuf, line); - } - if(curly_count > 0) { - ShowError("Missing right curly at file %s, line %d\n", file, *lines); - script = NULL; - } else { - // printf("Ok line %d\n",*lines); - script = parse_script(srcbuf, file, startline, SCRIPT_USE_LABEL_DB); - } - if (script == NULL) { - // script parse error? - aFree(srcbuf); - return 1; + if( strcmp(w2, "script") == 0 ) + {// parsing script with curly + const char* real_start; + const char* end; + + end = npc_skip_script(start, buffer, filepath); + if( end == NULL ) + return NULL;// (simple) parse error, don't continue + + real_start = strchr(start,'{'); + script = parse_script(real_start, filepath, strline(buffer,real_start-buffer), SCRIPT_USE_LABEL_DB); + label_list = NULL; + label_list_num = 0; + src_id = 0; + if( script ) + { + DB label_db = script_get_label_db(); + label_db->foreach(label_db, npc_convertlabel_db, &label_list, &label_list_num, filepath); + label_db->clear(label_db, NULL); // not needed anymore, so clear the db } - } else { - // duplicateする + } + else + {// duplicate npc char srcname[128]; - struct npc_data *dnd; - if (sscanf(w2, "duplicate(%[^)])", srcname) != 1) { - ShowError("bad duplicate name (in %s)! : %s", file, w2); - return 0; + if( sscanf(w2,"duplicate(%127[^)])",srcname) != 1 ) + { + ShowError("npc_parse_script: bad duplicate name in file '%s', line '%d' : %s\n", filepath, strline(buffer,start-buffer), w2); + return strchr(start, '\n');// next line, try to continue } - if ((dnd = npc_name2id(srcname)) == NULL) { - ShowError("bad duplicate name (in %s)! (not exist) : %s\n", file, srcname); - return 0; + dnd = npc_name2id(srcname); + if( dnd == NULL) { + ShowError("npc_parse_script: original npc not found for duplicate in file '%s', line '%d' : %s\n", filepath, strline(buffer,start-buffer), srcname); + return strchr(start, '\n');// next line, continue } script = dnd->u.scr.script; - label_dup = dnd->u.scr.label_list; - label_dupnum = dnd->u.scr.label_list_num; + label_list = dnd->u.scr.label_list;// TODO duplicate this? + label_list_num = dnd->u.scr.label_list_num; src_id = dnd->bl.id; + } - }// end of スクリプト解析 - - nd = (struct npc_data *)aCalloc(1, sizeof(struct npc_data)); - - if (sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3) { - // 接触型NPC + CREATE(nd, struct npc_data, 1); + if( sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3 ) + {// OnTouch area defined if (xs >= 0) xs = xs * 2 + 1; if (ys >= 0) ys = ys * 2 + 1; nd->u.scr.xs = xs; nd->u.scr.ys = ys; - } else { - // クリック型NPC + } + else + { class_ = atoi(w4); nd->u.scr.xs = 0; nd->u.scr.ys = 0; } - p = strchr(w3,':'); - while (p) { - if (p[1] == ':') break; - p = strchr(p+1, ':'); + // extended name + p = strstr(w3,"::"); + if( p ) + { + *p = '\0'; + safestrncpy(nd->name, w3, sizeof(nd->name)); + safestrncpy(nd->exname, p+2, sizeof(nd->exname)); } - if (p) { - *p = 0; - memcpy(nd->name, w3, NAME_LENGTH); - memcpy(nd->exname, p+2, NAME_LENGTH); - } else { - memcpy(nd->name, w3, NAME_LENGTH); - memcpy(nd->exname, w3, NAME_LENGTH); + else + { + safestrncpy(nd->name, w3, sizeof(nd->name)); + safestrncpy(nd->exname, w3, sizeof(nd->exname)); } - if((dnd = npc_name2id(nd->exname))){ - if(battle_config.etc_log) - ShowInfo("npc_parse_script: Overriding NPC '%s::%s' to '%s::%d'.. in file '%s' (Duplicated System Name - Lazy scripters >_>) \n",nd->name,nd->exname,nd->name,npc_script,file); - sprintf(nd->exname, "%d", npc_script); + if( npc_name2id(nd->exname) ) + {// duplicate name, generate new name + char newexname[32]; + int i = 0; + do + { + ++i; + sprintf(newexname, "%31d", i); + dnd = npc_name2id(newexname); + } + while( dnd ); + ShowWarning("npc_parse_script: Overriding NPC '%s::%s' to '%s::%d'.. in file '%s', line '%d' (Duplicated System Name - Lazy scripters >_>) \n", nd->name, nd->exname, nd->name, i, filepath, strline(buffer,start-buffer)); + safestrncpy(nd->exname, newexname, sizeof(nd->exname)); } nd->bl.prev = nd->bl.next = NULL; @@ -1837,12 +1800,15 @@ static int npc_parse_script(char* w1, char* w2, char* w3, char* w4, char* first_ nd->speed = 200; nd->u.scr.script = script; nd->u.scr.src_id = src_id; + nd->u.scr.label_list = label_list; + nd->u.scr.label_list_num = label_list_num; - npc_script++; + ++npc_script; nd->bl.type = BL_NPC; nd->bl.subtype = SCRIPT; - if (m >= 0) { + if( m >= 0 ) + { nd->n = map_addnpc(m, nd); status_change_init(&nd->bl); unit_dataset(&nd->bl); @@ -1858,34 +1824,20 @@ static int npc_parse_script(char* w1, char* w2, char* w3, char* w4, char* first_ } else { clif_spawn(&nd->bl); }*/ - if (class_ >= 0){ + if( class_ >= 0 ) + { status_set_viewdata(&nd->bl, nd->class_); clif_spawn(&nd->bl); } - } else { + } + else + { // we skip map_addnpc, but still add it to the list of ID's map_addiddb(&nd->bl); } strdb_put(npcname_db, nd->exname, nd); //----------------------------------------- - // ラベルデータの準備 - if (srcbuf){ - // script本体がある場合の処理 - // ラベルデータのコンバート - label_db = script_get_label_db(); - label_db->foreach(label_db, npc_convertlabel_db, nd); - label_db->clear(label_db,NULL); // not needed anymore, so clear the db - - // もう使わないのでバッファ解放 - aFree(srcbuf); - } else { - // duplicate - nd->u.scr.label_list = label_dup; // ラベルデータ共有 - nd->u.scr.label_list_num = label_dupnum; - } - - //----------------------------------------- // イベント用ラベルデータのエクスポート for (i = 0; i < nd->u.scr.label_list_num; i++) { @@ -1897,13 +1849,13 @@ static int npc_parse_script(char* w1, char* w2, char* w3, char* w4, char* first_ struct event_data* ev; char buf[50+1]; // 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS snprintf(buf, sizeof(buf), "%s::%s", nd->exname, lname); - + // generate the data and insert it - ev = (struct event_data *)aMalloc(sizeof(struct event_data)); + CREATE(ev, struct event_data, 1); ev->nd = nd; ev->pos = pos; - if (strdb_put(ev_db, buf, ev) != NULL) //There was already another event of the same name? - ShowWarning("npc_parse_script : duplicate event %s (%s)\n", buf, file); + if( strdb_put(ev_db, buf, ev) != NULL )// There was already another event of the same name? + ShowWarning("npc_parse_script : duplicate event %s (%s)\n", buf, filepath); } } @@ -2031,76 +1983,35 @@ int npc_changename(const char* name, const char* newname, short look) return 0; } -/*========================================== - * function行解析 - *------------------------------------------*/ -static int npc_parse_function(char* w1, char* w2, char* w3, char* w4, char* first_line, FILE* fp, int* lines, const char* file) +/// Parses a function. +/// function%TAB%script%TAB%<function name>%TAB%{<code>} +static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { - char *srcbuf, *p; + struct dbt *func_db; struct script_code *script; struct script_code *oldscript; - int srcsize = 65536; - int startline = 0; - char line[1024]; - int curly_count = 0; - struct dbt *user_db; - - // スクリプトの解析 - srcbuf = (char *) aMallocA (srcsize*sizeof(char)); - if (strchr(first_line,'{')) { - strcpy(srcbuf, strchr(first_line,'{')); - startline = *lines; - } else - srcbuf[0] = 0; - npc_parse_script_line(srcbuf,&curly_count,*lines); - - while (curly_count > 0) { - fgets(line, sizeof(line), fp); - (*lines)++; - npc_parse_script_line(line,&curly_count,*lines); - if (feof(fp)) - break; - if (strlen(srcbuf)+strlen(line)+1 >= (unsigned int)srcsize) { - srcsize += 65536; - srcbuf = (char *)aRealloc(srcbuf, srcsize); - memset(srcbuf + srcsize - 65536, '\0', 65536); - } - if (srcbuf[0]!='{') { - if (strchr(line,'{')) { - strcpy(srcbuf, strchr(line,'{')); - startline = *lines; - } - } else - strcat(srcbuf,line); - } - if(curly_count > 0) { - ShowError("Missing right curly at file %s, line %d\n",file, *lines); - script = NULL; - } else { - script = parse_script(srcbuf, file, startline,0); - } - if (script == NULL) { - // script parse error? - aFree(srcbuf); - return 1; - } + const char* end; - p = (char *) aMallocA (50*sizeof(char)); - strncpy(p, w3, 50); + end = npc_skip_script(start,buffer,filepath); + if( end == NULL ) + return NULL;// (simple) parse error, don't continue - user_db = script_get_userfunc_db(); - oldscript = (struct script_code *)strdb_get(user_db, p); - if(oldscript != NULL) { - ShowInfo("parse_function: Overwriting user function [%s] (%s:%d)\n", p, file, *lines); - script_free_vars( &oldscript->script_vars ); - aFree( oldscript->script_buf ); - user_db->remove(user_db,str2key(p)); + start = strchr(start,'{'); + script = parse_script(start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT); + if( script == NULL )// parse error, continue + return end; + + func_db = script_get_userfunc_db(); + oldscript = (struct script_code*)strdb_put(func_db, w3, script); + if( oldscript != NULL ) + { + ShowInfo("npc_parse_function: Overwriting user function [%s] (%s:%d)\n", w3, filepath, strline(buffer,start-buffer)); + script_free_vars(&oldscript->script_vars); + aFree(oldscript->script_buf); + aFree(oldscript); } - strdb_put(user_db, p, script); - // もう使わないのでバッファ解放 - aFree(srcbuf); - return 0; + return end; } @@ -2128,45 +2039,51 @@ int npc_parse_mob2(struct spawn_data* mob, int index) return 1; } -int npc_parse_mob(char* w1, char* w2, char* w3, char* w4) +static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { int level, num, class_, mode, x,y,xs,ys; - char mapname[MAP_NAME_LENGTH_EXT]; - char mobname[NAME_LENGTH]; + char mapname[32]; + char mobname[128]; struct spawn_data mob, *data; struct mob_db* db; memset(&mob, 0, sizeof(struct spawn_data)); - // 引数の個数チェック - if (sscanf(w1, "%15[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 || - sscanf(w4, "%d,%d,%u,%u,%49[^\t\r\n]", &class_, &num, &mob.delay1, &mob.delay2, mob.eventname) < 2 ) { - ShowError("bad monster line : %s %s %s (file %s)\n", w1, w3, w4, current_file); - return 1; + // w1=<map name>,<x>,<y>,<xs>,<ys> + // w4=<mob id>,<amount>,<delay1>,<delay2>,<event> + if( sscanf(w1, "%31[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 + || sscanf(w4, "%d,%d,%u,%u,%127[^\t\r\n]", &class_, &num, &mob.delay1, &mob.delay2, mob.eventname) < 2 ) + { + ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue } - if (!mapindex_name2id(mapname)) { - ShowError("wrong map name : %s %s (file %s)\n", w1,w3, current_file); - return 1; + if( mapindex_name2id(mapname) == 0 ) + { + ShowError("npc_parse_mob: Unknown map '%s' in file '%s', line '%d'.\n", mapname, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue } mode = map_mapname2mapid(mapname); - if (mode < 0) //Not loaded on this map-server instance. - return 1; + if( mode < 0 )//Not loaded on this map-server instance. + return strchr(start,'\n');// skip and continue mob.m = (unsigned short)mode; - if (x < 0 || map[mob.m].xs <= x || y < 0 || map[mob.m].ys <= y) { - ShowError("Out of range spawn coordinates: %s (%d,%d), map size is (%d,%d) - %s %s (file %s)\n", map[mob.m].name, x, y, map[mob.m].xs-1, map[mob.m].ys-1, w1,w3, current_file); - return 1; + if( x < 0 || x >= map[mob.m].xs || y < 0 || y >= map[mob.m].ys ) + { + ShowError("npc_parse_mob: Spawn coordinates out of range: %s (%d,%d), map size is (%d,%d) - %s %s (file '%s', line '%d').\n", map[mob.m].name, x, y, (map[mob.m].xs-1), (map[mob.m].ys-1), w1, w3, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue } // check monster ID if exists! - if (mobdb_checkid(class_)==0) { - ShowError("bad monster ID : %s %s (file %s)\n", w3, w4, current_file); - return 1; + if( mobdb_checkid(class_) == 0 ) + { + ShowError("npc_parse_mob: Unknown mob ID : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue } - if (num < 1 || num>1000 ) { - ShowError("wrong number of monsters : %s %s (file %s)\n", w3, w4, current_file); - return 1; + if( num < 1 || num > 1000 ) + { + ShowError("npc_parse_mob: Invalid number of monsters (must be inside the range [1,1000]) : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue } //Fix for previously wrong interpretation of the delays @@ -2214,12 +2131,12 @@ int npc_parse_mob(char* w1, char* w2, char* w3, char* w4) } // parse MOB_NAME,[MOB LEVEL] - if (sscanf(w3, "%23[^,],%d", mobname, &level) > 1) + if (sscanf(w3, "%127[^,],%d", mobname, &level) > 1) mob.level = level; if(mob.delay1>0xfffffff || mob.delay2>0xfffffff) { - ShowError("wrong monsters spawn delays : %s %s (file %s)\n", w3, w4, current_file); - return 1; + ShowError("npc_parse_mob: wrong monsters spawn delays : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue } //Use db names instead of the spawn file ones. @@ -2230,8 +2147,11 @@ int npc_parse_mob(char* w1, char* w2, char* w3, char* w4) else strncpy(mob.name, mobname, NAME_LENGTH-1); - if (!mob_parse_dataset(&mob)) //Verify dataset. - return 1; + if( !mob_parse_dataset(&mob) ) //Verify dataset. + { + ShowError("npc_parse_mob: Invalid dataset : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer)); + return strchr(start,'\n');// skip and continue + } for(x=0; x < ARRAYLENGTH(db->spawn); x++) { @@ -2288,30 +2208,36 @@ int npc_parse_mob(char* w1, char* w2, char* w3, char* w4) npc_mob++; - return 0; + return strchr(start,'\n');// continue } /*========================================== * マップフラグ行の解析 *------------------------------------------*/ -static int npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4) +static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { int m; - char mapname[MAP_NAME_LENGTH_EXT]; + char mapname[32]; int state = 1; - // 引数の個数チェック - if (sscanf(w1, "%15[^,]",mapname) != 1) - return 1; - + // w1=<mapname> + if( sscanf(w1, "%31[^,]", mapname) != 1 ) + { + ShowError("npc_parse_mapflag: Invalid mapflag definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue + } m = map_mapname2mapid(mapname); - if (m < 0) - return 1; + if( m < 0 ) + { + ShowWarning("npc_parse_mapflag: Unknown map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", mapname, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue + } + if (w4 && !strcmpi(w4, "off")) state = 0; //Disable mapflag rather than enable it. [Skotlex] if (!strcmpi(w3, "nosave")) { - char savemap[MAP_NAME_LENGTH_EXT]; + char savemap[32]; int savex, savey; if (state == 0) ; //Map flag disabled. @@ -2319,12 +2245,12 @@ static int npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4) map[m].save.map = 0; map[m].save.x = -1; map[m].save.y = -1; - } else if (sscanf(w4, "%15[^,],%d,%d", savemap, &savex, &savey) == 3) { + } else if (sscanf(w4, "%31[^,],%d,%d", savemap, &savex, &savey) == 3) { map[m].save.map = mapindex_name2id(savemap); map[m].save.x = savex; map[m].save.y = savey; if (!map[m].save.map) { - ShowWarning("Specified save point map '%s' for mapflag 'nosave' not found (file %s), using 'SavePoint'.\n",savemap,current_file); + ShowWarning("npc_parse_mapflag: Specified save point map '%s' for mapflag 'nosave' not found (file '%s', line '%d'), using 'SavePoint'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", savemap, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); map[m].save.x = -1; map[m].save.y = -1; } @@ -2353,7 +2279,7 @@ static int npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4) map[m].flag.pvp=state; if (state) { if (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) - ShowWarning("You can't set PvP and GvG flags for the same map! Removing GvG flags from %s\n", map[m].name); + ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); map[m].flag.gvg=0; map[m].flag.gvg_dungeon=0; map[m].flag.gvg_castle=0; @@ -2400,7 +2326,7 @@ static int npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4) if (state && map[m].flag.pvp) { map[m].flag.pvp=0; - ShowWarning("You can't set PvP and GvG flags for the same map! Removing PvP flag from %s\n", map[m].name); + ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); } } else if (!strcmpi(w3,"gvg_noparty")) @@ -2503,125 +2429,159 @@ static int npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4) else if (!strcmpi(w3,"guildlock")) map[m].flag.guildlock=state; - return 0; + return strchr(start,'\n');// continue } /*========================================== * Setting up map cells *------------------------------------------*/ -static int npc_parse_mapcell(char* w1, char* w2, char* w3, char* w4) +static const char* npc_parse_mapcell(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { int m, cell, x, y, x0, y0, x1, y1; - char type[24], mapname[MAP_NAME_LENGTH_EXT]; - - if (sscanf(w1, "%15[^,]", mapname) != 1) - return 1; + char type[32], mapname[32]; + // w1=<mapname> + // w3=<type>,<x1>,<y1>,<x2>,<y2> + if( sscanf(w1, "%31[^,]", mapname) != 1 + || sscanf(w3, "%31[^,],%d,%d,%d,%d", type, &x0, &y0, &x1, &y1) < 5 ) + { + ShowError("npc_parse_mapcell: Invalid mapcell definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue + } m = map_mapname2mapid(mapname); - if (m < 0) - return 1; - - if (sscanf(w3, "%23[^,],%d,%d,%d,%d", type, &x0, &y0, &x1, &y1) < 5) { - ShowError("Bad setcell line : %s\n",w3); - return 1; + if( m < 0 ) + { + ShowWarning("npc_parse_mapcell: Unknown map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", mapname, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + return strchr(start,'\n');// skip and continue } + cell = strtol(type, (char **)NULL, 0); - //printf ("0x%x %d %d %d %d\n", cell, x0, y0, x1, y1); - if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } - if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + if( x0 > x1 ) + swap(x0, x1); + if( y0 > y1 ) + swap(y0, y1); - for (x = x0; x <= x1; x++) { - for (y = y0; y <= y1; y++) { + for( x = x0; x <= x1; ++x ) + for( y = y0; y <= y1; ++y ) map_setcell(m, x, y, cell); - //printf ("setcell 0x%x %d %d %d\n", cell, m, x, y); - } - } - return 0; + return strchr(start,'\n');// continue } -void npc_parsesrcfile(const char* name) +void npc_parsesrcfile(const char* filepath) { int m, lines = 0; - char line[2048]; - - FILE *fp = fopen (name,"r"); - if (fp == NULL) { - ShowError ("File not found : %s\n", name); + FILE* fp; + size_t len; + char* buffer; + const char* p; + + // read whole file to buffer + fp = fopen(filepath, "rb"); + if( fp == NULL ) + { + ShowError("npc_parsesrcfile: File not found '%s'.\n", filepath); + return; + } + fseek(fp, 0, SEEK_END); + len = ftell(fp); + buffer = (char*)aMalloc(len+1); + buffer[len] = '\0'; + fseek(fp, 0, SEEK_SET); + if( fread(buffer, len, 1, fp) != 1 ) + { + ShowError("npc_parsesrcfile: Failed to read file '%s'.\n", filepath); + aFree(buffer); + fclose(fp); return; } - current_file = name; + fclose(fp); - while (fgets(line, sizeof(line), fp)) + // parse buffer + for( p = skip_space(buffer); p && *p ; p = skip_space(p) ) { char w1[2048], w2[2048], w3[2048], w4[2048], mapname[2048]; int i, w4pos, count; lines++; - if (line[0] == '/' && line[1] == '/') - continue; - - if (!sscanf(line, " %n", &i) && i == strlen(line)) // just whitespace - continue; + w1[0] = w2[0] = w3[0] = w4[0] = '\0'; - // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認 - w1[0] = w2[0] = w3[0] = w4[0] = '\0'; //It's best to initialize values - //to prevent passing previously parsed values to the parsers when not all - //fields are specified. [Skotlex] - if ((count = sscanf(line, "%[^\t\r\n]\t%[^\t\r\n]\t%[^\t\r\n]\t%n%[^\r\n]", w1, w2, w3, &w4pos, w4)) < 3) + // w1<TAB>w2<TAB>w3<TAB>w4 + if( (count = sscanf(p, "%[^\t\r\n]\t%[^\t\r\n]\t%[^\t\r\n]\t%n%[^\r\n]", w1, w2, w3, &w4pos, w4)) < 3 ) { - if ((count = sscanf(line, "%s %s %[^\t]\t %n%[^\n]", w1, w2, w3, &w4pos, w4)) == 4 || - (count = sscanf(line, "%s %s %s %n%[^\n]\n", w1, w2, w3, &w4pos, w4)) >= 3) - { - ShowWarning("Incorrect separator syntax in file '%s', line '%i'. Use tabs instead of spaces!\n * %s %s %s %s\n",current_file,lines,w1,w2,w3,w4); - } else { - ShowError("Could not parse file '%s', line '%i'.\n * %s %s %s %s\n",current_file,lines,w1,w2,w3,w4); + if( (count = sscanf(p, "%s %s %[^\t]\t %n%[^\n]", w1, w2, w3, &w4pos, w4)) == 4 + || (count = sscanf(p, "%s %s %s %n%[^\n]\n", w1, w2, w3, &w4pos, w4)) >= 3 ) + {// Incorrect syntax, try to parse + ShowWarning("npc_parsesrcfile: Incorrect separator syntax in file '%s', line '%d'. Use tabs instead of spaces!\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + } + else + {// Unknown syntax, try to continue + ShowError("npc_parsesrcfile: Unknown syntax in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + p = strchr(p,'\n');// next line continue; } } - // マップの存在確認 - if (strcmp(w1,"-") !=0 && strcmpi(w1,"function") != 0 ){ + if( strcmp(w1,"-") !=0 && strcasecmp(w1,"function") != 0 ) + {// w1 = <map name>,<x>,<y>,<facing> sscanf(w1,"%[^,]",mapname); - if (!mapindex_name2id(mapname)) { //Incorrect map - ShowError("Invalid map '%s' in line %d, file %s\n", mapname, lines, current_file); - if (strcmpi(w2,"script") == 0 && count > 3) //we must skip the script info... - npc_skip_script(w1,w2,w3,w4,line+w4pos,fp,&lines); + if( !mapindex_name2id(mapname) ) + {// Incorrect map, we must skip the script info... + ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'.\n", mapname, filepath, strline(buffer,p-buffer)); + if( strcasecmp(w2,"script") == 0 && count > 3 ) + p = npc_skip_script(p,buffer,filepath); + p = strchr(p,'\n');// next line continue; } - if ((m = map_mapname2mapid(mapname)) < 0) { - // "mapname" is not assigned to this server - // we must skip the script info... - if (strcmpi(w2,"script") == 0 && count > 3) - npc_skip_script(w1,w2,w3,w4,line+w4pos,fp,&lines); + m = map_mapname2mapid(mapname); + if( m < 0 ) + {// "mapname" is not assigned to this server, we must skip the script info... + if( strcasecmp(w2,"script") == 0 && count > 3 ) + p = npc_skip_script(p,buffer,filepath); + p = strchr(p,'\n');// next line continue; } } - if (strcmpi(w2,"warp") == 0 && count > 3) { - npc_parse_warp(w1,w2,w3,w4); - } else if (strcmpi(w2,"shop") == 0 && count > 3) { - npc_parse_shop(w1,w2,w3,w4); - } else if (strcmpi(w2,"script") == 0 && count > 3) { - if (strcmpi(w1,"function") == 0) { - npc_parse_function(w1,w2,w3,w4,line+w4pos,fp,&lines,name); - } else { - npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines,name); - } - } else if ((i = 0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) && count > 3) { - npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines,name); - } else if (strcmpi(w2,"monster") == 0 && count > 3) { - npc_parse_mob(w1,w2,w3,w4); - } else if (strcmpi(w2,"mapflag") == 0 && count >= 3) { - npc_parse_mapflag(w1,w2,w3,w4); - } else if (strcmpi(w2,"setcell") == 0 && count >= 3) { - npc_parse_mapcell(w1,w2,w3,w4); - } else { - ShowError("Probably TAB is missing in file '%s', line '%i':\n * %s %s %s %s\n",current_file,lines,w1,w2,w3,w4); + + if( strcasecmp(w2,"warp") == 0 && count > 3 ) + { + p = npc_parse_warp(w1,w2,w3,w4, p, buffer, filepath); + } + else if( strcasecmp(w2,"shop") == 0 && count > 3 ) + { + p = npc_parse_shop(w1,w2,w3,w4, p, buffer, filepath); + } + else if( strcasecmp(w2,"script") == 0 && count > 3 ) + { + if( strcasecmp(w1,"function") == 0 ) + p = npc_parse_function(w1, w2, w3, w4, p, buffer, filepath); + else + p = npc_parse_script(w1,w2,w3,w4, p, buffer, filepath); + } + else if( (i=0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) && count > 3 ) + { + p = npc_parse_script(w1,w2,w3,w4, p, buffer, filepath); + } + else if( strcmpi(w2,"monster") == 0 && count > 3 ) + { + p = npc_parse_mob(w1, w2, w3, w4, p, buffer, filepath); + } + else if( strcmpi(w2,"mapflag") == 0 && count >= 3 ) + { + p = npc_parse_mapflag(w1, w2, w3, w4, p, buffer, filepath); + } + else if( strcmpi(w2,"setcell") == 0 && count >= 3 ) + { + p = npc_parse_mapcell(w1, w2, w3, w4, p, buffer, filepath); + } + else + { + ShowError("Probably TAB is missing in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + p = strchr(p,'\n');// skip and continue } } - fclose(fp); - current_file = NULL; + aFree(buffer); return; } diff --git a/src/map/npc.h b/src/map/npc.h index 39aad1cf8..7293b4a7c 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -52,9 +52,8 @@ int npc_checknear2(struct map_session_data* sd, struct block_list* bl); int npc_buysellsel(struct map_session_data* sd, int id, int type); int npc_buylist(struct map_session_data* sd,int n, unsigned short* item_list); int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list); -int npc_parse_mob(char* w1, char* w2, char* w3, char* w4); int npc_parse_mob2(struct spawn_data* mob, int index); // [Wizputer] -int npc_parse_warp(char* w1,char* w2,char* w3,char* w4); +const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath); int npc_globalmessage(const char* name,const char* mes); void npc_setcells(struct npc_data* nd); @@ -67,7 +66,7 @@ int npc_get_new_npc_id(void); void npc_addsrcfile(const char* name); void npc_delsrcfile(const char* name); -void npc_parsesrcfile(const char* name); +void npc_parsesrcfile(const char* filepath); int do_final_npc(void); int do_init_npc(void); int npc_event_do_oninit(void); diff --git a/src/map/script.c b/src/map/script.c index c4e45d667..116973f17 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -722,9 +722,10 @@ void set_label(int l,int pos, const char* script_pos) } /// Skips spaces and/or comments. -static const char* skip_space(const char* p) { + if( p == NULL ) + return NULL; for(;;) { while( ISSPACE(*p) ) @@ -740,7 +741,7 @@ const char* skip_space(const char* p) for(;;) { if( *p == '\0' ) - disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p); + return p;//disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p); if( *p == '*' && p[1] == '/' ) {// end of block comment p += 2; @@ -1896,7 +1897,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o { const char *p,*tmpp; int i; - struct script_code *code; + struct script_code* code = NULL; static int first=1; char end; @@ -1955,8 +1956,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o p=skip_space(p); if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS ) {// does not require brackets around the script - if( *p == '\0' ) - {// empty script + if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) + {// empty script and can return NULL aFree( script_buf ); script_pos = 0; script_size = 0; @@ -1969,9 +1970,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o {// requires brackets around the script if( *p != '{' ) disp_error_message("not found '{'",p); - p = skip_space(++p); - if( *p == '}' ) - {// empty script + p = skip_space(p+1); + if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) + {// empty script and can return NULL aFree( script_buf ); script_pos = 0; script_size = 0; @@ -3586,6 +3587,7 @@ static int do_final_userfunc_sub (DBKey key,void *data,va_list ap) if(code){ script_free_vars( &code->script_vars ); aFree( code->script_buf ); + aFree( code ); } return 0; } @@ -3683,7 +3685,7 @@ int do_init_script() { mapreg_db= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); mapregstr_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); - userfunc_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_RELEASE_BOTH,50); + userfunc_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_DUP_KEY,0); scriptlabel_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA,50); script_load_mapreg(); diff --git a/src/map/script.h b/src/map/script.h index 9783eeb3b..1e92f73d1 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -63,9 +63,14 @@ struct script_state { enum script_parse_options { SCRIPT_USE_LABEL_DB = 0x1,// records labels in scriptlabel_db - SCRIPT_IGNORE_EXTERNAL_BRACKETS = 0x2// ignores the check for {} brackets around the script + SCRIPT_IGNORE_EXTERNAL_BRACKETS = 0x2,// ignores the check for {} brackets around the script + SCRIPT_RETURN_EMPTY_SCRIPT = 0x4// returns the script object instead of NULL for empty scripts }; +const char* skip_space(const char* p); +const char* script_print_line(const char* p, const char* mark, int line); +void script_error(const char *src,const char *file,int start_line, const char *error_msg, const char *error_pos); + struct script_code* parse_script(const char* src,const char* file,int line,int options); void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno); void run_script(struct script_code*,int,int,int); |