summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/map.h4
-rw-r--r--src/map/npc.c156
2 files changed, 94 insertions, 66 deletions
diff --git a/src/map/map.h b/src/map/map.h
index 4a0223610..5cef74b07 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -830,8 +830,8 @@ struct npc_data {
short n;
short class_;
short speed;
- char name[NAME_LENGTH];
- char exname[NAME_LENGTH];
+ char name[NAME_LENGTH+1];// display name
+ char exname[NAME_LENGTH+1];// unique npc name
int chat_id;
unsigned int next_walktime;
diff --git a/src/map/npc.c b/src/map/npc.c
index 7e442e615..9b86ff367 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -94,7 +94,7 @@ int npc_enable_sub(struct block_list *bl, va_list ap)
nullpo_retr(0, nd=va_arg(ap,struct npc_data *));
if(bl->type == BL_PC && (sd=(struct map_session_data *)bl))
{
- char name[50]; // need 24 + 9 for the "::OnTouch"
+ char name[NAME_LENGTH*2+3];
if (nd->sc.option&OPTION_INVISIBLE) // 無効化されている
return 1;
@@ -103,7 +103,7 @@ int npc_enable_sub(struct block_list *bl, va_list ap)
return 1;
sd->areanpc_id=nd->bl.id;
- snprintf(name, 50, "%s::OnTouch", nd->exname); // exname to be specific. exname is the unique identifier for script events. [Lance]
+ snprintf(name, ARRAYLENGTH(name), "%s::OnTouch", nd->exname); // exname to be specific. exname is the unique identifier for script events. [Lance]
npc_event(sd,name,0);
}
//aFree(name);
@@ -194,7 +194,7 @@ int npc_event_export(char* lname, void* data, va_list ap)
if ((lname[0]=='O' || lname[0]=='o')&&(lname[1]=='N' || lname[1]=='n')) {
struct event_data *ev;
- char buf[51];
+ char buf[NAME_LENGTH*2+3];
char* p = strchr(lname, ':');
// エクスポートされる
ev = (struct event_data *) aMalloc(sizeof(struct event_data));
@@ -208,7 +208,7 @@ int npc_event_export(char* lname, void* data, va_list ap)
ev->nd = nd;
ev->pos = pos;
*p = '\0';
- sprintf(buf, "%s::%s", nd->exname, lname);
+ snprintf(buf, ARRAYLENGTH(buf), "%s::%s", nd->exname, lname);
*p = ':';
strdb_put(ev_db, buf, ev);
}
@@ -561,9 +561,9 @@ void npc_timerevent_quit(struct map_session_data* sd)
sd->npc_timer_id = -1;
if (nd && nd->bl.type == BL_NPC)
{ //Execute OnTimerQuit
- char buf[sizeof(nd->exname)+sizeof("::OnTimerQuit")+1];
+ char buf[NAME_LENGTH*2+3];
struct event_data *ev;
- sprintf(buf,"%s::OnTimerQuit",nd->exname);
+ snprintf(buf, ARRAYLENGTH(buf), "%s::OnTimerQuit", nd->exname);
ev = strdb_get(ev_db, buf);
if(ev && ev->nd != nd) {
ShowWarning("npc_timerevent_quit: Unable to execute \"OnTimerQuit\", two NPCs have the same event name [%s]!\n",buf);
@@ -765,14 +765,13 @@ int npc_touch_areanpc(struct map_session_data* sd, int m, int x, int y)
break;
case SCRIPT:
{
- //char *name=(char *)aCallocA(50,sizeof(char)); // fixed [Shinomori]
- char name[50]; // need 24 max + 9 for "::OnTouch"
+ char name[NAME_LENGTH*2+3];
if(sd->areanpc_id == map[m].npc[i]->bl.id)
return 1;
sd->areanpc_id = map[m].npc[i]->bl.id;
- sprintf(name,"%s::OnTouch", map[m].npc[i]->exname); // It goes here too. exname being the unique identifier. [Lance]
+ snprintf(name, ARRAYLENGTH(name), "%s::OnTouch", map[m].npc[i]->exname); // It goes here too. exname being the unique identifier. [Lance]
if( npc_event(sd,name,0)>0 ) {
pc_stop_walking(sd,1); //Make it stop walking!
@@ -1032,11 +1031,11 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
//npc_buylist for script-controlled shops.
static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd)
{
- char npc_ev[51];
+ char npc_ev[NAME_LENGTH*2+3];
int i;
int regkey = add_str("@bought_nameid");
int regkey2 = add_str("@bought_quantity");
- sprintf(npc_ev, "%s::OnBuyItem", nd->exname);
+ snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname);
for(i=0;i<n;i++){
pc_setreg(sd,regkey+(i<<24),(int)item_list[i*2+1]);
pc_setreg(sd,regkey2+(i<<24),(int)item_list[i*2]);
@@ -1214,8 +1213,8 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
}
if(nd) {
- char npc_ev[51];
- sprintf(npc_ev, "%s::OnSellItem", nd->exname);
+ char npc_ev[NAME_LENGTH*2+3];
+ snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname);
npc_event(sd, npc_ev, 0);
}
@@ -1302,7 +1301,7 @@ int npc_unload(struct npc_data* nd)
npc_remove_map(nd);
map_deliddb(&nd->bl);
- strdb_remove(npcname_db, (nd->bl.subtype < SCRIPT) ? nd->name : nd->exname);
+ strdb_remove(npcname_db, nd->exname);
if (nd->chat_id) // remove npc chatroom object and kick users
chat_deletenpcchat(nd);
@@ -1418,6 +1417,72 @@ void npc_delsrcfile(const char* name)
}
}
+/// Parses and sets the name and exname of a npc.
+/// Assumes that m, x and y are already set in nd.
+static void npc_parsename(struct npc_data* nd, const char* name, const char* start, const char* buffer, const char* filepath)
+{
+ const char* p;
+ struct npc_data* dnd;
+ char newname[NAME_LENGTH];
+
+ // parse name
+ p = strstr(name,"::");
+ if( p )
+ {// <Display name>::<Unique name>
+ size_t len = p-name;
+ if( len >= NAME_LENGTH )
+ {
+ ShowWarning("npc_parsename: Display name of '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH);
+ safestrncpy(nd->name, name, sizeof(nd->name));
+ }
+ else
+ {
+ memcpy(nd->name, name, len);
+ memset(nd->name+len, 0, sizeof(nd->name)-len);
+ }
+ len = strlen(p+2);
+ if( len >= NAME_LENGTH )
+ ShowWarning("npc_parsename: Unique name of '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH);
+ safestrncpy(nd->exname, p+2, sizeof(nd->exname));
+ }
+ else
+ {// <Display name>
+ size_t len = strlen(name);
+ if( len >= NAME_LENGTH )
+ ShowWarning("npc_parsename: Name '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH);
+ safestrncpy(nd->name, name, sizeof(nd->name));
+ safestrncpy(nd->exname, name, sizeof(nd->exname));
+ }
+
+ if( *nd->exname == '\0' || strstr(nd->exname,"::") != NULL )
+ {// invalid
+ snprintf(newname, ARRAYLENGTH(newname), "0_%d_%d_%d", nd->bl.m, nd->bl.x, nd->bl.y);
+ ShowWarning("npc_parsename: Invalid unique name in file '%s', line'%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname);
+ safestrncpy(nd->exname, newname, sizeof(nd->exname));
+ }
+
+ if( *nd->exname == '\0' || (dnd=npc_name2id(nd->exname)) != NULL )
+ {// duplicate unique name, generate new one
+ char this_mapname[32];
+ char other_mapname[32];
+ int i = 0;
+ do
+ {
+ ++i;
+ snprintf(newname, ARRAYLENGTH(newname), "%d_%d_%d_%d", i, nd->bl.m, nd->bl.x, nd->bl.y);
+ }
+ while( npc_name2id(newname) != NULL );
+
+ strcpy(this_mapname, (nd->bl.m==-1?"(not on a map)":mapindex_id2name(nd->bl.m)));
+ strcpy(other_mapname, (dnd->bl.m==-1?"(not on a map)":mapindex_id2name(dnd->bl.m)));
+
+ ShowWarning("npc_parsename: Duplicate unique name in file '%s', line'%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname);
+ ShowDebug("this npc:\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n", nd->name, nd->exname, this_mapname, nd->bl.x, nd->bl.y);
+ ShowDebug("other npc:\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n", dnd->name, dnd->exname, other_mapname, dnd->bl.x, dnd->bl.y);
+ safestrncpy(nd->exname, newname, sizeof(nd->exname));
+ }
+}
+
/// 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)
{
@@ -1451,8 +1516,7 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
nd->bl.m = m;
nd->bl.x = x;
nd->bl.y = y;
- safestrncpy(nd->name, w3, sizeof(nd->name));
- safestrncpy(nd->exname, w3, sizeof(nd->exname));
+ npc_parsename(nd, w3, start, buffer, filepath);
if (!battle_config.warp_point_debug)
nd->class_ = WARP_CLASS;
@@ -1476,7 +1540,7 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
status_change_init(&nd->bl);
unit_dataset(&nd->bl);
clif_spawn(&nd->bl);
- strdb_put(npcname_db, nd->name, nd);
+ strdb_put(npcname_db, nd->exname, nd);
return strchr(start,'\n');// continue
}
@@ -1546,7 +1610,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
nd->bl.x = x;
nd->bl.y = y;
nd->bl.id = npc_get_new_npc_id();
- safestrncpy(nd->name, w3, sizeof(nd->name));
+ npc_parsename(nd, w3, start, buffer, filepath);
nd->class_ = m==-1?-1:atoi(w4);
nd->speed = 200;
@@ -1566,7 +1630,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
{// 'floating' shop?
map_addiddb(&nd->bl);
}
- strdb_put(npcname_db, nd->name, nd);
+ strdb_put(npcname_db, nd->exname, nd);
return strchr(start,'\n');// continue
}
@@ -1680,7 +1744,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
char mapname[32];
struct script_code *script;
int i;
- char *p;
+ const char* end;
struct npc_label_list* label_list;
int label_list_num;
@@ -1697,9 +1761,9 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
else
{// npc in a map
if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4
- || (strcmp(w2, "script") == 0 && strchr(w4,',') == NULL) )
+ || (strcasecmp(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);
+ 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);
@@ -1708,7 +1772,6 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
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 )
@@ -1729,6 +1792,8 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
else
{// duplicate npc
char srcname[128];
+
+ end = strchr(start,'\n');
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);
@@ -1761,39 +1826,11 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
nd->u.scr.ys = 0;
}
- // extended name
- p = strstr(w3,"::");
- if( p )
- {
- *p = '\0';
- safestrncpy(nd->name, w3, sizeof(nd->name));
- safestrncpy(nd->exname, p+2, sizeof(nd->exname));
- }
- else
- {
- safestrncpy(nd->name, w3, sizeof(nd->name));
- safestrncpy(nd->exname, w3, sizeof(nd->exname));
- }
-
- 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;
nd->bl.m = m;
nd->bl.x = x;
nd->bl.y = y;
+ npc_parsename(nd, w3, start, buffer, filepath);
nd->bl.id = npc_get_new_npc_id();
nd->class_ = class_;
nd->speed = 200;
@@ -1814,15 +1851,6 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
nd->ud.dir = dir;
npc_setcells(nd);
map_addblock(&nd->bl);
- // Unused. You can always use xxx::OnXXXX events. Have this removed to improve perfomance.
- /*if (evflag) { // イベント型
- struct event_data *ev = (struct event_data *)aCalloc(1, sizeof(struct event_data));
- ev->nd = nd;
- ev->pos = 0;
- strdb_put(ev_db, nd->exname, ev);
- } else {
- clif_spawn(&nd->bl);
- }*/
if( class_ >= 0 )
{
status_set_viewdata(&nd->bl, nd->class_);
@@ -1846,8 +1874,8 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n'))
{
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);
+ char buf[NAME_LENGTH*2+3]; // 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS
+ snprintf(buf, ARRAYLENGTH(buf), "%s::%s", nd->exname, lname);
// generate the data and insert it
CREATE(ev, struct event_data, 1);
@@ -1886,7 +1914,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
}
nd->u.scr.timerid = -1;
- return 0;
+ return end;
}
void npc_setcells(struct npc_data* nd)