summaryrefslogtreecommitdiff
path: root/src/map/npc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/npc.c')
-rw-r--r--src/map/npc.c1028
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");