Jelajahi Sumber

* Readded @disablenpc
* Fixed @reloadscript not removing old NPC's and monsters first
* Some changes in mob and NPC unloading
* Changed the original @disablenpc to @hidenpc

git-svn-id: https://svn.code.sf.net/p/rathena/svn/branches/stable@1429 54d463be-8e91-2dee-dedb-b68131a5f0ec

celest 20 tahun lalu
induk
melakukan
171609d4a2
12 mengubah file dengan 290 tambahan dan 172 penghapusan
  1. 9 0
      Changelog-SVN.txt
  2. 3 0
      conf-tmpl/atcommand_athena.conf
  3. 1 1
      npc/jobs/custom/jobchange.txt
  4. 30 3
      src/map/atcommand.c
  5. 1 0
      src/map/atcommand.h
  6. 19 11
      src/map/clif.c
  7. 2 2
      src/map/map.c
  8. 24 16
      src/map/mob.c
  9. 3 1
      src/map/mob.h
  10. 193 136
      src/map/npc.c
  11. 3 1
      src/map/npc.h
  12. 2 1
      src/map/pet.c

+ 9 - 0
Changelog-SVN.txt

@@ -1,6 +1,15 @@
 
 Date	Added
 
+04/07
+	* Readded @disablenpc (not the same as @hidenpc) [celest]
+	* Fixed @reloadscript not removing old NPC's and monsters first [celest]
+	* Some changes in mob and NPC unloading [celest]
+	* Changed the original @disablenpc to @hidenpc [celest]
+	* Fixed HP Conversion to properly not reduce HP if SP is full [celest]
+	* Updated Defender -- should reduce walking speed, and does not reduce attack speed
+	  at level 5 [celest]
+
 04/06
 	* Fixed a crash in clif_send when checking packet version, thanks to Alex14
 	* Fixed a crash in Deluge, Volcano and Violent Gale, thanks to Alex14

+ 3 - 0
conf-tmpl/atcommand_athena.conf

@@ -567,6 +567,9 @@ enablenpc: 80
 // Disables a NPC.
 disablenpc: 80
 
+// Hides a NPC.
+hidenpc: 80
+
 // Move a NPC
 npcmove: 80
 

+ 1 - 1
npc/jobs/custom/jobchange.txt

@@ -61,7 +61,7 @@ Llevelcheck:
 Ladvclasses:
 	if(SkillPoint != 0) goto Lskillpt;
 //Lord Knight & Paladin
-	if(oldclass == 7 && readparam(19) == 4001 || oldclass == 14 && readparam(19) == 4001) goto Lswordsmanhigh;
+	if(oldclass == 7 && readparam(19) == 4001 || oldclass == 13 && readparam(19) == 4001 || oldclass == 14 && readparam(19) == 4001 || oldclass == 21 && readparam(19) == 4001) goto Lswordsmanhigh;
 	if(readparam(19) == 4002 && oldclass == 7) goto Llordknight;
 	if(readparam(19) == 4002 && oldclass == 14) goto Lpaladin;
 //Assassin Cross & Stalker

+ 30 - 3
src/map/atcommand.c

@@ -167,6 +167,7 @@ ACMD_FUNC(guildrecall); // by Yor
 ACMD_FUNC(partyrecall); // by Yor
 ACMD_FUNC(nuke); // [Valaris]
 ACMD_FUNC(enablenpc);
+ACMD_FUNC(hidenpc);
 ACMD_FUNC(disablenpc);
 ACMD_FUNC(servertime); // by Yor
 ACMD_FUNC(chardelitem); // by Yor
@@ -433,6 +434,7 @@ static AtCommandInfo atcommand_info[] = {
 	{ AtCommand_PartyRecall,		"@partyrecall",		60, atcommand_partyrecall }, // by Yor
 	{ AtCommand_Nuke,				"@nuke",			60, atcommand_nuke }, // [Valaris]
 	{ AtCommand_Enablenpc,			"@enablenpc",		80, atcommand_enablenpc }, // []
+	{ AtCommand_Hidenpc,			"@hidenpc",			80, atcommand_hidenpc }, // []
 	{ AtCommand_Disablenpc,			"@disablenpc",		80, atcommand_disablenpc }, // []
 	{ AtCommand_ServerTime,			"@time",			 0, atcommand_servertime }, // by Yor
 	{ AtCommand_ServerTime,			"@date",			 0, atcommand_servertime }, // by Yor
@@ -5735,9 +5737,9 @@ int atcommand_reloadscript(
 	rehash();
 
 	atcommand_broadcast( fd, sd, "@broadcast", "Reloading NPCs..." );
-	do_init_npc();
+	//do_init_npc();
 	do_init_script();
-
+	npc_reload();
 	npc_event_do_oninit();
 
 	clif_displaymessage(fd, msg_table[100]); // Scripts reloaded.
@@ -6183,7 +6185,7 @@ int atcommand_enablenpc(const int fd, struct map_session_data* sd,
  *
  *------------------------------------------
  */
-int atcommand_disablenpc(const int fd, struct map_session_data* sd,
+int atcommand_hidenpc(const int fd, struct map_session_data* sd,
 	const char* command, const char* message)
 {
 	char NPCname[100];
@@ -6207,6 +6209,31 @@ int atcommand_disablenpc(const int fd, struct map_session_data* sd,
 	return 0;
 }
 
+int atcommand_disablenpc(const int fd, struct map_session_data* sd,
+	const char* command, const char* message)
+{
+	struct npc_data *nd;
+	char NPCname[100];
+	nullpo_retr(-1, sd);
+
+	memset(NPCname, '\0', sizeof(NPCname));
+
+	if (!message || !*message || sscanf(message, "%99[^\n]", NPCname) < 1) {
+		clif_displaymessage(fd, "Please, enter a NPC name (usage: @npcoff <NPC_name>).");
+		return -1;
+	}
+
+	if ((nd = npc_name2id(NPCname)) != NULL) {
+		npc_unload(nd);
+		clif_displaymessage(fd, msg_table[112]); // Npc Disabled.
+	} else {
+		clif_displaymessage(fd, msg_table[111]); // This NPC doesn't exist.
+		return -1;
+	}
+
+	return 0;
+}
+
 /*==========================================
  * time in txt for time command (by [Yor])
  *------------------------------------------

+ 1 - 0
src/map/atcommand.h

@@ -145,6 +145,7 @@ enum AtCommandType {
 	AtCommand_PartyRecall, // by Yor
 	AtCommand_Nuke,	// [Valaris]
 	AtCommand_Enablenpc,
+	AtCommand_Hidenpc,
 	AtCommand_Disablenpc,
 	AtCommand_ServerTime, // by Yor
 	AtCommand_CharDelItem, // by Yor

+ 19 - 11
src/map/clif.c

@@ -242,12 +242,11 @@ int clif_foreachclient(int (*func)(struct map_session_data*, va_list),...)
  */
 int clif_send_sub(struct block_list *bl, va_list ap)
 {
-	unsigned char *buf;
-	int len;
 	struct block_list *src_bl;
-	int type;
 	struct map_session_data *sd;
-
+	unsigned char *buf;
+	int len, type;
+	
 	nullpo_retr(0, bl);
 	nullpo_retr(0, ap);
 	nullpo_retr(0, sd = (struct map_session_data *)bl);
@@ -259,20 +258,23 @@ int clif_send_sub(struct block_list *bl, va_list ap)
 
 	switch(type) {
 	case AREA_WOS:
-		if (bl && bl == src_bl)
+		if (bl == src_bl)
 			return 0;
 		break;
 	case AREA_WOC:
-		if ((sd && sd->chatID) || (bl && bl == src_bl))
+		if (sd->chatID || bl == src_bl)
 			return 0;
 		break;
 	case AREA_WOSC:
-		if ((sd) && sd->chatID && sd->chatID == ((struct map_session_data*)src_bl)->chatID)
-			return 0;
+		{
+			struct map_session_data *ssd = (struct map_session_data *)src_bl;
+			if (ssd && sd->chatID && sd->chatID == ssd->chatID)
+				return 0;
+		}
 		break;
 	}
 
-	if ((sd != NULL) && (session[sd->fd] != NULL)) {
+	if (session[sd->fd] != NULL) {
 		if (WFIFOP(sd->fd,0) == buf) {
 			printf("WARNING: Invalid use of clif_send function\n");
 			printf("         Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0));
@@ -10686,10 +10688,16 @@ static int clif_parse(int fd) {
 
 	// get packet version before to parse
 	packet_ver = 0;
-	if (sd)
+	if (sd) {
 		packet_ver = sd->packet_ver;
+		if (packet_ver < 0 || packet_ver > MAX_PACKET_VER) {	// unusual, but just in case
+			close(fd);
+			session[fd]->eof = 1;
+			printf("clif_parse: session #%d, bad packet version -> disconnected.\n", fd);
+			return 0;
+		}
 	// check authentification packet to know packet version
-	else {
+	} else {
 		// packet DB
 		if (IS_PACKET_DB_VER (cmd)) {
 			if (RFIFOREST(fd) >= packet_db[clif_config.packet_db_ver][cmd].len &&

+ 2 - 2
src/map/map.c

@@ -3131,10 +3131,10 @@ int cleanup_sub(struct block_list *bl, va_list ap) {
             map_quit((struct map_session_data *) bl);
             break;
         case BL_NPC:
-            npc_delete((struct npc_data *)bl);
+            npc_unload((struct npc_data *)bl);
             break;
         case BL_MOB:
-            mob_delete((struct mob_data *)bl);
+            mob_unload((struct mob_data *)bl);
             break;
         case BL_PET:
             pet_remove_map((struct map_session_data *)bl);

+ 24 - 16
src/map/mob.c

@@ -914,7 +914,8 @@ int mob_spawn(int id)
 	struct mob_data *md;
 	struct block_list *bl;
 
-	nullpo_retr(-1, bl=map_id2bl(id));
+	//nullpo_retr(-1, bl=map_id2bl(id));
+	bl=map_id2bl(id);
 
 	if(!bl || !bl->type || bl->type!=BL_MOB)
 		return -1;
@@ -2106,42 +2107,49 @@ static int mob_delay_item_drop2(int tid,unsigned int tick,int id,int data)
  * mob data is erased.
  *------------------------------------------
  */
-int mob_delete(struct mob_data *md)
+void mob_unload(struct mob_data *md)
+{
+	nullpo_retv(md);
+	mob_remove_map(md, 0);
+	map_deliddb(&md->bl);
+	aFree(md);
+	md = NULL;
+}
+int mob_remove_map(struct mob_data *md, int type)
 {
 	nullpo_retr(1, md);
 
 	if(md->bl.prev == NULL)
 		return 1;
 	mob_changestate(md,MS_DEAD,0);
-	clif_clearchar_area(&md->bl,1);
+	clif_clearchar_area(&md->bl,type);
 	map_delblock(&md->bl);
-	if(mob_get_viewclass(md->class_) <= 1000)
-		clif_clearchar_delay(gettick()+3000,&md->bl,0);
-	mob_deleteslave(md);
-	mob_setdelayspawn(md->bl.id);
+	if (md->lootitem){
+		aFree(md->lootitem);
+		md->lootitem = NULL;
+	}
+
 	return 0;
 }
-
-int mob_catch_delete(struct mob_data *md,int type)
+int mob_delete(struct mob_data *md)
 {
 	nullpo_retr(1, md);
 
-	if(md->bl.prev == NULL)
-		return 1;
-	mob_changestate(md,MS_DEAD,0);
-	clif_clearchar_area(&md->bl,type);
-	map_delblock(&md->bl);
+	mob_remove_map(md, 1);
+	if (mob_get_viewclass(md->class_) <= 1000)
+		clif_clearchar_delay(gettick()+3000,&md->bl,0);
+	mob_deleteslave(md);
 	mob_setdelayspawn(md->bl.id);
 	return 0;
 }
-
 int mob_timer_delete(int tid, unsigned int tick, int id, int data)
 {
 	struct mob_data *md=(struct mob_data *)map_id2bl(id);
 	nullpo_retr(0, md);
 
 //for Alchemist CANNIBALIZE [Lupus]
-	mob_catch_delete(md,3);
+	mob_remove_map(md, 3);
+	mob_setdelayspawn(md->bl.id);
 	return 0;
 }
 

+ 3 - 1
src/map/mob.h

@@ -105,6 +105,7 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist);
 int mob_stop_walking(struct mob_data *md,int type);
 int mob_stopattack(struct mob_data *);
 int mob_spawn(int);
+int mob_setdelayspawn(int);
 int mob_damage(struct block_list *,struct mob_data*,int,int);
 int mob_changestate(struct mob_data *md,int state,int type);
 int mob_heal(struct mob_data*,int);
@@ -123,8 +124,9 @@ short mob_get_clothes_color(int);	//player mob dye [Valaris]
 int mob_get_equip(int); // mob equip [Valaris]
 int do_init_mob(void);
 
+void mob_unload(struct mob_data *md);
+int mob_remove_map(struct mob_data *md, int type);
 int mob_delete(struct mob_data *md);
-int mob_catch_delete(struct mob_data *md,int type);
 int mob_timer_delete(int tid, unsigned int tick, int id, int data);
 
 int mob_deleteslave(struct mob_data *md);

+ 193 - 136
src/map/npc.c

@@ -128,6 +128,15 @@ struct npc_data* npc_name2id(const char *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);
+}
+
 /*==========================================
  * イベントキューのイベント処理
  *------------------------------------------
@@ -164,25 +173,6 @@ int npc_event_dequeue(struct map_session_data *sd)
 	return 0;
 }
 
-
-
-
-int npc_delete(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,1);
-    map_delblock(&nd->bl);
-    return 0;
-}
-
 /*==========================================
  * イベントの遅延実行
  *------------------------------------------
@@ -1366,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;
+}
 
 //
 // 初期化関係
@@ -1798,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;
@@ -2240,6 +2285,74 @@ static int npc_parse_mapflag(char *w1,char *w2,char *w3,char *w4)
 	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;
@@ -2272,37 +2385,7 @@ static int npc_read_indoors(void)
 
 	return 0;
 }
-static int npc_unload(struct npc_data *nd)
-{
-	struct chat_data *cd;
-
-	nullpo_retr (0, nd);
-	if (nd->chat_id && (cd=(struct chat_data*)map_id2bl(nd->chat_id))){
-		aFree (cd);
-		cd = NULL;
-	}	
-	if (nd->bl.subtype == SCRIPT) {
-		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;
-			}
-		}
-	}
-	clif_clearchar_area(&nd->bl, 2);
-	map_delblock(&nd->bl);
-	map_deliddb(&nd->bl);
-	aFree(nd);
-	nd = NULL;
 
-	return 0;
-}
 static int ev_db_final(void *key,void *data,va_list ap)
 {
 	aFree(data);
@@ -2318,25 +2401,70 @@ static int npcname_db_final(void *key,void *data,va_list ap)
  * 
  *------------------------------------------
  */
+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_data *nd;
-	struct block_list *bl;
-	int i;	
+	struct npc_src_list *nsl;
+	int m, last_npc_id;
+	time_t last_time = time(0);
+	int busy = 0;
+	char c = '-';
 
-	if(ev_db) 
+	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);
 
-	for (i = START_NPC_NUM; i < npc_id; i++) {
-		if((bl = map_id2bl(i)) && bl->type == BL_NPC && (nd = (struct npc_data *)bl))
-			npc_unload(nd);
+	// 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;
-
-	
 }
 /*==========================================
  * 終了
@@ -2378,15 +2506,6 @@ int do_final_npc(void)
 	return 0;
 }
 
-
-void ev_release(struct dbn *db, int which)
-{
-    if (which & 0x1)
-        aFree(db->key);
-    if (which & 0x2)
-        aFree(db->data);
-}
-
 /*==========================================
  * npc初期化
  *------------------------------------------
@@ -2394,9 +2513,6 @@ 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;
 	time_t last_time = time(0);
 	int busy = 0;
 	char c = '-';
@@ -2411,75 +2527,17 @@ int do_init_npc(void)
 	//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));
+	memset(&ev_tm_b, -1, sizeof(ev_tm_b));
 
-	for(nsl=npc_src_first;nsl;nsl=nsl->next) {
+	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);
-		}
-		current_file=nsl->name;
-		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);
-			}
-		}
-		fclose(fp);
+		//
+		npc_parsesrcfile(nsl->name);
 		current_file = NULL;
 		printf("\r");
 		ShowStatus("Loading NPCs... Working: ");
@@ -2498,14 +2556,13 @@ int do_init_npc(void)
 //		fflush(stdout);
 	}
 	printf("\r");
-	sprintf(tmp_output,"Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:%30s\n\t-'"
+	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);
-	ShowInfo(tmp_output);	
-
+		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");

+ 3 - 1
src/map/npc.h

@@ -52,7 +52,9 @@ int npc_timerevent_start(struct npc_data *nd, int rid);
 int npc_timerevent_stop(struct npc_data *nd);
 int npc_gettimerevent_tick(struct npc_data *nd);
 int npc_settimerevent_tick(struct npc_data *nd,int newtimer);
-int npc_delete(struct npc_data *nd);
+int npc_remove_map(struct npc_data *nd);
+int npc_unload(struct npc_data *nd);
+int npc_reload(void);
 
 extern char *current_file;
 

+ 2 - 1
src/map/pet.c

@@ -889,7 +889,8 @@ int pet_catch_process2(struct map_session_data *sd,int target_id)
 		pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
 
 	if(rand()%10000 < pet_catch_rate) {
-		mob_catch_delete(md,0);
+		mob_remove_map(md,0);
+		mob_setdelayspawn(md->bl.id);
 		clif_pet_rulet(sd,1);
 //		if(battle_config.etc_log)
 //			printf("rulet success %d\n",target_id);