diff options
Diffstat (limited to 'src/map/npc.c')
-rw-r--r-- | src/map/npc.c | 1028 |
1 files changed, 647 insertions, 381 deletions
diff --git a/src/map/npc.c b/src/map/npc.c index b1f9c54ec..069597f83 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -15,29 +15,39 @@ #include "clif.h" #include "intif.h" #include "pc.h" +#include "status.h" #include "itemdb.h" #include "script.h" #include "mob.h" #include "pet.h" #include "battle.h" #include "skill.h" +#include "grfio.h" +#include "showmsg.h" #ifdef MEMWATCH #include "memwatch.h" #endif - +#ifdef _WIN32 +#undef isspace +#define isspace(x) (x == ' ' || x == '\t') +#endif struct npc_src_list { struct npc_src_list * next; - struct npc_src_list * prev; +// struct npc_src_list * prev; //[Shinomori] char name[4]; -} ; +}; -static struct npc_src_list *npc_src_first,*npc_src_last; +static struct npc_src_list *npc_src_first=NULL; +static struct npc_src_list *npc_src_last=NULL; static int npc_id=START_NPC_NUM; -static int npc_warp,npc_shop,npc_script,npc_mob; - +static int npc_warp=0; +static int npc_shop=0; +static int npc_script=0; +static int npc_mob=0; +char *current_file = NULL; int npc_get_new_npc_id(void){ return npc_id++; } static struct dbt *ev_db; @@ -62,31 +72,33 @@ int npc_enable_sub( struct block_list *bl, va_list ap ) { struct map_session_data *sd; struct npc_data *nd; - char *name=(char *)aCalloc(50,sizeof(char)); + //char *name=(char *)aCallocA(50,sizeof(char)); // fixed [Shinomori] nullpo_retr(0, bl); nullpo_retr(0, 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" if (nd->flag&1) // 無効化されている return 1; - memcpy(name,nd->name,50); if(sd->areanpc_id==nd->bl.id) return 1; sd->areanpc_id=nd->bl.id; - npc_event(sd,strcat(name,"::OnTouch"),0); + + sprintf(name,"%s::OnTouch", nd->name); + npc_event(sd,name,0); } - free(name); + //aFree(name); return 0; } int npc_enable(const char *name,int flag) { - struct npc_data *nd=strdb_search(npcname_db,name); + struct npc_data *nd= (struct npc_data *) strdb_search(npcname_db,name); if (nd==NULL) return 0; - + if (flag&1) { // 有効化 nd->flag&=~1; clif_spawnnpc(nd); @@ -114,8 +126,17 @@ int npc_enable(const char *name,int flag) */ struct npc_data* npc_name2id(const char *name) { - return strdb_search(npcname_db,name); + return (struct npc_data *) strdb_search(npcname_db,name); +} + +void ev_release(struct dbn *db, int which) +{ + if (which & 0x1) + aFree(db->key); + if (which & 0x2) + aFree(db->data); } + /*========================================== * イベントキューのイベント処理 *------------------------------------------ @@ -126,47 +147,69 @@ int npc_event_dequeue(struct map_session_data *sd) sd->npc_id=0; if (sd->eventqueue[0][0]) { // キューのイベント処理 - char *name=(char *)aCalloc(50,sizeof(char)); - int i; + size_t ev; - memcpy(name,sd->eventqueue[0],50); - for(i=MAX_EVENTQUEUE-2;i>=0;i--) - memcpy(sd->eventqueue[i],sd->eventqueue[i+1],50); - add_timer(gettick()+100,npc_event_timer,sd->bl.id,(int)name); + // find an empty place in eventtimer list + for(ev=0;ev<MAX_EVENTTIMER;ev++) + if( sd->eventtimer[ev]==-1 ) + break; + if(ev<MAX_EVENTTIMER) + { // generate and insert the timer + int i; + // copy the first event name + char *name=(char *)aMalloc(50*sizeof(char)); + memcpy(name,sd->eventqueue[0],50); + // shift queued events down by one + for(i=1;i<MAX_EVENTQUEUE;i++) + memcpy(sd->eventqueue[i-1],sd->eventqueue[i],50); + // clear the last event + sd->eventqueue[MAX_EVENTQUEUE-1][0]=0; + // add the timer + sd->eventtimer[ev]=add_timer(gettick()+100,pc_eventtimer,sd->bl.id,(int)name);//!!todo!! + + }else + printf("npc_event_dequeue: event timer is full !\n"); } return 0; } -int npc_delete(struct npc_data *nd) -{ - nullpo_retr(1, nd); - - if(nd->bl.prev == NULL) - return 1; - - clif_clearchar_area(&nd->bl,1); - map_delblock(&nd->bl); - return 0; -} - /*========================================== * イベントの遅延実行 *------------------------------------------ */ int npc_event_timer(int tid,unsigned int tick,int id,int data) { + char *eventname = (char *)data; + struct event_data *ev = (struct event_data *)strdb_search(ev_db,eventname); + struct npc_data *nd; struct map_session_data *sd=map_id2sd(id); - if (sd==NULL) - return 0; - - npc_event(sd,(const char *)data,0); - free((void*)data); + size_t i; + + if((ev==NULL || (nd=ev->nd)==NULL)) + { + if(battle_config.error_log) + printf("npc_event: event not found [%s]\n",eventname); + } + else + { + for(i=0;i<MAX_EVENTTIMER;i++) { + if( nd->eventtimer[i]==tid ) { + nd->eventtimer[i]=-1; + npc_event(sd,eventname,0); // sd NULL check is within + break; + } + } + if(i==MAX_EVENTTIMER && battle_config.error_log) + printf("npc_event_timer: event timer not found [%s]!\n",eventname); + } + + aFree(eventname); return 0; } int npc_timer_event(const char *eventname) // Added by RoVeRT { - struct event_data *ev=strdb_search(ev_db,eventname); + struct event_data *ev=(struct event_data *) strdb_search(ev_db,eventname); struct npc_data *nd; // int xs,ys; @@ -220,7 +263,7 @@ int npc_timer(int tid,unsigned int tick,int id,int data) // Added by RoVeRT { strdb_foreach(npcname_db,npc_timer_sub); - free((void*)data); + aFree((void*)data); return 0; }*/ /*========================================== @@ -233,14 +276,14 @@ int npc_event_export(void *key,void *data,va_list ap) char *lname=(char *)key; int pos=(int)data; struct npc_data *nd=va_arg(ap,struct npc_data *); - + if ((lname[0]=='O' || lname[0]=='o')&&(lname[1]=='N' || lname[1]=='n')) { struct event_data *ev; char *buf; char *p=strchr(lname,':'); // エクスポートされる - ev=calloc(sizeof(struct event_data), 1); - buf=calloc(50, 1); + ev=(struct event_data *) aCalloc(sizeof(struct event_data), 1); + buf=(char *) aCallocA(50, 1); if (ev==NULL || buf==NULL) { printf("npc_event_export: out of memory !\n"); exit(1); @@ -261,62 +304,6 @@ int npc_event_export(void *key,void *data,va_list ap) return 0; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*========================================== * 全てのNPCのOn*イベント実行 *------------------------------------------ @@ -326,29 +313,39 @@ int npc_event_doall_sub(void *key,void *data,va_list ap) char *p=(char *)key; struct event_data *ev; int *c; + int rid; const char *name; nullpo_retr(0, ev=(struct event_data *)data); nullpo_retr(0, ap); nullpo_retr(0, c=va_arg(ap,int *)); - name=va_arg(ap,const char *); + rid=va_arg(ap, int); if( (p=strchr(p,':')) && p && strcmpi(name,p)==0 ){ - run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id); + run_script(ev->nd->u.scr.script,ev->pos,rid,ev->nd->bl.id); (*c)++; } - + return 0; } int npc_event_doall(const char *name) { int c=0; char buf[64]="::"; - + + strncpy(buf+2,name,62); + strdb_foreach(ev_db,npc_event_doall_sub,&c,buf,0); + return c; +} +int npc_event_doall_id(const char *name, int rid) +{ + int c=0; + char buf[64]="::"; + strncpy(buf+2,name,62); - strdb_foreach(ev_db,npc_event_doall_sub,&c,buf); - return c; + strdb_foreach(ev_db,npc_event_doall_sub,&c,buf,rid); + return c; } int npc_event_do_sub(void *key,void *data,va_list ap) @@ -374,7 +371,7 @@ int npc_event_do_sub(void *key,void *data,va_list ap) int npc_event_do(const char *name) { int c=0; - + if (*name==':' && name[1]==':') { return npc_event_doall(name+2); } @@ -394,7 +391,7 @@ int npc_event_do_clock(int tid,unsigned int tick,int id,int data) char buf[64]; char *day=""; int c=0; - + time(&timer); t=localtime(&timer); @@ -407,7 +404,7 @@ int npc_event_do_clock(int tid,unsigned int tick,int id,int data) case 5: day = "Fri"; break; case 6: day = "Sat"; break; } - + if (t->tm_min != ev_tm_b.tm_min ) { sprintf(buf,"OnMinute%02d",t->tm_min); c+=npc_event_doall(buf); @@ -433,8 +430,10 @@ int npc_event_do_clock(int tid,unsigned int tick,int id,int data) */ int npc_event_do_oninit(void) { - int c = npc_event_doall("OnInit"); - printf("npc: OnInit Event done. (%d npc)\n",c); +// int c = npc_event_doall("OnInit"); + sprintf(tmp_output,"Event '"CL_WHITE"OnInit"CL_RESET"' executed with '" + CL_WHITE"%d"CL_RESET"' NPCs.\n",npc_event_doall("OnInit")); + ShowStatus(tmp_output); add_timer_interval(gettick()+100, npc_event_do_clock,0,0,1000); @@ -452,7 +451,7 @@ int npc_addeventtimer(struct npc_data *nd,int tick,const char *name) if( nd->eventtimer[i]==-1 ) break; if(i<MAX_EVENTTIMER){ - char *evname=malloc(24); + char *evname=(char *) aMallocA(24); if(evname==NULL){ printf("npc_addeventtimer: out of memory !\n");exit(1); } @@ -493,33 +492,33 @@ int npc_cleareventtimer(struct npc_data *nd) int npc_do_ontimer_sub(void *key,void *data,va_list ap) { - char *p=(char *)key; - struct event_data *ev=(struct event_data *)data; - int *c=va_arg(ap,int *); + char *p = (char *)key; + struct event_data *ev = (struct event_data *)data; + int *c = va_arg(ap,int *); // struct map_session_data *sd=va_arg(ap,struct map_session_data *); - int option=va_arg(ap,int); - int tick=0; + int option = va_arg(ap,int); + int tick = 0; char temp[10]; char event[50]; - if(ev->nd->bl.id==(int)*c && (p=strchr(p,':')) && p && strnicmp("::OnTimer",p,8)==0 ){ - sscanf(&p[9],"%s",temp); - tick=atoi(temp); + if(ev->nd->bl.id == (int)*c && (p = strchr(p,':')) && strnicmp("::OnTimer",p,8) == 0){ + sscanf(&p[9], "%s", temp); + tick = atoi(temp); - strcpy( event, ev->nd->name); - strcat( event, p); + strcpy(event, ev->nd->name); + strcat(event, p); if (option!=0) { - npc_addeventtimer(ev->nd,tick,event); + npc_addeventtimer(ev->nd, tick, event); } else { - npc_deleventtimer(ev->nd,event); + npc_deleventtimer(ev->nd, event); } } return 0; } -int npc_do_ontimer(int npc_id, struct map_session_data *sd, int option) +int npc_do_ontimer(int npc_id, int option) { - strdb_foreach(ev_db,npc_do_ontimer_sub,&npc_id,sd,option); + strdb_foreach(ev_db, npc_do_ontimer_sub, &npc_id, option); return 0; } /*========================================== @@ -533,13 +532,13 @@ int npc_timerevent_import(void *key,void *data,va_list ap) int pos=(int)data; struct npc_data *nd=va_arg(ap,struct npc_data *); int t=0,i=0; - + if(sscanf(lname,"OnTimer%d%n",&t,&i)==1 && lname[i]==':') { // タイマーイベント struct npc_timerevent_list *te=nd->u.scr.timer_event; int j,i=nd->u.scr.timeramount; - if(te==NULL) te=malloc(sizeof(struct npc_timerevent_list)); - else te=realloc( te, sizeof(struct npc_timerevent_list) * (i+1) ); + if(te==NULL) te=(struct npc_timerevent_list*)aMallocA(sizeof(struct npc_timerevent_list)); + else te= (struct npc_timerevent_list*)aRealloc( te, sizeof(struct npc_timerevent_list) * (i+1) ); if(te==NULL){ printf("npc_timerevent_import: out of memory !\n"); exit(1); @@ -573,7 +572,7 @@ int npc_timerevent(int tid,unsigned int tick,int id,int data) nd->u.scr.timertick=tick; te=nd->u.scr.timer_event+ nd->u.scr.nexttimer; nd->u.scr.timerid = -1; - + t = nd->u.scr.timer+=data; nd->u.scr.nexttimer++; if( nd->u.scr.timeramount>nd->u.scr.nexttimer ){ @@ -581,14 +580,14 @@ int npc_timerevent(int tid,unsigned int tick,int id,int data) nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,next); } - run_script(nd->u.scr.script,te->pos,0,nd->bl.id); + run_script(nd->u.scr.script,te->pos,nd->u.scr.rid,nd->bl.id); return 0; } /*========================================== * タイマーイベント開始 *------------------------------------------ */ -int npc_timerevent_start(struct npc_data *nd) +int npc_timerevent_start(struct npc_data *nd, int rid) { int j,n, next; @@ -597,17 +596,19 @@ int npc_timerevent_start(struct npc_data *nd) n=nd->u.scr.timeramount; if( nd->u.scr.nexttimer>=0 || n==0 ) return 0; - + for(j=0;j<n;j++){ if( nd->u.scr.timer_event[j].timer > nd->u.scr.timer ) break; } + if(j>=n) // check if there is a timer to use !!BEFORE!! you write stuff to the structures [Shinomori] + return 0; + nd->u.scr.nexttimer=j; nd->u.scr.timertick=gettick(); + if (rid >= 0) nd->u.scr.rid=rid; // changed to: attaching to given rid by default [Shinomori] + // if rid is less than 0 leave it unchanged [celest] - if(j>=n) - return 0; - next = nd->u.scr.timer_event[j].timer - nd->u.scr.timer; nd->u.scr.timerid = add_timer(gettick()+next,npc_timerevent,nd->bl.id,next); return 0; @@ -626,6 +627,7 @@ int npc_timerevent_stop(struct npc_data *nd) if(nd->u.scr.timerid!=-1) delete_timer(nd->u.scr.timerid,npc_timerevent); nd->u.scr.timerid = -1; + nd->u.scr.rid = 0; } return 0; } @@ -660,7 +662,7 @@ int npc_settimerevent_tick(struct npc_data *nd,int newtimer) npc_timerevent_stop(nd); nd->u.scr.timer=newtimer; if(flag>=0) - npc_timerevent_start(nd); + npc_timerevent_start(nd, -1); return 0; } @@ -670,7 +672,7 @@ int npc_settimerevent_tick(struct npc_data *nd,int newtimer) */ int npc_event(struct map_session_data *sd,const char *eventname,int mob_kill) { - struct event_data *ev=strdb_search(ev_db,eventname); + struct event_data *ev=(struct event_data *) strdb_search(ev_db,eventname); struct npc_data *nd; int xs,ys; char mobevent[100]; @@ -686,7 +688,7 @@ int npc_event(struct map_session_data *sd,const char *eventname,int mob_kill) if(mob_kill && (ev==NULL || (nd=ev->nd)==NULL)){ strcpy( mobevent, eventname); strcat( mobevent, "::OnMyMobDead"); - ev=strdb_search(ev_db,mobevent); + ev= (struct event_data *) strdb_search(ev_db,mobevent); if (ev==NULL || (nd=ev->nd)==NULL) { if (strnicmp(eventname,"GM_MONSTER",10)!=0) printf("npc_event: event not found [%s]\n",mobevent); @@ -732,7 +734,7 @@ int npc_event(struct map_session_data *sd,const char *eventname,int mob_kill) npc_event_dequeue(sd); return 0; } - + sd->npc_id=nd->bl.id; sd->npc_pos=run_script(nd->u.scr.script,ev->pos,sd->bl.id,nd->bl.id); return 0; @@ -753,7 +755,7 @@ int npc_command_sub(void *key,void *data,va_list ap) if (strcmp(command,temp)==0) run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id); } - + return 0; } @@ -782,7 +784,7 @@ int npc_touch_areanpc(struct map_session_data *sd,int m,int x,int y) f=0; continue; } - + switch(map[m].npc[i]->bl.subtype) { case WARP: xs=map[m].npc[i]->u.warp.xs; @@ -813,15 +815,18 @@ int npc_touch_areanpc(struct map_session_data *sd,int m,int x,int y) break; case SCRIPT: { - char *name=(char *)aCalloc(50,sizeof(char)); + //char *name=(char *)aCallocA(50,sizeof(char)); // fixed [Shinomori] + char name[50]; // need 24 max + 9 for "::OnTouch" - memcpy(name,map[m].npc[i]->name,50); - if(sd->areanpc_id==map[m].npc[i]->bl.id) + if(sd->areanpc_id == map[m].npc[i]->bl.id) return 1; - sd->areanpc_id=map[m].npc[i]->bl.id; - if(npc_event(sd,strcat(name,"::OnTouch"),0)>0) + sd->areanpc_id = map[m].npc[i]->bl.id; + + sprintf(name,"%s::OnTouch", map[m].npc[i]->name); + + if( npc_event(sd,name,0)>0 ) npc_click(sd,map[m].npc[i]->bl.id); - free(name); + //aFree(name); break; } } @@ -844,8 +849,8 @@ int npc_checknear(struct map_session_data *sd,int id) printf("no such npc : %d\n",id); return 1; } - - if (nd->class<0) // イベント系は常にOK + + if (nd->class_<0) // イベント系は常にOK return 0; // エリア判定 @@ -858,6 +863,32 @@ int npc_checknear(struct map_session_data *sd,int id) } /*========================================== + * NPCのオープンチャット発言 + *------------------------------------------ + */ +int npc_globalmessage(const char *name,char *mes) +{ + struct npc_data *nd=(struct npc_data *) strdb_search(npcname_db,name); + char temp[100]; + char ntemp[50]; + char *ltemp; + + if(nd==NULL) return 0; + if(name==NULL) return 0; + + ltemp=strchr(name,'#'); + if(ltemp!=NULL) { + strncpy(ntemp,name,ltemp - name); // 123#456 の # から後ろを削除する + ntemp[ltemp - name]=0x00; // strncpy のバグ?使い方間違ってる? + } + + snprintf(temp, sizeof temp ,"%s : %s",ntemp,mes); + clif_GlobalMessage(&nd->bl,temp); + + return 0; +} + +/*========================================== * クリック時のNPC処理 *------------------------------------------ */ @@ -957,7 +988,7 @@ int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list) { struct npc_data *nd; double z; - int i,j,w,skill,itemamount=0,new=0; + int i,j,w,skill,itemamount=0,new_=0; nullpo_retr(3, sd); nullpo_retr(3, item_list); @@ -987,7 +1018,7 @@ int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list) case ADDITEM_EXIST: break; case ADDITEM_NEW: - new++; + new_++; break; case ADDITEM_OVERAMOUNT: return 2; @@ -999,7 +1030,7 @@ int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list) return 1; // zeny不足 if (w+sd->weight > sd->max_weight) return 2; // 重量超過 - if (pc_inventoryblank(sd)<new) + if (pc_inventoryblank(sd)<new_) return 3; // 種類数超過 pc_payzeny(sd,(int)z); @@ -1014,7 +1045,7 @@ int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list) } //商人経験値 -/* if ((sd->status.class == 5) || (sd->status.class == 10) || (sd->status.class == 18)) { +/* if ((sd->status.class_ == 5) || (sd->status.class_ == 10) || (sd->status.class_ == 18)) { z = z * pc_checkskill(sd,MC_DISCOUNT) / ((1 + 300 / itemamount) * 4000) * battle_config.shop_exp; pc_gainexp(sd,0,z); }*/ @@ -1022,7 +1053,7 @@ int npc_buylist(struct map_session_data *sd,int n,unsigned short *item_list) if (sd->status.skill[MC_DISCOUNT].flag != 0) skill = sd->status.skill[MC_DISCOUNT].flag - 2; if (skill > 0) { - z = (log(z * (double)skill) * (double)battle_config.shop_exp/100.); + z = z * (double)skill * (double)battle_config.shop_exp/10000.; if (z < 1) z = 1; pc_gainexp(sd,0,(int)z); @@ -1074,7 +1105,7 @@ int npc_selllist(struct map_session_data *sd,int n,unsigned short *item_list) } //商人経験値 -/* if ((sd->status.class == 5) || (sd->status.class == 10) || (sd->status.class == 18)) { +/* if ((sd->status.class_ == 5) || (sd->status.class_ == 10) || (sd->status.class_ == 18)) { z = z * pc_checkskill(sd,MC_OVERCHARGE) / ((1 + 500 / itemamount) * 4000) * battle_config.shop_exp ; pc_gainexp(sd,0,z); }*/ @@ -1082,7 +1113,7 @@ int npc_selllist(struct map_session_data *sd,int n,unsigned short *item_list) if (sd->status.skill[MC_OVERCHARGE].flag != 0) skill = sd->status.skill[MC_OVERCHARGE].flag - 2; if (skill > 0) { - z = (log(z * (double)skill) * (double)battle_config.shop_exp/100.); + z = z * (double)skill * (double)battle_config.shop_exp/10000.; if (z < 1) z = 1; pc_gainexp(sd,0,(int)z); @@ -1106,8 +1137,8 @@ static int calc_next_walk_step(struct npc_data *nd) if(nd->walkpath.path_pos>=nd->walkpath.path_len) return -1; if(nd->walkpath.path[nd->walkpath.path_pos]&1) - return battle_get_speed(&nd->bl)*14/10; - return battle_get_speed(&nd->bl); + return status_get_speed(&nd->bl)*14/10; + return status_get_speed(&nd->bl); } @@ -1118,7 +1149,7 @@ static int calc_next_walk_step(struct npc_data *nd) static int npc_walk(struct npc_data *nd,unsigned int tick,int data) { int moveblock; - int i,ctype; + int i; static int dirx[8]={0,-1,-1,-1,0,1,1,1}; static int diry[8]={1,1,0,-1,-1,-1,0,1}; int x,y,dx,dy; @@ -1143,8 +1174,7 @@ static int npc_walk(struct npc_data *nd,unsigned int tick,int data) x = nd->bl.x; y = nd->bl.y; - ctype = map_getcell(nd->bl.m,x,y); - if(ctype == 1 || ctype == 5) { + if(map_getcell(nd->bl.m,x,y,CELL_CHKNOPASS)) { npc_stop_walking(nd,1); return 0; } @@ -1152,8 +1182,7 @@ static int npc_walk(struct npc_data *nd,unsigned int tick,int data) dx = dirx[nd->dir]; dy = diry[nd->dir]; - ctype = map_getcell(nd->bl.m,x+dx,y+dy); - if(ctype == 1 || ctype == 5) { + if(map_getcell(nd->bl.m,x+dx,y+dy,CELL_CHKNOPASS)) { npc_walktoxy_sub(nd); return 0; } @@ -1183,7 +1212,7 @@ static int npc_walk(struct npc_data *nd,unsigned int tick,int data) if(nd->walkpath.path_pos>=nd->walkpath.path_len) clif_fixnpcpos(nd); // When npc stops, retransmission current of a position. - + } return 0; } @@ -1228,7 +1257,7 @@ static int npc_walktimer(int tid,unsigned int tick,int id,int data) if(nd->walktimer != tid){ return 0; } - + nd->walktimer=-1; if(nd->bl.prev == NULL) @@ -1293,7 +1322,7 @@ int npc_stop_walking(struct npc_data *nd,int type) if(nd->state.state == MS_WALK || nd->state.state == MS_IDLE) { int dx=0,dy=0; - + nd->walkpath.path_len=0; if(type&4){ dx=nd->to_x-nd->bl.x; @@ -1318,7 +1347,7 @@ int npc_stop_walking(struct npc_data *nd,int type) if(type&0x01) clif_fixnpcpos(nd); if(type&0x02) { - int delay=battle_get_dmotion(&nd->bl); + int delay=status_get_dmotion(&nd->bl); unsigned int tick = gettick(); if(nd->canmove_tick < tick) nd->canmove_tick = tick + delay; @@ -1327,6 +1356,56 @@ int npc_stop_walking(struct npc_data *nd,int type) return 0; } +int npc_remove_map (struct npc_data *nd) +{ + nullpo_retr(1, nd); + + if(nd->bl.prev == NULL) + return 1; + +#ifdef PCRE_SUPPORT + npc_chat_finalize(nd); +#endif + clif_clearchar_area(&nd->bl,2); + strdb_erase(npcname_db, nd->name); + map_delblock(&nd->bl); + map_deliddb(&nd->bl); + + return 0; +} + +int npc_unload(struct npc_data *nd) +{ + nullpo_retr (0, nd); + + if (nd->chat_id) { + struct chat_data *cd = (struct chat_data*)map_id2bl(nd->chat_id); + if (cd) aFree (cd); + cd = NULL; + } + if (nd->bl.subtype == SCRIPT) { + if (nd->u.scr.timerid != -1) + delete_timer(nd->u.scr.timerid, npc_timerevent); + npc_cleareventtimer (nd); + if (nd->u.scr.timer_event) + aFree(nd->u.scr.timer_event); + if (nd->u.scr.src_id == 0) { + if(nd->u.scr.script) { + aFree(nd->u.scr.script); + nd->u.scr.script = NULL; + } + if (nd->u.scr.label_list) { + aFree(nd->u.scr.label_list); + nd->u.scr.label_list = NULL; + } + } + } + npc_remove_map (nd); + aFree(nd); + nd = NULL; + + return 0; +} // // 初期化関係 @@ -1343,7 +1422,7 @@ void npc_clearsrcfile() while( p ) { struct npc_src_list *p2=p; p=p->next; - free(p2); + aFree(p2); } npc_src_first=NULL; npc_src_last=NULL; @@ -1354,7 +1433,7 @@ void npc_clearsrcfile() */ void npc_addsrcfile(char *name) { - struct npc_src_list *new; + struct npc_src_list *new_; size_t len; if ( strcmpi(name,"clear")==0 ) { @@ -1362,16 +1441,27 @@ void npc_addsrcfile(char *name) return; } - len = sizeof(*new) + strlen(name); - new=(struct npc_src_list *)aCalloc(1,len); - new->next = NULL; - strncpy(new->name,name,strlen(name)+1); + { + // prevent multiple insert of source files + struct npc_src_list *p=npc_src_first; + while( p ) + { // found the file, no need to insert it again + if( 0==strcmp(name,p->name) ) + return; + p=p->next; + } + } + + len = sizeof(*new_) + strlen(name); + new_=(struct npc_src_list *)aCalloc(1,len); + new_->next = NULL; + strncpy(new_->name,name,strlen(name)+1); if (npc_src_first==NULL) - npc_src_first = new; + npc_src_first = new_; if (npc_src_last) - npc_src_last->next = new; + npc_src_last->next = new_; - npc_src_last=new; + npc_src_last=new_; } /*========================================== * 読み込むnpcファイルの削除 @@ -1391,7 +1481,7 @@ void npc_delsrcfile(char *name) *lp=p->next; if ( npc_src_last==p ) npc_src_last=pp; - free(p); + aFree(p); break; } } @@ -1432,9 +1522,9 @@ int npc_parse_warp(char *w1,char *w2,char *w3,char *w4) nd->chat_id=0; if (!battle_config.warp_point_debug) - nd->class=WARP_CLASS; + nd->class_=WARP_CLASS; else - nd->class=WARP_DEBUG_CLASS; + nd->class_=WARP_DEBUG_CLASS; nd->speed=200; nd->option = 0; nd->opt1 = 0; @@ -1449,11 +1539,9 @@ int npc_parse_warp(char *w1,char *w2,char *w3,char *w4) for(i=0;i<ys;i++) { for(j=0;j<xs;j++) { - int t; - t=map_getcell(m,x-xs/2+j,y-ys/2+i); - if (t==1 || t==5) + if(map_getcell(m,x-xs/2+j,y-ys/2+i,CELL_CHKNOPASS)) continue; - map_setcell(m,x-xs/2+j,y-ys/2+i,t|0x80); + map_setcell(m,x-xs/2+j,y-ys/2+i,CELL_SETNPC); } } @@ -1494,20 +1582,26 @@ static int npc_parse_shop(char *w1,char *w2,char *w3,char *w4) while (p && pos < max) { int nameid,value; + struct item_data *id; p++; if (sscanf(p, "%d:%d", &nameid, &value) != 2) break; nd->u.shop_item[pos].nameid = nameid; - if (value < 0) { - struct item_data *id = itemdb_search(nameid); + id = itemdb_search(nameid); + 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*75/100 < id->value_sell*124/100) { + sprintf (tmp_output, "Item %s [%d] buying:%d < selling:%d\n", + id->name, id->nameid, value*75/100, id->value_sell*124/100); + ShowWarning (tmp_output); + } pos++; p=strchr(p,','); } if (pos == 0) { - free(nd); + aFree(nd); return 1; } nd->u.shop_item[pos++].nameid = 0; @@ -1520,14 +1614,14 @@ static int npc_parse_shop(char *w1,char *w2,char *w3,char *w4) nd->dir = dir; nd->flag = 0; memcpy(nd->name, w3, 24); - nd->class = atoi(w4); + nd->class_ = atoi(w4); nd->speed = 200; nd->chat_id = 0; nd->option = 0; nd->opt1 = 0; nd->opt2 = 0; nd->opt3 = 0; - + nd = (struct npc_data *)aRealloc(nd, sizeof(struct npc_data) + sizeof(nd->u.shop_item[0]) * pos); @@ -1554,20 +1648,28 @@ int npc_convertlabel_db(void *key,void *data,va_list ap) struct npc_label_list *lst; int num; char *p=strchr(lname,':'); - + nullpo_retr(0, ap); nullpo_retr(0, nd=va_arg(ap,struct npc_data *)); lst=nd->u.scr.label_list; num=nd->u.scr.label_list_num; if(!lst){ - lst=(struct npc_label_list *)aCalloc(1,sizeof(struct npc_label_list)); + lst=(struct npc_label_list *)aCallocA(1,sizeof(struct npc_label_list)); num=0; }else lst=(struct npc_label_list *)aRealloc(lst,sizeof(struct npc_label_list)*(num+1)); *p='\0'; - strncpy(lst[num].name,lname,24); + + // here we check if the label fit into the buffer + if (strlen(lname)>23) { + printf("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, current_file); + exit(1); + } + memcpy(lst[num].name,lname,strlen(lname)+1); //including EOS + + *p=':'; lst[num].pos=pos; nd->u.scr.label_list=lst; @@ -1580,7 +1682,7 @@ int npc_convertlabel_db(void *key,void *data,va_list ap) */ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line,FILE *fp,int *lines) { - int x,y,dir=0,m,xs=0,ys=0,class=0; // [Valaris] thanks to fov + int x,y,dir=0,m,xs=0,ys=0,class_=0; // [Valaris] thanks to fov char mapname[24]; unsigned char *srcbuf=NULL,*script; int srcsize=65536; @@ -1609,94 +1711,92 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line if(strcmp(w2,"script")==0){ // スクリプトの解析 - srcbuf=(char *)aCalloc(srcsize,sizeof(char)); + srcbuf=(unsigned char *)aCallocA(srcsize,sizeof(char)); if (strchr(first_line,'{')) { - strcpy(srcbuf,strchr(first_line,'{')); + strcpy((char *) srcbuf,strchr(first_line,'{')); startline=*lines; } else srcbuf[0]=0; while(1) { - for(i=strlen(srcbuf)-1;i>=0 && isspace(srcbuf[i]);i--); + for(i=strlen((const char *) srcbuf)-1;i>=0 && isspace(srcbuf[i]);i--); if (i>=0 && srcbuf[i]=='}') break; - fgets(line,1020,fp); + fgets((char *) line,1020,fp); (*lines)++; if (feof(fp)) break; - if (strlen(srcbuf)+strlen(line)+1>=srcsize) { + if (strlen((char *) srcbuf)+strlen((char *) line)+1>=srcsize) { srcsize += 65536; - srcbuf = (char *)aRealloc(srcbuf, srcsize); + srcbuf = (unsigned char *)aRealloc(srcbuf, srcsize); memset(srcbuf + srcsize - 65536, '\0', 65536); } if (srcbuf[0]!='{') { - if (strchr(line,'{')) { - strcpy(srcbuf,strchr(line,'{')); + if (strchr((char *) line,'{')) { + strcpy((char *) srcbuf,strchr((const char *) line,'{')); startline=*lines; } } else - strcat(srcbuf,line); + strcat((char *) srcbuf,(const char *) line); } - script=parse_script(srcbuf,startline); + script=(unsigned char *) parse_script((unsigned char *) srcbuf,startline); if (script==NULL) { // script parse error? - free(srcbuf); + aFree(srcbuf); return 1; } }else{ // duplicateする - + char srcname[128]; struct npc_data *nd2; if( sscanf(w2,"duplicate(%[^)])",srcname)!=1 ){ - printf("bad duplicate name! : %s",w2); + printf("bad duplicate name (in %s)! : %s",current_file, w2); return 0; } if( (nd2=npc_name2id(srcname))==NULL ){ - printf("bad duplicate name! (not exist) : %s\n",srcname); + printf("bad duplicate name (in %s)! (not exist) : %s\n", current_file, srcname); return 0; } - script=nd2->u.scr.script; + script=(unsigned char *)nd2->u.scr.script; label_dup=nd2->u.scr.label_list; label_dupnum=nd2->u.scr.label_list_num; src_id=nd2->bl.id; - + }// end of スクリプト解析 nd=(struct npc_data *)aCalloc(1,sizeof(struct npc_data)); if(m==-1){ // スクリプトコピー用のダミーNPC - - }else if( sscanf(w4,"%d,%d,%d",&class,&xs,&ys)==3) { + + }else if( sscanf(w4,"%d,%d,%d",&class_,&xs,&ys)==3) { // 接触型NPC int i,j; - + if (xs>=0)xs=xs*2+1; if (ys>=0)ys=ys*2+1; - - if (class>=0) { + + if (class_>=0) { for(i=0;i<ys;i++) { for(j=0;j<xs;j++) { - int t; - t=map_getcell(m,x-xs/2+j,y-ys/2+i); - if (t==1 || t==5) + if(map_getcell(m,x-xs/2+j,y-ys/2+i,CELL_CHKNOPASS)) continue; - map_setcell(m,x-xs/2+j,y-ys/2+i,t|0x80); + map_setcell(m,x-xs/2+j,y-ys/2+i,CELL_SETNPC); } } } - + nd->u.scr.xs=xs; nd->u.scr.ys=ys; } else { // クリック型NPC - class=atoi(w4); + class_=atoi(w4); nd->u.scr.xs=0; nd->u.scr.ys=0; } - - if (class<0 && m>=0) { // イベント型NPC + + if (class_<0 && m>=0) { // イベント型NPC evflag=1; } @@ -1719,9 +1819,9 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line nd->bl.id=npc_get_new_npc_id(); nd->dir = dir; nd->flag=0; - nd->class=class; + nd->class_=class_; nd->speed=200; - nd->u.scr.script=script; + nd->u.scr.script=(char *) script; nd->u.scr.src_id=src_id; nd->chat_id=0; nd->option = 0; @@ -1730,7 +1830,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line nd->opt3 = 0; nd->walktimer=-1; - //printf("script npc %s %d %d read done\n",mapname,nd->bl.id,nd->class); + //printf("script npc %s %d %d read done\n",mapname,nd->bl.id,nd->class_); npc_script++; nd->bl.type=BL_NPC; nd->bl.subtype=SCRIPT; @@ -1738,6 +1838,11 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line nd->n=map_addnpc(m,nd); map_addblock(&nd->bl); + // clear event timers upon initialise + memset(nd->eventqueue, 0, sizeof(nd->eventqueue)); + for(i = 0; i < MAX_EVENTTIMER; i++) + nd->eventtimer[i] = -1; + if (evflag) { // イベント型 struct event_data *ev=(struct event_data *)aCalloc(1,sizeof(struct event_data)); ev->nd=nd; @@ -1750,21 +1855,21 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line //----------------------------------------- - // ラベルデータの準備 + // ラベルデータの準備 if(srcbuf){ // script本体がある場合の処理 - + // ラベルデータのコンバート label_db=script_get_label_db(); strdb_foreach(label_db,npc_convertlabel_db,nd); - + // もう使わないのでバッファ解放 - free(srcbuf); + aFree(srcbuf); }else{ // duplicate -// nd->u.scr.label_list=malloc(sizeof(struct npc_label_list)*label_dupnum); +// nd->u.scr.label_list=aMallocA(sizeof(struct npc_label_list)*label_dupnum); // memcpy(nd->u.scr.label_list,label_dup,sizeof(struct npc_label_list)*label_dupnum); nd->u.scr.label_list=label_dup; // ラベルデータ共有 @@ -1776,25 +1881,76 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line for(i=0;i<nd->u.scr.label_list_num;i++){ char *lname=nd->u.scr.label_list[i].name; int pos=nd->u.scr.label_list[i].pos; - + if ((lname[0]=='O' || lname[0]=='o')&&(lname[1]=='N' || lname[1]=='n')) { +/* +I rearrange the code so this is just for commenting; remove it if you have enough if it [Shinomori] struct event_data *ev; char *buf; // エクスポートされる ev=(struct event_data *)aCalloc(1,sizeof(struct event_data)); - buf=(char *)aCalloc(50,sizeof(char)); +why allocing 50 chars ? + buf=(char *)aCallocA(50,sizeof(char)); +why checking here? +lname is identical to nd->u.scr.label_list[i].name which is only 24 chars so check for strlen should be 23 if (strlen(lname)>24) { - printf("npc_parse_script: label name error !\n"); + printf("npc_parse_script: label name error (%s) !\n", current_file); exit(1); }else{ + //struct event_data *ev2; ev->nd=nd; ev->pos=pos; sprintf(buf,"%s::%s",nd->exname,lname); + //ev2 = strdb_search(ev_db,buf); + //if(ev2 != NULL) { + // printf("npc_parse_script : duplicate event %s\n",buf); + // aFree(ev2); + //} +you are sure reentering the same database key will overwrite the existing entry? strdb_insert(ev_db,buf,ev); +anyway instead of removing data from the db and inserting a new one +wouldn't it be easier just not to insert the new duplicate event, it is a duplicate anyway? + } +*/ + // this check is useless here because the buffer is only 24 chars + // and already overwritten if this is here is reached + // I leave the check anyway but place it correctly to npc_convertlabel_db + if (strlen(lname)>23) { + printf("npc_parse_script: label name longer than 23 chars! '%s' (%s)\n", lname, current_file); + exit(1); + }else{ + struct event_data *ev; + struct event_data *ev2; + char *buf; + // エクスポートされる + + // 51 comes from: 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS + //buf=(char *)aMalloc(51,sizeof(char)); + // but to save some memory we alloc only the really necessary space + buf=(char *)aMalloc( (3+strlen(nd->exname)+strlen(lname))*sizeof(char)); + sprintf(buf,"%s::%s",nd->exname,lname); + + // search the label in ev_db; + // remember the label is max 50 chars + eos; see the strdb_init below + ev2 = (struct event_data *)strdb_search(ev_db,buf); + if(ev2 != NULL) { + printf("npc_parse_script : duplicate event %s (%s)\n",buf, current_file); + + // just skip the label insertion and free the alloced buffer + aFree(buf); + } + else + { // generate the data and insert it + ev=(struct event_data *)aCalloc(1,sizeof(struct event_data)); + ev->nd=nd; + ev->pos=pos; + strdb_insert(ev_db,buf,ev); + } + } } } - + //----------------------------------------- // ラベルデータからタイマーイベント取り込み for(i=0;i<nd->u.scr.label_list_num;i++){ @@ -1806,7 +1962,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line struct npc_timerevent_list *te=nd->u.scr.timer_event; int j,k=nd->u.scr.timeramount; if(te==NULL) - te=(struct npc_timerevent_list *)aCalloc(1,sizeof(struct npc_timerevent_list)); + te=(struct npc_timerevent_list *)aCallocA(1,sizeof(struct npc_timerevent_list)); else te=(struct npc_timerevent_list *)aRealloc( te, sizeof(struct npc_timerevent_list) * (k+1) ); for(j=0;j<k;j++){ @@ -1824,7 +1980,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line nd->u.scr.nexttimer=-1; nd->u.scr.timerid=-1; - + return 0; } @@ -1843,7 +1999,7 @@ static int npc_parse_function(char *w1,char *w2,char *w3,char *w4,char *first_li char *p; // スクリプトの解析 - srcbuf=(char *)aCalloc(srcsize,sizeof(char)); + srcbuf=(char *)aCallocA(srcsize,sizeof(char)); if (strchr(first_line,'{')) { strcpy(srcbuf,strchr(first_line,'{')); startline=*lines; @@ -1870,14 +2026,14 @@ static int npc_parse_function(char *w1,char *w2,char *w3,char *w4,char *first_li } else strcat(srcbuf,line); } - script=parse_script(srcbuf,startline); + script= parse_script((unsigned char *) srcbuf,startline); if (script==NULL) { // script parse error? - free(srcbuf); + aFree(srcbuf); return 1; } - p=(char *)aCalloc(50,sizeof(char)); + p=(char *)aCallocA(50,sizeof(char)); strncpy(p,w3,50); strdb_insert(script_get_userfunc_db(),p,script); @@ -1885,10 +2041,10 @@ static int npc_parse_function(char *w1,char *w2,char *w3,char *w4,char *first_li // label_db=script_get_label_db(); // もう使わないのでバッファ解放 - free(srcbuf); - + aFree(srcbuf); + // printf("function %s => %p\n",p,script); - + return 0; } @@ -1899,7 +2055,7 @@ static int npc_parse_function(char *w1,char *w2,char *w3,char *w4,char *first_li */ int npc_parse_mob(char *w1,char *w2,char *w3,char *w4) { - int m,x,y,xs,ys,class,num,delay1,delay2,level; + int m,x,y,xs,ys,class_,num,delay1,delay2,level; int i; char mapname[24]; char mobname[24]; @@ -1910,7 +2066,7 @@ int npc_parse_mob(char *w1,char *w2,char *w3,char *w4) delay1=delay2=0; // 引数の個数チェック if (sscanf(w1,"%[^,],%d,%d,%d,%d",mapname,&x,&y,&xs,&ys) < 3 || - sscanf(w4,"%d,%d,%d,%d,%s",&class,&num,&delay1,&delay2,eventname) < 2 ) { + sscanf(w4,"%d,%d,%d,%d,%s",&class_,&num,&delay1,&delay2,eventname) < 2 ) { printf("bad monster line : %s\n",w3); return 1; } @@ -1925,13 +2081,13 @@ int npc_parse_mob(char *w1,char *w2,char *w3,char *w4) for(i=0;i<num;i++) { md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data)); - if(class>4000) { // large/tiny mobs [Valaris] + if(class_>4000) { // large/tiny mobs [Valaris] md->size=2; - class-=4000; + class_-=4000; } - else if(class>2000) { + else if(class_>2000) { md->size=1; - class-=2000; + class_-=2000; } md->bl.prev=NULL; @@ -1940,19 +2096,16 @@ int npc_parse_mob(char *w1,char *w2,char *w3,char *w4) md->bl.x=x; md->bl.y=y; - if(sscanf(w3,"%[^,],%d",mobname,&level) > 1) { - if(strcmp(mobname,"--en--")==0) - memcpy(md->name,mob_db[class].name,24); - else if(strcmp(mobname,"--ja--")==0) - memcpy(md->name,mob_db[class].jname,24); + if(sscanf(w3,"%[^,],%d",mobname,&level) > 1) md->level=level; - } - - else - memcpy(md->name,w3,24); + if(strcmp(mobname,"--en--")==0) + memcpy(md->name,mob_db[class_].name,24); + else if(strcmp(mobname,"--ja--")==0) + memcpy(md->name,mob_db[class_].jname,24); + else memcpy(md->name,mobname,24); md->n = i; - md->base_class = md->class = class; + md->base_class = md->class_ = class_; md->bl.id=npc_get_new_npc_id(); md->m =m; md->x0=x; @@ -1966,9 +2119,9 @@ int npc_parse_mob(char *w1,char *w2,char *w3,char *w4) md->timer = -1; md->target_id=0; md->attacked_id=0; - md->speed=mob_db[class].speed; + md->speed=mob_db[class_].speed; - if (mob_db[class].mode&0x02) + if (mob_db[class_].mode&0x02) md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item)); else md->lootitem=NULL; @@ -2013,7 +2166,7 @@ static int npc_parse_mapflag(char *w1,char *w2,char *w3,char *w4) //マップフラグ if ( strcmpi(w3,"nosave")==0) { if (strcmp(w4,"SavePoint")==0) { - memcpy(map[m].save.map,"SavePoint",16); + memcpy(map[m].save.map,"SavePoint",10); map[m].save.x=-1; map[m].save.y=-1; }else if (sscanf(w4,"%[^,],%d,%d",savemap,&savex,&savey)==3) { @@ -2106,19 +2259,19 @@ static int npc_parse_mapflag(char *w1,char *w2,char *w3,char *w4) } else if (strcmpi(w3,"noicewall")==0) { // noicewall [Valaris] map[m].flag.noicewall=1; - } + } else if (strcmpi(w3,"snow")==0) { // snow [Valaris] map[m].flag.snow=1; - } + } else if (strcmpi(w3,"fog")==0) { // fog [Valaris] map[m].flag.fog=1; - } + } else if (strcmpi(w3,"sakura")==0) { // sakura [Valaris] map[m].flag.sakura=1; - } + } else if (strcmpi(w3,"leaves")==0) { // leaves [Valaris] map[m].flag.leaves=1; - } + } else if (strcmpi(w3,"rain")==0) { // rain [Valaris] map[m].flag.rain=1; } @@ -2128,15 +2281,116 @@ static int npc_parse_mapflag(char *w1,char *w2,char *w3,char *w4) else if (strcmpi(w3,"nogo")==0) { // celest map[m].flag.nogo=1; } - + + return 0; +} + +void npc_parsesrcfile(char *name) +{ + int m, lines = 0; + char line[1024]; + + FILE *fp = fopen (name,"r"); + if (fp == NULL) { + ShowError ("File not found : %s\n", name); + exit(1); + } + current_file = name; + + while (fgets(line, 1020, fp)) { + char w1[1024], w2[1024], w3[1024], w4[1024], mapname[1024]; + int i, j, w4pos, count; + lines++; + + if (line[0] == '/' && line[1] == '/') + continue; + // 不要なスペースやタブの連続は詰める + for (i = j = 0; line[i]; i++) { + if (line[i]==' ') { + if (!((line[i+1] && (isspace(line[i+1]) || line[i+1]==',')) || + (j && line[j-1]==','))) + line[j++]=' '; + } else if (line[i]=='\t') { + if (!(j && line[j-1]=='\t')) + line[j++]='\t'; + } else + line[j++]=line[i]; + } + // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認 + if ((count = sscanf(line,"%[^\t]\t%[^\t]\t%[^\t\r\n]\t%n%[^\t\r\n]", w1, w2, w3, &w4pos, w4)) < 3 && + (count = sscanf(line,"%s%s%s%n%s", w1, w2, w3, &w4pos, w4)) < 3) { + continue; + } + // マップの存在確認 + if (strcmp(w1,"-") !=0 && strcmpi(w1,"function") != 0 ){ + sscanf(w1,"%[^,]",mapname); + m = map_mapname2mapid(mapname); + if (strlen(mapname)>16 || m<0) { + // "mapname" is not assigned to this server + 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); + } else { + npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines); + } + } 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); + } 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); + } + } + fclose(fp); + + return; +} + +static int npc_read_indoors(void) +{ + char *buf,*p; + int s, m; + + buf=(char *) grfio_reads("data\\indoorrswtable.txt",&s); + + if(buf==NULL) + return -1; + + buf[s]=0; + for(p=buf;p-buf<s;){ + char buf2[64]; + + if(sscanf(p,"%[^#]#",buf2) == 1){ + char map_name[64] = ""; + strncpy(map_name, buf2, strlen(buf2) - 4); + strcat(map_name, ".gat"); + if ((m = map_mapname2mapid(map_name)) >= 0) + map[m].flag.indoors=1; + } + + p=strchr(p,10); + if(!p) break; + p++; + } + aFree(buf); + sprintf(tmp_output,"Done reading '"CL_WHITE"%s"CL_RESET"'.\n","data\\indoorrswtable.txt"); + ShowStatus(tmp_output); + return 0; } static int ev_db_final(void *key,void *data,va_list ap) { - free(data); - if(strstr(key,"::")!=NULL) - free(key); + aFree(data); + if(strstr((const char *) key,"::")!=NULL) + aFree(key); return 0; } static int npcname_db_final(void *key,void *data,va_list ap) @@ -2144,6 +2398,75 @@ static int npcname_db_final(void *key,void *data,va_list ap) return 0; } /*========================================== + * + *------------------------------------------ + */ +int npc_cleanup_sub (struct block_list *bl, va_list ap) { + nullpo_retr(0, bl); + + switch(bl->type) { + case BL_NPC: + npc_unload((struct npc_data *)bl); + break; + case BL_MOB: + mob_unload((struct mob_data *)bl); + break; + } + + return 0; +} +int npc_reload(void) +{ + struct npc_src_list *nsl; + int m, last_npc_id; + time_t last_time = time(0); + int busy = 0; + char c = '-'; + + for (m = 0; m < map_num; m++) { + map_foreachinarea(npc_cleanup_sub, m, 0, 0, map[m].xs, map[m].ys, 0); + map[m].npc_num = 0; + } + if(ev_db) + strdb_final(ev_db,ev_db_final); + if(npcname_db) + strdb_final(npcname_db,npcname_db_final); + + // anything else we should cleanup? + // Reloading npc's now + ev_db = strdb_init(51); + npcname_db = strdb_init(24); + ev_db->release = ev_release; + npc_warp = npc_shop = npc_script = npc_mob = 0; + last_npc_id = npc_id; + + for (nsl = npc_src_first; nsl; nsl = nsl->next) { + npc_parsesrcfile(nsl->name); + printf("\r"); + ShowStatus("Loading NPCs... Working: "); + if (last_time != time(0)) { + last_time = time(0); + switch(busy) { + case 0: c='\\'; busy++; break; + case 1: c='|'; busy++; break; + case 2: c='/'; busy++; break; + case 3: c='-'; busy=0; + } + } + printf("[%c]",c); + fflush(stdout); + } + printf("\r"); + ShowInfo ("Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:%30s\n\t-'" + CL_WHITE"%d"CL_RESET"' Warps\n\t-'" + CL_WHITE"%d"CL_RESET"' Shops\n\t-'" + CL_WHITE"%d"CL_RESET"' Scripts\n\t-'" + CL_WHITE"%d"CL_RESET"' Mobs\n", + npc_id - last_npc_id, "", npc_warp, npc_shop, npc_script, npc_mob); + + return 0; +} +/*========================================== * 終了 *------------------------------------------ */ @@ -2153,7 +2476,6 @@ int do_final_npc(void) struct block_list *bl; struct npc_data *nd; struct mob_data *md; - struct chat_data *cd; struct pet_data *pd; if(ev_db) @@ -2161,53 +2483,27 @@ int do_final_npc(void) if(npcname_db) strdb_final(npcname_db,npcname_db_final); - for(i=START_NPC_NUM;i<npc_id;i++){ - if((bl=map_id2bl(i))){ + npc_clearsrcfile(); + + for (i = START_NPC_NUM; i < npc_id; i++){ + if((bl = map_id2bl(i))){ if(bl->type == BL_NPC && (nd = (struct npc_data *)bl)){ - if(nd->chat_id && (cd=(struct chat_data*)map_id2bl(nd->chat_id))){ - free(cd); - cd = NULL; - } - if(nd->bl.subtype == SCRIPT){ - if(nd->u.scr.timer_event) - free(nd->u.scr.timer_event); - if(nd->u.scr.src_id==0){ - if(nd->u.scr.script){ - free(nd->u.scr.script); - nd->u.scr.script=NULL; - } - if(nd->u.scr.label_list){ - free(nd->u.scr.label_list); - nd->u.scr.label_list = NULL; - } - } - } - free(nd); - nd = NULL; - }else if(bl->type == BL_MOB && (md = (struct mob_data *)bl)){ - if(md->lootitem){ - free(md->lootitem); + npc_unload(nd); + }else if (bl->type == BL_MOB && (md = (struct mob_data *)bl)){ + if (md->lootitem){ + aFree(md->lootitem); md->lootitem = NULL; } - free(md); + aFree(md); md = NULL; }else if(bl->type == BL_PET && (pd = (struct pet_data *)bl)){ - free(pd); + aFree(pd); pd = NULL; } } } - - return 0; -} - -void ev_release(struct dbn *db, int which) -{ - if (which & 0x1) - free(db->key); - if (which & 0x2) - free(db->data); + return 0; } /*========================================== @@ -2217,86 +2513,56 @@ void ev_release(struct dbn *db, int which) int do_init_npc(void) { struct npc_src_list *nsl; - FILE *fp; - char line[1024]; - int m,lines; - - ev_db=strdb_init(24); - npcname_db=strdb_init(24); - - ev_db->release = ev_release; - - memset(&ev_tm_b,-1,sizeof(ev_tm_b)); - - for(nsl=npc_src_first;nsl;nsl=nsl->next) { - if(nsl->prev){ - free(nsl->prev); + time_t last_time = time(0); + int busy = 0; + char c = '-'; + + // indoorrswtable.txt and etcinfo.txt [Celest] + if (battle_config.indoors_override_grffile) + npc_read_indoors(); + //npc_read_weather(); + + // comparing only the first 24 chars of labels that are 50 chars long isn't that nice + // will cause "duplicated" labels where actually no dup is... + //ev_db=strdb_init(24); + ev_db = strdb_init(51); + npcname_db = strdb_init(24); + ev_db->release = ev_release; + + memset(&ev_tm_b, -1, sizeof(ev_tm_b)); + + for (nsl = npc_src_first; nsl; nsl = nsl->next) { + /*if(nsl->prev){ // [Shinomori] + aFree(nsl->prev); nsl->prev = NULL; - } - fp=fopen(nsl->name,"r"); - if (fp==NULL) { - printf("file not found : %s\n",nsl->name); - exit(1); - } - lines=0; - while(fgets(line,1020,fp)) { - char w1[1024],w2[1024],w3[1024],w4[1024],mapname[1024]; - int i,j,w4pos,count; - lines++; - - if (line[0] == '/' && line[1] == '/') - continue; - // 不要なスペースやタブの連続は詰める - for(i=j=0;line[i];i++) { - if (line[i]==' ') { - if (!((line[i+1] && (isspace(line[i+1]) || line[i+1]==',')) || - (j && line[j-1]==','))) - line[j++]=' '; - } else if (line[i]=='\t') { - if (!(j && line[j-1]=='\t')) - line[j++]='\t'; - } else - line[j++]=line[i]; - } - // 最初はタブ区切りでチェックしてみて、ダメならスペース区切りで確認 - if ((count=sscanf(line,"%[^\t]\t%[^\t]\t%[^\t\r\n]\t%n%[^\t\r\n]",w1,w2,w3,&w4pos,w4)) < 3 && - (count=sscanf(line,"%s%s%s%n%s",w1,w2,w3,&w4pos,w4)) < 3) { - continue; - } - // マップの存在確認 - if( strcmp(w1,"-")!=0 && strcmpi(w1,"function")!=0 ){ - sscanf(w1,"%[^,]",mapname); - m = map_mapname2mapid(mapname); - if (strlen(mapname)>16 || m<0) { - // "mapname" is not assigned to this server - 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); - }else{ - npc_parse_script(w1,w2,w3,w4,line+w4pos,fp,&lines); - } - } 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); - } 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); + }*/ + // + npc_parsesrcfile(nsl->name); + current_file = NULL; + printf("\r"); + ShowStatus("Loading NPCs... Working: "); + if (last_time != time(0)) { + last_time = time(0); + switch(busy) { + case 0: c='\\'; busy++; break; + case 1: c='|'; busy++; break; + case 2: c='/'; busy++; break; + case 3: c='-'; busy=0; } } - fclose(fp); + printf("[%c]",c); + fflush(stdout); // printf("\rLoading NPCs [%d]: %-54s",npc_id-START_NPC_NUM,nsl->name); // fflush(stdout); } - printf("\rNPCs Loaded: %d [Warps:%d Shops:%d Scripts:%d Mobs:%d]\n", - npc_id-START_NPC_NUM,npc_warp,npc_shop,npc_script,npc_mob); - + printf("\r"); + ShowInfo ("Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:%30s\n\t-'" + CL_WHITE"%d"CL_RESET"' Warps\n\t-'" + CL_WHITE"%d"CL_RESET"' Shops\n\t-'" + CL_WHITE"%d"CL_RESET"' Scripts\n\t-'" + CL_WHITE"%d"CL_RESET"' Mobs\n", + npc_id - START_NPC_NUM, "", npc_warp, npc_shop, npc_script, npc_mob); + add_timer_func_list(npc_walktimer,"npc_walktimer"); // [Valaris] add_timer_func_list(npc_event_timer,"npc_event_timer"); add_timer_func_list(npc_event_do_clock,"npc_event_do_clock"); |