summaryrefslogtreecommitdiff
path: root/src/map/npc.c
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2014-05-09 07:37:53 +0200
committerHaru <haru@dotalux.com>2014-05-09 07:40:43 +0200
commit5f1529083ad1f35a3ac66cc041ee74d6db2f3552 (patch)
tree32c4d73a7f68cd7a1a963e14e3972333758bb541 /src/map/npc.c
parent581ff22b9bad7567a27980df31636f0c75ba5fc2 (diff)
downloadhercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.gz
hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.bz2
hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.tar.xz
hercules-5f1529083ad1f35a3ac66cc041ee74d6db2f3552.zip
Return EXIT_FAILURE if a script parse error occurred.
- This affects normal execution as well as ./script-checker runs. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/map/npc.c')
-rw-r--r--src/map/npc.c239
1 files changed, 144 insertions, 95 deletions
diff --git a/src/map/npc.c b/src/map/npc.c
index 43e4bcc88..27759d185 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -2532,8 +2532,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
}
/// 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)
-{
+const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) {
int x, y, xs, ys, to_x, to_y, m;
unsigned short i;
char mapname[32], to_mapname[32];
@@ -2542,22 +2541,24 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
// 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 )
- {
+ || 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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
m = map->mapname2mapid(mapname);
i = mapindex->name2id(to_mapname);
- if( i == 0 )
- {
+ 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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) {
ShowError("npc_parse_warp: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');;//try next
}
@@ -2597,25 +2598,27 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
}
/// Parses a shop/cashshop npc.
-const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)
-{
+const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) {
//TODO: could be rewritten to NOT need this temp array [ultramage]
- #define MAX_SHOPITEM 100
+#define MAX_SHOPITEM 100
struct npc_item_list items[MAX_SHOPITEM];
+#undef MAX_SHOPITEM
char *p;
int x, y, dir, m, i;
struct npc_data *nd;
enum npc_subtype type;
- if( strcmp(w1,"-") == 0 ) {// 'floating' shop?
+ if( strcmp(w1,"-") == 0 ) {
+ // 'floating' shop?
x = y = dir = 0;
m = -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 )
- {
+ || 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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
@@ -2624,6 +2627,7 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s
if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) {
ShowError("npc_parse_shop: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');;//try next
}
@@ -2633,38 +2637,38 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s
type = SHOP;
p = strchr(w4,',');
- for( i = 0; i < ARRAYLENGTH(items) && p; ++i )
- {
+ for( i = 0; i < ARRAYLENGTH(items) && p; ++i ) {
int nameid, value;
struct item_data* id;
- if( sscanf(p, ",%d:%d", &nameid, &value) != 2 )
- {
+ 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);
+ if (retval) *retval = EXIT_FAILURE;
break;
}
- if( (id = itemdb->exists(nameid)) == NULL )
- {
+ if( (id = itemdb->exists(nameid)) == NULL ) {
ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%d').\n", filepath, strline(buffer,start-buffer), nameid);
p = strchr(p+1,',');
+ if (retval) *retval = EXIT_FAILURE;
continue;
}
- if( value < 0 )
- {
+ if( value < 0 ) {
if( type == SHOP ) value = id->value_buy;
else value = 0; // Cashshop doesn't have a "buy price" in the item_db
}
- if( type == SHOP && value == 0 )
- { // NPC selling items for free!
+ if( type == SHOP && value == 0 ) {
+ // NPC selling items for free!
ShowWarning("npc_parse_shop: Item %s [%d] is being sold for FREE in file '%s', line '%d'.\n",
id->name, nameid, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
- if( type == SHOP && value*0.75 < id->value_sell*1.24 )
- {// Exploit possible: you can buy and sell back with profit
+ if( type == SHOP && value*0.75 < id->value_sell*1.24 ) {
+ // Exploit 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) in 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));
+ if (retval) *retval = EXIT_FAILURE;
}
//for logs filters, atcommands and iteminfo script command
if( id->maxchance == 0 )
@@ -2674,9 +2678,9 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s
items[i].value = value;
p = strchr(p+1,',');
}
- if( i == 0 )
- {
+ if( i == 0 ) {
ShowWarning("npc_parse_shop: Ignoring empty shop in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// continue
}
@@ -2743,8 +2747,7 @@ void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath
}
// Skip the contents of a script.
-const char* npc_skip_script(const char* start, const char* buffer, const char* filepath)
-{
+const char* npc_skip_script(const char* start, const char* buffer, const char* filepath, int *retval) {
const char* p;
int curly_count;
@@ -2753,9 +2756,9 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f
// initial bracket (assumes the previous part is ok)
p = strchr(start,'{');
- if( p == NULL )
- {
+ if( p == NULL ) {
ShowError("npc_skip_script: Missing left curly in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
}
@@ -2775,16 +2778,15 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f
{// string
for( ++p; *p != '"' ; ++p )
{
- if( *p == '\\' && (unsigned char)p[-1] <= 0x7e )
+ if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) {
++p;// escape sequence (not part of a multibyte character)
- else if( *p == '\0' )
- {
+ } else if( *p == '\0' ) {
script->error(buffer, filepath, 0, "Unexpected end of string.", p);
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
- }
- else if( *p == '\n' )
- {
+ } else if( *p == '\n' ) {
script->error(buffer, filepath, 0, "Unexpected newline at string.", p);
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
}
}
@@ -2792,6 +2794,7 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f
else if( *p == '\0' )
{// end of buffer
ShowError("Missing %d right curlys in file '%s', line '%d'.\n", curly_count, filepath, strline(buffer,p-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
}
}
@@ -2804,7 +2807,7 @@ const char* npc_skip_script(const char* start, const char* buffer, const char* f
/// -%TAB%script%TAB%<NPC Name>%TAB%-1,{<code>}
/// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,{<code>}
/// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>,{<code>}
-const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options) {
+const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) {
int x, y, dir = 0, m, xs = 0, ys = 0; // [Valaris] thanks to fov
char mapname[32];
struct script_code *scriptroot;
@@ -2824,6 +2827,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
} else {// npc in a map
if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ) {
ShowError("npc_parse_script: Invalid placement 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);
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// unknown format, don't continue
}
m = map->mapname2mapid(mapname);
@@ -2834,15 +2838,16 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
if( strstr(w4,",{") == NULL || script_start == NULL || (end != NULL && script_start > end) )
{
ShowError("npc_parse_script: Missing left curly ',{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
}
++script_start;
- end = npc->skip_script(script_start, buffer, filepath);
+ end = npc->skip_script(script_start, buffer, filepath, retval);
if( end == NULL )
return NULL;// (simple) parse error, don't continue
- scriptroot = script->parse(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB);
+ scriptroot = script->parse(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB, retval);
label_list = NULL;
label_list_num = 0;
if( script->label_count ) {
@@ -2906,6 +2911,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
if (npc->event_export(nd, i)) {
ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n",
nd->exname, nd->u.scr.label_list[i].name, filepath);
+ if (retval) *retval = EXIT_FAILURE;
}
npc->timerevent_export(nd, i);
}
@@ -2936,8 +2942,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
/// npc: -%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>
/// npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>
/// !!Only NPO_ONINIT is available trough options!!
-const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options)
-{
+const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) {
int x, y, dir, m, xs = -1, ys = -1;
char mapname[32];
char srcname[128];
@@ -2957,6 +2962,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
if( w2[length-1] != ')' || length <= 11 || length-11 >= sizeof(srcname) )
{// does not match 'duplicate(%127s)', name is empty or too long
ShowError("npc_parse_script: bad duplicate name in file '%s', line '%d': %s\n", filepath, strline(buffer,start-buffer), w2);
+ if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
safestrncpy(srcname, w2+10, length-10);
@@ -2964,6 +2970,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
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);
+ if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
src_id = dnd->bl.id;
@@ -2979,6 +2986,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
dir = 0;
} else if( fields != 4 ) {// <map name>,<x>,<y>,<facing>
ShowError("npc_parse_duplicate: Invalid placement format for duplicate in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
+ if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
m = map->mapname2mapid(mapname);
@@ -2986,6 +2994,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) {
ShowError("npc_parse_duplicate: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return end;//try next
}
@@ -2993,6 +3002,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY>
else if( type == WARP ) {
ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
+ if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
@@ -3069,6 +3079,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
if (npc->event_export(nd, i)) {
ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n",
nd->exname, nd->u.scr.label_list[i].name, filepath);
+ if (retval) *retval = EXIT_FAILURE;
}
npc->timerevent_export(nd, i);
}
@@ -3152,7 +3163,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
else
snprintf(w4, sizeof(w4), "%d", snd->class_);
- npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE);
+ npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE, NULL);
}
return 0;
@@ -3339,8 +3350,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
/// Parses a function.
/// function%TAB%script%TAB%<function name>%TAB%{<code>}
-const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)
-{
+const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) {
DBMap* func_db;
DBData old_data;
struct script_code *scriptroot;
@@ -3349,18 +3359,18 @@ const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const cha
script_start = strstr(start,"\t{");
end = strchr(start,'\n');
- if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) )
- {
+ if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) {
ShowError("npc_parse_function: Missing left curly '%%TAB%%{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
+ if (retval) *retval = EXIT_FAILURE;
return NULL;// can't continue
}
++script_start;
- end = npc->skip_script(script_start,buffer,filepath);
+ end = npc->skip_script(script_start,buffer,filepath, retval);
if( end == NULL )
return NULL;// (simple) parse error, don't continue
- scriptroot = script->parse(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT);
+ scriptroot = script->parse(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT, retval);
if( scriptroot == NULL )// parse error, continue
return end;
@@ -3394,7 +3404,7 @@ void npc_parse_mob2(struct spawn_data* mobspawn)
}
}
-const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) {
+const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) {
int num, class_, m,x,y,xs,ys, i,j;
int mob_lv = -1, ai = -1, size = -1;
char mapname[32], mobname[NAME_LENGTH];
@@ -3413,10 +3423,12 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st
|| sscanf(w4, "%d,%d,%u,%u,%127[^,],%d,%d[^\t\r\n]", &class_, &num, &mobspawn.delay1, &mobspawn.delay2, mobspawn.eventname, &size, &ai) < 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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
if( mapindex->name2id(mapname) == 0 ) {
ShowError("npc_parse_mob: Unknown map '%s' in file '%s', line '%d'.\n", mapname, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
m = map->mapname2mapid(mapname);
@@ -3426,32 +3438,38 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st
if( x < 0 || x >= map->list[mobspawn.m].xs || y < 0 || y >= map->list[mobspawn.m].ys ) {
ShowError("npc_parse_mob: Spawn coordinates out of range: %s (%d,%d), map size is (%d,%d) - %s %s in file '%s', line '%d'.\n", map->list[mobspawn.m].name, x, y, (map->list[mobspawn.m].xs-1), (map->list[mobspawn.m].ys-1), w1, w3, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
// check monster ID if exists!
if( mob->db_checkid(class_) == 0 ) {
ShowError("npc_parse_mob: Unknown mob ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
if( num < 1 || num > 1000 ) {
ShowError("npc_parse_mob: Invalid number of monsters %d, must be inside the range [1,1000] in file '%s', line '%d'.\n", num, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
if( (mobspawn.state.size < 0 || mobspawn.state.size > 2) && size != -1 ) {
ShowError("npc_parse_mob: Invalid size number %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.size, class_, filepath, strline(buffer, start - buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start, '\n');
}
if( (mobspawn.state.ai < 0 || mobspawn.state.ai > 4) && ai != -1 ) {
ShowError("npc_parse_mob: Invalid ai %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.ai, class_, filepath, strline(buffer, start - buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start, '\n');
}
if( (mob_lv == 0 || mob_lv > MAX_LEVEL) && mob_lv != -1 ) {
ShowError("npc_parse_mob: Invalid level %d for mob ID %d in file '%s', line '%d'.\n", mob_lv, class_, filepath, strline(buffer, start - buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start, '\n');
}
@@ -3482,6 +3500,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st
if(mobspawn.delay1>0xfffffff || mobspawn.delay2>0xfffffff) {
ShowError("npc_parse_mob: Invalid spawn delays %u %u in file '%s', line '%d'.\n", mobspawn.delay1, mobspawn.delay2, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
@@ -3496,6 +3515,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st
//Verify dataset.
if( !mob->parse_dataset(&mobspawn) ) {
ShowError("npc_parse_mob: Invalid dataset for monster ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
@@ -3555,7 +3575,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st
* eg : bat_c01 mapflag battleground 2
* also chking if mapflag conflict with another
*------------------------------------------*/
-const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) {
+const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) {
int16 m;
char mapname[32];
int state = 1;
@@ -3564,11 +3584,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
m = map->mapname2mapid(mapname);
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);
+ if (retval) *retval = EXIT_FAILURE;
return strchr(start,'\n');// skip and continue
}
@@ -3590,6 +3612,7 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
map->list[m].save.y = savey;
if (!map->list[m].save.map) {
ShowWarning("npc_parse_mapflag: Specified save point map '%s' for mapflag 'nosave' not found in 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);
+ if (retval) *retval = EXIT_FAILURE;
map->list[m].save.x = -1;
map->list[m].save.y = -1;
}
@@ -3628,10 +3651,12 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
map->list[m].flag.gvg_dungeon = 0;
map->list[m].flag.gvg_castle = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( state && map->list[m].flag.battleground ) {
map->list[m].flag.battleground = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)) && map->list[m].zone != zone ) {
map->zone_change(m,zone,start,buffer,filepath);
@@ -3678,10 +3703,12 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
if( state && map->list[m].flag.pvp ) {
map->list[m].flag.pvp = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( state && map->list[m].flag.battleground ) {
map->list[m].flag.battleground = 0;
ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)) && map->list[m].zone != zone ) {
map->zone_change(m,zone,start,buffer,filepath);
@@ -3710,12 +3737,14 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
if( map->list[m].flag.battleground && map->list[m].flag.pvp ) {
map->list[m].flag.pvp = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( map->list[m].flag.battleground && (map->list[m].flag.gvg || map->list[m].flag.gvg_dungeon || map->list[m].flag.gvg_castle) ) {
map->list[m].flag.gvg = 0;
map->list[m].flag.gvg_dungeon = 0;
map->list[m].flag.gvg_castle = 0;
ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
}
if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) && map->list[m].zone != zone ) {
@@ -3818,10 +3847,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
if( modifier[0] == '\0' ) {
ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) {
ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n",skill_name, map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else {
int idx = map->list[m].unit_count;
@@ -3874,10 +3906,13 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
if( modifier[0] == '\0' ) {
ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else if( !( skill_id = skill->name2id(skill_name) ) ) {
ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", skill_name, map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else {
int idx = map->list[m].skill_count;
@@ -3916,6 +3951,7 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
if( !(zone = strdb_get(map->zone_db, w4)) ) {
ShowWarning("npc_parse_mapflag: Invalid zone '%s'! removing flag from %s in file '%s', line '%d'.\n", w4, map->list[m].name, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
} else if( map->list[m].zone != zone ) {
map->zone_change(m,zone,start,buffer,filepath);
}
@@ -3939,15 +3975,25 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
map->list[m].flag.src4instance = (state) ? 1 : 0;
} else if ( !strcmpi(w3,"nocashshop") ) {
map->list[m].flag.nocashshop = (state) ? 1 : 0;
- } else
+ } else {
ShowError("npc_parse_mapflag: unrecognized mapflag '%s' in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer));
+ if (retval) *retval = EXIT_FAILURE;
+ }
return strchr(start,'\n');// continue
}
-//Read file and create npc/func/mapflag/monster... accordingly.
-//@runOnInit should we exec OnInit when it's done ?
+/**
+ * Parses a script file and creates NPCs/functions/mapflags/monsters/etc
+ * accordingly.
+ *
+ * @param filepath File name and path.
+ * @param runOnInit Whether the OnInit label should be called.
+ * @retval EXIT_SUCCESS if filepath was loaded correctly.
+ * @retval EXIT_FAILURE if there were errors/warnings when loading filepath.
+ */
int npc_parsesrcfile(const char* filepath, bool runOnInit) {
+ int success = EXIT_SUCCESS;
int16 m, x, y;
int lines = 0;
FILE* fp;
@@ -3957,10 +4003,9 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
// read whole file to buffer
fp = fopen(filepath, "rb");
- if( fp == NULL )
- {
+ if( fp == NULL ) {
ShowError("npc_parsesrcfile: File not found '%s'.\n", filepath);
- return -1;
+ return EXIT_FAILURE;
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
@@ -3968,12 +4013,11 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
fseek(fp, 0, SEEK_SET);
len = fread(buffer, sizeof(char), len, fp);
buffer[len] = '\0';
- if( ferror(fp) )
- {
+ if( ferror(fp) ) {
ShowError("npc_parsesrcfile: Failed to read file '%s' - %s\n", filepath, strerror(errno));
aFree(buffer);
fclose(fp);
- return -1;
+ return EXIT_FAILURE;
}
fclose(fp);
@@ -3986,12 +4030,11 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
ShowError("npc_parsesrcfile: Detected unsupported UTF-8 BOM in file '%s'. Stopping (please consider using another character set.)\n", filepath);
aFree(buffer);
fclose(fp);
- return -1;
+ return EXIT_FAILURE;
}
// parse buffer
- for( p = script->skip_space(buffer); p && *p ; p = script->skip_space(p) )
- {
+ for( p = script->skip_space(buffer); p && *p ; p = script->skip_space(p) ) {
int pos[9];
char w1[2048], w2[2048], w3[2048], w4[2048];
int i, count;
@@ -4002,41 +4045,50 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
if( count < 0 )
{
ShowError("npc_parsesrcfile: Parse error in file '%s', line '%d'. Stopping...\n", filepath, strline(buffer,p-buffer));
+ success = EXIT_FAILURE;
break;
}
// fill w1
- if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 )
+ if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 ) {
ShowWarning("npc_parsesrcfile: w1 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[3]-pos[2], filepath, strline(buffer,p-buffer));
+ success = EXIT_FAILURE;
+ }
i = min(pos[3]-pos[2], ARRAYLENGTH(w1)-1);
memcpy(w1, p+pos[2], i*sizeof(char));
w1[i] = '\0';
// fill w2
- if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 )
+ if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 ) {
ShowWarning("npc_parsesrcfile: w2 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[5]-pos[4], filepath, strline(buffer,p-buffer));
+ success = EXIT_FAILURE;
+ }
i = min(pos[5]-pos[4], ARRAYLENGTH(w2)-1);
memcpy(w2, p+pos[4], i*sizeof(char));
w2[i] = '\0';
// fill w3
- if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 )
+ if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 ) {
ShowWarning("npc_parsesrcfile: w3 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[7]-pos[6], filepath, strline(buffer,p-buffer));
+ success = EXIT_FAILURE;
+ }
i = min(pos[7]-pos[6], ARRAYLENGTH(w3)-1);
memcpy(w3, p+pos[6], i*sizeof(char));
w3[i] = '\0';
// fill w4 (to end of line)
- if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 )
+ if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 ) {
ShowWarning("npc_parsesrcfile: w4 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[1]-pos[8], filepath, strline(buffer,p-buffer));
- if( pos[8] != -1 )
- {
+ success = EXIT_FAILURE;
+ }
+ if( pos[8] != -1 ) {
i = min(pos[1]-pos[8], ARRAYLENGTH(w4)-1);
memcpy(w4, p+pos[8], i*sizeof(char));
w4[i] = '\0';
- }
- else
+ } else {
w4[0] = '\0';
+ }
- if( count < 3 )
- {// Unknown syntax
+ if( count < 3 ) {
+ // Unknown syntax
ShowError("npc_parsesrcfile: Unknown syntax in file '%s', line '%d'. Stopping...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4);
+ success = EXIT_FAILURE;
break;
}
@@ -4045,13 +4097,12 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
char mapname[MAP_NAME_LENGTH*2];
x = y = 0;
sscanf(w1,"%23[^,],%hd,%hd[^,]",mapname,&x,&y);
- if( !mapindex->name2id(mapname) )
- {// Incorrect map, we must skip the script info...
+ if( !mapindex->name2id(mapname) ) {
+ // Incorrect map, we must skip the script info...
ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'. Skipping line...\n", mapname, filepath, strline(buffer,p-buffer));
- if( strcmp(w2,"script") == 0 && count > 3 )
- {
- if((p = npc->skip_script(p,buffer,filepath)) == NULL)
- {
+ success = EXIT_FAILURE;
+ if( strcmp(w2,"script") == 0 && count > 3 ) {
+ if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) {
break;
}
}
@@ -4061,10 +4112,8 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
m = map->mapname2mapid(mapname);
if( m < 0 ) {
// "mapname" is not assigned to this server, we must skip the script info...
- if( strcmp(w2,"script") == 0 && count > 3 )
- {
- if((p = npc->skip_script(p,buffer,filepath)) == NULL)
- {
+ if( strcmp(w2,"script") == 0 && count > 3 ) {
+ if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) {
break;
}
}
@@ -4073,10 +4122,9 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
}
if (x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys) {
ShowError("npc_parsesrcfile: Unknown coordinates ('%d', '%d') for map '%s' in file '%s', line '%d'. Skipping line...\n", x, y, mapname, filepath, strline(buffer,p-buffer));
- if( strcmp(w2,"script") == 0 && count > 3 )
- {
- if((p = npc->skip_script(p,buffer,filepath)) == NULL)
- {
+ success = EXIT_FAILURE;
+ if( strcmp(w2,"script") == 0 && count > 3 ) {
+ if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) {
break;
}
}
@@ -4087,37 +4135,37 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
if( strcmp(w2,"warp") == 0 && count > 3 )
{
- p = npc->parse_warp(w1,w2,w3,w4, p, buffer, filepath);
+ p = npc->parse_warp(w1,w2,w3,w4, p, buffer, filepath, &success);
}
else if( (strcmp(w2,"shop") == 0 || strcmp(w2,"cashshop") == 0) && count > 3 )
{
- p = npc->parse_shop(w1,w2,w3,w4, p, buffer, filepath);
+ p = npc->parse_shop(w1,w2,w3,w4, p, buffer, filepath, &success);
}
else if( strcmp(w2,"script") == 0 && count > 3 )
{
if( strcmp(w1,"function") == 0 ) {
- p = npc->parse_function(w1, w2, w3, w4, p, buffer, filepath);
+ p = npc->parse_function(w1, w2, w3, w4, p, buffer, filepath, &success);
} else {
#ifdef ENABLE_CASE_CHECK
if( strcasecmp(w1, "function") == 0 ) DeprecationWarning("npc_parsesrcfile", w1, "function", filepath, strline(buffer, p-buffer)); // TODO
#endif // ENABLE_CASE_CHECK
- p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit?NPO_ONINIT:NPO_NONE);
+ p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit?NPO_ONINIT:NPO_NONE, &success);
}
}
else if( strcmp(w2,"trader") == 0 && count > 3 ) {
- p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,(runOnInit?NPO_ONINIT:NPO_NONE)|NPO_TRADER);
+ p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,(runOnInit?NPO_ONINIT:NPO_NONE)|NPO_TRADER, &success);
}
else if( (i=0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) && count > 3 )
{
- p = npc->parse_duplicate(w1,w2,w3,w4, p, buffer, filepath, (runOnInit?NPO_ONINIT:NPO_NONE));
+ p = npc->parse_duplicate(w1,w2,w3,w4, p, buffer, filepath, (runOnInit?NPO_ONINIT:NPO_NONE), &success);
}
else if( (strcmp(w2,"monster") == 0 || strcmp(w2,"boss_monster") == 0) && count > 3 )
{
- p = npc->parse_mob(w1, w2, w3, w4, p, buffer, filepath);
+ p = npc->parse_mob(w1, w2, w3, w4, p, buffer, filepath, &success);
}
else if( strcmp(w2,"mapflag") == 0 && count >= 3 )
{
- p = npc->parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath);
+ p = npc->parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath, &success);
}
else
{
@@ -4139,11 +4187,12 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
#endif // ENABLE_CASE_CHECK
ShowError("npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in file '%s', line '%d'. Skipping line...\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
+ success = EXIT_FAILURE;
}
}
aFree(buffer);
- return 0;
+ return success;
}
int npc_script_event(struct map_session_data* sd, enum npce_event type)