瀏覽代碼

* Made remaining csv databases (guild, castle, homunculus, itemdb, mercenary) use sv_readdb, where applicable (follow up to r14524, r14526 and r14532).
- Few databases remain unchanged, which have either a custom layout or are otherwise incompatible with sv_readdb.

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

ai4rei 14 年之前
父節點
當前提交
ad0f39a6ec
共有 5 個文件被更改,包括 350 次插入541 次删除
  1. 2 0
      Changelog-Trunk.txt
  2. 36 77
      src/map/guild.c
  3. 158 193
      src/map/homunculus.c
  4. 75 136
      src/map/itemdb.c
  5. 79 135
      src/map/mercenary.c

+ 2 - 0
Changelog-Trunk.txt

@@ -1,6 +1,8 @@
 Date	Added
 
 2010/12/29
+	* Made remaining csv databases (guild, castle, homunculus, itemdb, mercenary) use sv_readdb, where applicable (follow up to r14524, r14526 and r14532). [Ai4rei]
+	- Few databases remain unchanged, which have either a custom layout or are otherwise incompatible with sv_readdb.
 	* Collection of random insignificant changes. [Ai4rei]
 	- Added progress indication on map-server shutdown when objects are removed from maps, as it takes significant amount of time to complete.
 	- Moved ers_free in db_obj_vclear, so that the node pointer is not used for comparison after it has been freed.

+ 36 - 77
src/map/guild.c

@@ -103,46 +103,34 @@ int guild_checkskill(struct guild *g,int id)
 /*==========================================
  * guild_skill_tree.txt reading - from jA [Komurka]
  *------------------------------------------*/
-int guild_read_guildskill_tree_db(void)
-{
-	int i,k,id=0,ln=0;
-	FILE *fp;
-	char line[1024],*p;
+static bool guild_read_guildskill_tree_db(char* split[], int columns, int current)
+{// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
+	int k, id, skillid;
 
-	memset(guild_skill_tree,0,sizeof(guild_skill_tree));
-	sprintf(line, "%s/guild_skill_tree.txt", db_path);
-	if( (fp=fopen(line,"r"))==NULL){
-		ShowError("can't read %s\n", line);
-		return -1;
+	skillid = atoi(split[0]);
+	id = skillid - GD_SKILLBASE;
+
+	if( id < 0 || id >= MAX_GUILDSKILL )
+	{
+		ShowWarning("guild_read_guildskill_tree_db: Invalid skill id %d.\n", skillid);
+		return false;
+	}
+
+	guild_skill_tree[id].id = skillid;
+	guild_skill_tree[id].max = atoi(split[1]);
+
+	if( guild_skill_tree[id].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[id].max == 0 )
+	{// enable guild's glory when required for emblems
+		guild_skill_tree[id].max = 1;
 	}
-	while(fgets(line, sizeof(line), fp))
+
+	for( k = 0; k < 5; k++ )
 	{
-		char *split[50];
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		for(i=0,p=line;i<12 && p;i++){
-			split[i]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		if(i<12)
-			continue;
-		id = atoi(split[0]) - GD_SKILLBASE;
-		if(id<0 || id>=MAX_GUILDSKILL)
-			continue;
-		guild_skill_tree[id].id=atoi(split[0]);
-		guild_skill_tree[id].max=atoi(split[1]);
-		if (guild_skill_tree[id].id==GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[id].max==0) guild_skill_tree[id].max=1;
-		for(k=0;k<5;k++){
-			guild_skill_tree[id].need[k].id=atoi(split[k*2+2]);
-			guild_skill_tree[id].need[k].lv=atoi(split[k*2+3]);
-		}
-	ln++;
+		guild_skill_tree[id].need[k].id = atoi(split[k*2+2]);
+		guild_skill_tree[id].need[k].lv = atoi(split[k*2+3]);
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"guild_skill_tree.txt");
 
-	return 0;
+	return true;
 }
 
 /*==========================================
@@ -168,51 +156,21 @@ int guild_check_skill_require(struct guild *g,int id)
 	return 1;
 }
 
-static int guild_read_castledb(void)
-{
-	FILE *fp;
-	char line[1024];
-	int j,ln=0;
-	char *str[32],*p;
+static bool guild_read_castledb(char* str[], int columns, int current)
+{// <castle id>,<map name>,<castle name>,<castle event>[,<reserved/unused switch flag>]
 	struct guild_castle *gc;
 
-	sprintf(line, "%s/castle_db.txt", db_path);
-	if( (fp=fopen(line,"r"))==NULL){
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
-
-	while(fgets(line, sizeof(line), fp))
-	{
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		memset(str,0,sizeof(str));
-		for(j=0,p=line;j<6 && p;j++){
-			str[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		if (j < 4) //Insufficient data for castle. [Skotlex]
-		{
-			ShowError("castle_db.txt: invalid line '%s'\n", line);
-			continue;
-		}
-
-		gc=(struct guild_castle *)aCalloc(1,sizeof(struct guild_castle));
-		gc->castle_id=atoi(str[0]);
-		gc->mapindex = mapindex_name2id(str[1]);
-		safestrncpy(gc->castle_name,str[2],NAME_LENGTH);
-		safestrncpy(gc->castle_event,str[3],NAME_LENGTH);
+	CREATE(gc, struct guild_castle, 1);
+	gc->castle_id = atoi(str[0]);
+	gc->mapindex = mapindex_name2id(str[1]);
+	safestrncpy(gc->castle_name, str[2], sizeof(gc->castle_name));
+	safestrncpy(gc->castle_event, str[3], sizeof(gc->castle_event));
 
-		idb_put(castle_db,gc->castle_id,gc);
+	idb_put(castle_db,gc->castle_id,gc);
 
-		//intif_guild_castle_info(gc->castle_id);
+	//intif_guild_castle_info(gc->castle_id);
 
-		ln++;
-	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"castle_db.txt");
-	return 0;
+	return true;
 }
 
 /// lookup: guild id -> guild*
@@ -1969,9 +1927,10 @@ void do_init_guild(void)
 	expcache_ers = ers_new(sizeof(struct guild_expcache)); 
 	guild_castleinfoevent_db=idb_alloc(DB_OPT_BASE);
 
-	guild_read_castledb();
+	sv_readdb(db_path, "castle_db.txt", ',', 4, 5, -1, &guild_read_castledb);
 
-	guild_read_guildskill_tree_db(); //guild skill tree [Komurka]
+	memset(guild_skill_tree,0,sizeof(guild_skill_tree));
+	sv_readdb(db_path, "guild_skill_tree.txt", ',', 12, 12, -1, &guild_read_guildskill_tree_db); //guild skill tree [Komurka]
 
 	add_timer_func_list(guild_payexp_timer,"guild_payexp_timer");
 	add_timer_func_list(guild_send_xy_timer, "guild_send_xy_timer");

+ 158 - 193
src/map/homunculus.c

@@ -8,6 +8,7 @@
 #include "../common/nullpo.h"
 #include "../common/mmo.h"
 #include "../common/showmsg.h"
+#include "../common/strlib.h"
 #include "../common/utils.h"
 
 #include "log.h"
@@ -876,226 +877,190 @@ int merc_hom_shuffle(struct homun_data *hd)
 	return 1;
 }
 
+static bool read_homunculusdb_sub(char* str[], int columns, int current)
+{
+	int classid; 
+	struct s_homunculus_db *db;
+
+	//Base Class,Evo Class
+	classid = atoi(str[0]);
+	if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
+	{
+		ShowError("read_homunculusdb : Invalid class %d\n", classid);
+		return false;
+	}
+	db = &homunculus_db[current];
+	db->base_class = classid;
+	classid = atoi(str[1]);
+	if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
+	{
+		db->base_class = 0;
+		ShowError("read_homunculusdb : Invalid class %d\n", classid);
+		return false;
+	}
+	db->evo_class = classid;
+	//Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
+	strncpy(db->name,str[2],NAME_LENGTH-1);
+	db->foodID = atoi(str[3]);
+	db->hungryDelay = atoi(str[4]);
+	db->base_size = atoi(str[5]);
+	db->evo_size = atoi(str[6]);
+	db->race = atoi(str[7]);
+	db->element = atoi(str[8]);
+	db->baseASPD = atoi(str[9]);
+	//base HP, SP, str, agi, vit, int, dex, luk
+	db->base.HP = atoi(str[10]);
+	db->base.SP = atoi(str[11]);
+	db->base.str = atoi(str[12]);
+	db->base.agi = atoi(str[13]);
+	db->base.vit = atoi(str[14]);
+	db->base.int_= atoi(str[15]);
+	db->base.dex = atoi(str[16]);
+	db->base.luk = atoi(str[17]);
+	//Growth Min/Max HP, SP, str, agi, vit, int, dex, luk
+	db->gmin.HP = atoi(str[18]);
+	db->gmax.HP = atoi(str[19]);
+	db->gmin.SP = atoi(str[20]);
+	db->gmax.SP = atoi(str[21]);
+	db->gmin.str = atoi(str[22]);
+	db->gmax.str = atoi(str[23]);
+	db->gmin.agi = atoi(str[24]);
+	db->gmax.agi = atoi(str[25]);
+	db->gmin.vit = atoi(str[26]);
+	db->gmax.vit = atoi(str[27]);
+	db->gmin.int_= atoi(str[28]);
+	db->gmax.int_= atoi(str[29]);
+	db->gmin.dex = atoi(str[30]);
+	db->gmax.dex = atoi(str[31]);
+	db->gmin.luk = atoi(str[32]);
+	db->gmax.luk = atoi(str[33]);
+	//Evolution Min/Max HP, SP, str, agi, vit, int, dex, luk
+	db->emin.HP = atoi(str[34]);
+	db->emax.HP = atoi(str[35]);
+	db->emin.SP = atoi(str[36]);
+	db->emax.SP = atoi(str[37]);
+	db->emin.str = atoi(str[38]);
+	db->emax.str = atoi(str[39]);
+	db->emin.agi = atoi(str[40]);
+	db->emax.agi = atoi(str[41]);
+	db->emin.vit = atoi(str[42]);
+	db->emax.vit = atoi(str[43]);
+	db->emin.int_= atoi(str[44]);
+	db->emax.int_= atoi(str[45]);
+	db->emin.dex = atoi(str[46]);
+	db->emax.dex = atoi(str[47]);
+	db->emin.luk = atoi(str[48]);
+	db->emax.luk = atoi(str[49]);
+
+	//Check that the min/max values really are below the other one.
+	if(db->gmin.HP > db->gmax.HP)
+		db->gmin.HP = db->gmax.HP;
+	if(db->gmin.SP > db->gmax.SP)
+		db->gmin.SP = db->gmax.SP;
+	if(db->gmin.str > db->gmax.str)
+		db->gmin.str = db->gmax.str;
+	if(db->gmin.agi > db->gmax.agi)
+		db->gmin.agi = db->gmax.agi;
+	if(db->gmin.vit > db->gmax.vit)
+		db->gmin.vit = db->gmax.vit;
+	if(db->gmin.int_> db->gmax.int_)
+		db->gmin.int_= db->gmax.int_;
+	if(db->gmin.dex > db->gmax.dex)
+		db->gmin.dex = db->gmax.dex;
+	if(db->gmin.luk > db->gmax.luk)
+		db->gmin.luk = db->gmax.luk;
+
+	if(db->emin.HP > db->emax.HP)
+		db->emin.HP = db->emax.HP;
+	if(db->emin.SP > db->emax.SP)
+		db->emin.SP = db->emax.SP;
+	if(db->emin.str > db->emax.str)
+		db->emin.str = db->emax.str;
+	if(db->emin.agi > db->emax.agi)
+		db->emin.agi = db->emax.agi;
+	if(db->emin.vit > db->emax.vit)
+		db->emin.vit = db->emax.vit;
+	if(db->emin.int_> db->emax.int_)
+		db->emin.int_= db->emax.int_;
+	if(db->emin.dex > db->emax.dex)
+		db->emin.dex = db->emax.dex;
+	if(db->emin.luk > db->emax.luk)
+		db->emin.luk = db->emax.luk;
+
+	return true;
+}
+
 int read_homunculusdb(void)
 {
-	FILE *fp;
-	char line[1024], *p;
-	int i, k, classid; 
-	int j = 0;
+	int i;
 	const char *filename[]={"homunculus_db.txt","homunculus_db2.txt"};
-	char *str[50];
-	struct s_homunculus_db *db;
 
 	memset(homunculus_db,0,sizeof(homunculus_db));
-	for(i = 0; i<2; i++)
+	for(i = 0; i<ARRAYLENGTH(filename); i++)
 	{
-		sprintf(line, "%s/%s", db_path, filename[i]);
-		fp = fopen(line,"r");
-		if(!fp){
-			if(i != 0)
-				continue;
-			ShowError("read_homunculusdb : can't read %s\n", line);
-			return -1;
-		}
+		char path[256];
 
-		while(fgets(line, sizeof(line), fp) && j < MAX_HOMUNCULUS_CLASS)
+		if( i > 0 )
 		{
-			if(line[0] == '/' && line[1] == '/')
-				continue;
+			sprintf(path, "%s/%s", db_path, filename[i]);
 
-			k = 0;
-			p = strtok (line,",");
-			while (p != NULL && k < 50)
-			{
-				str[k++] = p;
-				p = strtok (NULL, ",");
-			}
-			if (k < 50 )
-			{
-				ShowError("read_homunculusdb : Incorrect number of columns at %s, homunculus %d. Read %d columns, 50 are needed.\n", filename[i], j+1, k);
-				continue;
-			}
-			
-			//Base Class,Evo Class
-			classid = atoi(str[0]);
-			if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
-			{
-				ShowError("read_homunculusdb : Invalid class %d (%s)\n", classid, filename[i]);
-				continue;
-			}
-			db = &homunculus_db[j];
-			db->base_class = classid;
-			classid = atoi(str[1]);
-			if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
+			if( !exists(path) )
 			{
-				db->base_class = 0;
-				ShowError("read_homunculusdb : Invalid class %d (%s)\n", classid, filename[i]);
 				continue;
 			}
-			db->evo_class = classid;
-			//Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
-			strncpy(db->name,str[2],NAME_LENGTH-1);
-			db->foodID = atoi(str[3]);
-			db->hungryDelay = atoi(str[4]);
-			db->base_size = atoi(str[5]);
-			db->evo_size = atoi(str[6]);
-			db->race = atoi(str[7]);
-			db->element = atoi(str[8]);
-			db->baseASPD = atoi(str[9]);
-			//base HP, SP, str, agi, vit, int, dex, luk
-			db->base.HP = atoi(str[10]);
-			db->base.SP = atoi(str[11]);
-			db->base.str = atoi(str[12]);
-			db->base.agi = atoi(str[13]);
-			db->base.vit = atoi(str[14]);
-			db->base.int_= atoi(str[15]);
-			db->base.dex = atoi(str[16]);
-			db->base.luk = atoi(str[17]);
-			//Growth Min/Max HP, SP, str, agi, vit, int, dex, luk
-			db->gmin.HP = atoi(str[18]);
-			db->gmax.HP = atoi(str[19]);
-			db->gmin.SP = atoi(str[20]);
-			db->gmax.SP = atoi(str[21]);
-			db->gmin.str = atoi(str[22]);
-			db->gmax.str = atoi(str[23]);
-			db->gmin.agi = atoi(str[24]);
-			db->gmax.agi = atoi(str[25]);
-			db->gmin.vit = atoi(str[26]);
-			db->gmax.vit = atoi(str[27]);
-			db->gmin.int_= atoi(str[28]);
-			db->gmax.int_= atoi(str[29]);
-			db->gmin.dex = atoi(str[30]);
-			db->gmax.dex = atoi(str[31]);
-			db->gmin.luk = atoi(str[32]);
-			db->gmax.luk = atoi(str[33]);
-			//Evolution Min/Max HP, SP, str, agi, vit, int, dex, luk
-			db->emin.HP = atoi(str[34]);
-			db->emax.HP = atoi(str[35]);
-			db->emin.SP = atoi(str[36]);
-			db->emax.SP = atoi(str[37]);
-			db->emin.str = atoi(str[38]);
-			db->emax.str = atoi(str[39]);
-			db->emin.agi = atoi(str[40]);
-			db->emax.agi = atoi(str[41]);
-			db->emin.vit = atoi(str[42]);
-			db->emax.vit = atoi(str[43]);
-			db->emin.int_= atoi(str[44]);
-			db->emax.int_= atoi(str[45]);
-			db->emin.dex = atoi(str[46]);
-			db->emax.dex = atoi(str[47]);
-			db->emin.luk = atoi(str[48]);
-			db->emax.luk = atoi(str[49]);
-
-			//Check that the min/max values really are below the other one.
-			if(db->gmin.HP > db->gmax.HP)
-				db->gmin.HP = db->gmax.HP;
-			if(db->gmin.SP > db->gmax.SP)
-				db->gmin.SP = db->gmax.SP;
-			if(db->gmin.str > db->gmax.str)
-				db->gmin.str = db->gmax.str;
-			if(db->gmin.agi > db->gmax.agi)
-				db->gmin.agi = db->gmax.agi;
-			if(db->gmin.vit > db->gmax.vit)
-				db->gmin.vit = db->gmax.vit;
-			if(db->gmin.int_> db->gmax.int_)
-				db->gmin.int_= db->gmax.int_;
-			if(db->gmin.dex > db->gmax.dex)
-				db->gmin.dex = db->gmax.dex;
-			if(db->gmin.luk > db->gmax.luk)
-				db->gmin.luk = db->gmax.luk;
-
-			if(db->emin.HP > db->emax.HP)
-				db->emin.HP = db->emax.HP;
-			if(db->emin.SP > db->emax.SP)
-				db->emin.SP = db->emax.SP;
-			if(db->emin.str > db->emax.str)
-				db->emin.str = db->emax.str;
-			if(db->emin.agi > db->emax.agi)
-				db->emin.agi = db->emax.agi;
-			if(db->emin.vit > db->emax.vit)
-				db->emin.vit = db->emax.vit;
-			if(db->emin.int_> db->emax.int_)
-				db->emin.int_= db->emax.int_;
-			if(db->emin.dex > db->emax.dex)
-				db->emin.dex = db->emax.dex;
-			if(db->emin.luk > db->emax.luk)
-				db->emin.luk = db->emax.luk;
-
-			j++;
 		}
-		if (j > MAX_HOMUNCULUS_CLASS)
-			ShowWarning("read_homunculusdb: Reached max number of homunculus [%d]. Remaining homunculus were not read.\n ", MAX_HOMUNCULUS_CLASS);
-		fclose(fp);
-		ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' homunculus in '"CL_WHITE"db/%s"CL_RESET"'.\n",j,filename[i]);
+
+		sv_readdb(db_path, filename[i], ',', 50, 50, MAX_HOMUNCULUS_CLASS, &read_homunculusdb_sub);
 	}
+
 	return 0;
 }
 
-int read_homunculus_skilldb(void)
-{
-	FILE *fp;
-	char line[1024], *p;
+static bool read_homunculus_skilldb_sub(char* split[], int columns, int current)
+{// <hom class>,<skill id>,<max level>[,<job level>],<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5>
 	int k, classid; 
-	int j = 0;
-	char *split[15];
+	int j;
+	int minJobLevelPresent = 0;
 
-	memset(hskill_tree,0,sizeof(hskill_tree));
-	sprintf(line, "%s/homun_skill_tree.txt", db_path);
-	fp=fopen(line,"r");
-	if(fp==NULL){
-		ShowError("can't read %s\n", line);
-		return 1;
-	}
+	if( columns == 14 )
+		minJobLevelPresent = 1;	// MinJobLvl has been added
 
-	while(fgets(line, sizeof(line), fp))
+	// check for bounds [celest]
+	classid = atoi(split[0]) - HM_CLASS_BASE;
+	if ( classid >= MAX_HOMUNCULUS_CLASS )
 	{
-		int minJobLevelPresent = 0;
-
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-
-		k = 0;
-		p = strtok(line,",");
-		while (p != NULL && k < 15)
-		{
-			split[k++] = p;
-			p = strtok(NULL, ",");
-		}
-
-		if(k < 13)
-			continue;
-
-		if (k == 14)
-			minJobLevelPresent = 1;	// MinJobLvl has been added
+		ShowWarning("read_homunculus_skilldb: Invalud homunculus class %d.\n", atoi(split[0]));
+		return false;
+	}
 
-		// check for bounds [celest]
-		classid = atoi(split[0]) - HM_CLASS_BASE;
-		if ( classid >= MAX_HOMUNCULUS_CLASS )
-			continue;
+	k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
+	// Search an empty line or a line with the same skill_id (stored in j)
+	ARR_FIND( 0, MAX_SKILL_TREE, j, !hskill_tree[classid][j].id || hskill_tree[classid][j].id == k );
+	if (j == MAX_SKILL_TREE)
+	{
+		ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", k, classid);
+		return false;
+	}
 
-		k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
-		// Search an empty line or a line with the same skill_id (stored in j)
-		for(j = 0; j < MAX_SKILL_TREE && hskill_tree[classid][j].id && hskill_tree[classid][j].id != k; j++);
+	hskill_tree[classid][j].id = k;
+	hskill_tree[classid][j].max = atoi(split[2]);
+	if (minJobLevelPresent)
+		hskill_tree[classid][j].joblv = atoi(split[3]);
 
-		if (j == MAX_SKILL_TREE)
-		{
-			ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", k, classid);
-			continue;
-		}
+	for( k = 0; k < MAX_PC_SKILL_REQUIRE; k++ )
+	{
+		hskill_tree[classid][j].need[k].id = atoi(split[3+k*2+minJobLevelPresent]);
+		hskill_tree[classid][j].need[k].lv = atoi(split[3+k*2+minJobLevelPresent+1]);
+	}
 
-		hskill_tree[classid][j].id=k;
-		hskill_tree[classid][j].max=atoi(split[2]);
-		if (minJobLevelPresent)
-			hskill_tree[classid][j].joblv=atoi(split[3]);
+	return true;
+}
 
-		for(k=0;k<MAX_PC_SKILL_REQUIRE;k++){
-			hskill_tree[classid][j].need[k].id=atoi(split[3+k*2+minJobLevelPresent]);
-			hskill_tree[classid][j].need[k].lv=atoi(split[3+k*2+minJobLevelPresent+1]);
-		}
-	}
+int read_homunculus_skilldb(void)
+{
+	memset(hskill_tree,0,sizeof(hskill_tree));
+	sv_readdb(db_path, "homun_skill_tree.txt", ',', 13, 14, -1, &read_homunculus_skilldb_sub);
 
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","homun_skill_tree.txt");
 	return 0;
 }
 

+ 75 - 136
src/map/itemdb.c

@@ -471,46 +471,32 @@ int itemdb_isidentified(int nameid)
 /*==========================================
  * アイテム使用可能フラグのオーバーライド
  *------------------------------------------*/
-static int itemdb_read_itemavail (void)
-{
-	FILE *fp;
-	int nameid, j, k, ln = 0;
-	char line[1024], *str[10], *p;
+static bool itemdb_read_itemavail(char* str[], int columns, int current)
+{// <nameid>,<sprite>
+	int nameid, sprite;
 	struct item_data *id;
 
-	sprintf(line, "%s/item_avail.txt", db_path);
-	if ((fp = fopen(line,"r")) == NULL) {
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
+	nameid = atoi(str[0]);
 
-	while(fgets(line, sizeof(line), fp))
+	if( ( id = itemdb_exists(nameid) ) == NULL )
 	{
-		if (line[0] == '/' && line[1] == '/')
-			continue;
-		memset(str, 0, sizeof(str));
-		for (j = 0, p = line; j < 2 && p; j++) {
-			str[j] = p;
-			p = strchr(p, ',');
-			if(p) *p++ = 0;
-		}
+		ShowWarning("itemdb_read_itemavail: Invalid item id %d.\n", nameid);
+		return false;
+	}
 
-		if (j < 2 || str[0] == NULL ||
-			(nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
-			continue;
+	sprite = atoi(str[1]);
 
-		k = atoi(str[1]);
-		if (k > 0) {
-			id->flag.available = 1;
-			id->view_id = k;
-		} else
-			id->flag.available = 0;
-		ln++;
+	if( sprite > 0 )
+	{
+		id->flag.available = 1;
+		id->view_id = sprite;
+	}
+	else
+	{
+		id->flag.available = 0;
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_avail.txt");
 
-	return 0;
+	return true;
 }
 
 /*==========================================
@@ -591,137 +577,90 @@ static void itemdb_read_itemgroup(void)
 /*==========================================
  * 装備制限ファイル読み出し
  *------------------------------------------*/
-static int itemdb_read_noequip(void)
-{
-	FILE *fp;
-	char line[1024];
-	int ln=0;
-	int nameid,j;
-	char *str[32],*p;
+static bool itemdb_read_noequip(char* str[], int columns, int current)
+{// <nameid>,<mode>
+	int nameid;
 	struct item_data *id;
 
-	sprintf(line, "%s/item_noequip.txt", db_path);
-	if( (fp=fopen(line,"r"))==NULL ){
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
-	while(fgets(line, sizeof(line), fp))
-	{
-		if(line[0]=='/' && line[1]=='/')
-			continue;
-		memset(str,0,sizeof(str));
-		for(j=0,p=line;j<2 && p;j++){
-			str[j]=p;
-			p=strchr(p,',');
-			if(p) *p++=0;
-		}
-		if(str[0]==NULL)
-			continue;
-
-		nameid=atoi(str[0]);
-		if(nameid<=0 || !(id=itemdb_exists(nameid)))
-			continue;
+	nameid = atoi(str[0]);
 
-		id->flag.no_equip |= atoi(str[1]);
+	if( ( id = itemdb_exists(nameid) ) == NULL )
+	{
+		ShowWarning("itemdb_read_noequip: Invalid item id %d.\n", nameid);
+		return false;
+	}
 
-		ln++;
+	id->flag.no_equip |= atoi(str[1]);
 
-	}
-	fclose(fp);
-	if (ln > 0) {
-		ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"item_noequip.txt");
-	}	
-	return 0;
+	return true;
 }
 
 /*==========================================
  * Reads item trade restrictions [Skotlex]
  *------------------------------------------*/
-static int itemdb_read_itemtrade(void)
-{
-	FILE *fp;
-	int nameid, j, flag, gmlv, ln = 0;
-	char line[1024], *str[10], *p;
+static bool itemdb_read_itemtrade(char* str[], int columns, int current)
+{// <nameid>,<mask>,<gm level>
+	int nameid, flag, gmlv;
 	struct item_data *id;
 
-	sprintf(line, "%s/item_trade.txt", db_path);
-	if ((fp = fopen(line,"r")) == NULL) {
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
+	nameid = atoi(str[0]);
 
-	while(fgets(line, sizeof(line), fp))
+	if( ( id = itemdb_exists(nameid) ) == NULL )
 	{
-		if (line[0] == '/' && line[1] == '/')
-			continue;
-		memset(str, 0, sizeof(str));
-		for (j = 0, p = line; j < 3 && p; j++) {
-			str[j] = p;
-			p = strchr(p, ',');
-			if(p) *p++ = 0;
-		}
+		//ShowWarning("itemdb_read_itemtrade: Invalid item id %d.\n", nameid);
+		//return false;
+		// FIXME: item_trade.txt contains items, which are commented in item database.
+		return true;
+	}
 
-		if (j < 3 || str[0] == NULL ||
-			(nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
-			continue;
+	flag = atoi(str[1]);
+	gmlv = atoi(str[2]);
 
-		flag = atoi(str[1]);
-		gmlv = atoi(str[2]);
-		
-		if (flag > 0 && flag < 128 && gmlv > 0) { //Check range
-			id->flag.trade_restriction = flag;
-			id->gm_lv_trade_override = gmlv;
-			ln++;
-		}
+	if( flag < 0 || flag >= 128 )
+	{//Check range
+		ShowWarning("itemdb_read_itemtrade: Invalid trading mask %d for item id %d.\n", flag, nameid);
+		return false;
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_trade.txt");
 
-	return 0;
+	if( gmlv < 1 )
+	{
+		ShowWarning("itemdb_read_itemtrade: Invalid override GM level %d for item id %d.\n", gmlv, nameid);
+		return false;
+	}
+
+	id->flag.trade_restriction = flag;
+	id->gm_lv_trade_override = gmlv;
+
+	return true;
 }
 
 /*==========================================
  * Reads item delay amounts [Paradox924X]
  *------------------------------------------*/
-static int itemdb_read_itemdelay(void)
-{
-	FILE *fp;
-	int nameid, j, item_delays = 0;
-	char line[1024], *str[10], *p;
+static bool itemdb_read_itemdelay(char* str[], int columns, int current)
+{// <nameid>,<delay>
+	int nameid, delay;
 	struct item_data *id;
 
-	sprintf(line, "%s/item_delay.txt", db_path);
-	if ((fp = fopen(line,"r")) == NULL) {
-		ShowError("can't read %s\n", line);
-		return -1;
-	}
+	nameid = atoi(str[0]);
 
-	while(fgets(line, sizeof(line), fp))
+	if( ( id = itemdb_exists(nameid) ) == NULL )
 	{
-		if (line[0] == '/' && line[1] == '/')
-			continue;
-		if (item_delays == MAX_ITEMDELAYS) {
-			ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt! Increase MAX_ITEMDELAYS in itemdb.h!\n", db_path);
-			break;
-		}
-		memset(str, 0, sizeof(str));
-		for (j = 0, p = line; j < 2 && p; j++) {
-			str[j] = p;
-			p = strchr(p, ',');
-			if(p) *p++ = 0;
-		}
+		ShowWarning("itemdb_read_itemdelay: Invalid item id %d.\n", nameid);
+		return false;
+	}
 
-		if (j < 2 || str[0] == NULL ||
-			(nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
-			continue;
+	delay = atoi(str[1]);
 
-		id->delay = atoi(str[1]);
-		item_delays++;
+	if( delay < 0 )
+	{
+		ShowWarning("itemdb_read_itemdelay: Invalid delay %d for item id %d.\n", id->delay, nameid);
+		return false;
 	}
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", item_delays, "item_delay.txt");
 
-	return 0;
+	id->delay = delay;
+
+	return true;
 }
 
 /*======================================
@@ -1036,10 +975,10 @@ static void itemdb_read(void)
 		itemdb_readdb();
 
 	itemdb_read_itemgroup();
-	itemdb_read_itemavail();
-	itemdb_read_noequip();
-	itemdb_read_itemtrade();
-	itemdb_read_itemdelay();
+	sv_readdb(db_path, "item_avail.txt",   ',', 2, 2, -1,             &itemdb_read_itemavail);
+	sv_readdb(db_path, "item_noequip.txt", ',', 2, 2, -1,             &itemdb_read_noequip);
+	sv_readdb(db_path, "item_trade.txt",   ',', 3, 3, -1,             &itemdb_read_itemtrade);
+	sv_readdb(db_path, "item_delay.txt",   ',', 2, 2, MAX_ITEMDELAYS, &itemdb_read_itemdelay);
 }
 
 /*==========================================

+ 79 - 135
src/map/mercenary.c

@@ -8,6 +8,7 @@
 #include "../common/nullpo.h"
 #include "../common/mmo.h"
 #include "../common/showmsg.h"
+#include "../common/strlib.h"
 #include "../common/utils.h"
 
 #include "log.h"
@@ -402,162 +403,105 @@ int mercenary_checkskill(struct mercenary_data *md, int skill_id)
 	return 0;
 }
 
-int read_mercenarydb(void)
+static bool read_mercenarydb_sub(char* str[], int columns, int current)
 {
-	FILE *fp;
-	char line[1024], *p;
-	char *str[26];
-	int i, j = 0, k = 0, ele;
+	int ele;
 	struct s_mercenary_db *db;
 	struct status_data *status;
 
-	sprintf(line, "%s/%s", db_path, "mercenary_db.txt");
-	memset(mercenary_db,0,sizeof(mercenary_db));
-
-	fp = fopen(line, "r");
-	if( !fp )
+	db = &mercenary_db[current];
+	db->class_ = atoi(str[0]);
+	strncpy(db->sprite, str[1], NAME_LENGTH);
+	strncpy(db->name, str[2], NAME_LENGTH);
+	db->lv = atoi(str[3]);
+
+	status = &db->status;
+	db->vd.class_ = db->class_;
+
+	status->max_hp = atoi(str[4]);
+	status->max_sp = atoi(str[5]);
+	status->rhw.range = atoi(str[6]);
+	status->rhw.atk = atoi(str[7]);
+	status->rhw.atk2 = status->rhw.atk + atoi(str[8]);
+	status->def = atoi(str[9]);
+	status->mdef = atoi(str[10]);
+	status->str = atoi(str[11]);
+	status->agi = atoi(str[12]);
+	status->vit = atoi(str[13]);
+	status->int_ = atoi(str[14]);
+	status->dex = atoi(str[15]);
+	status->luk = atoi(str[16]);
+	db->range2 = atoi(str[17]);
+	db->range3 = atoi(str[18]);
+	status->size = atoi(str[19]);
+	status->race = atoi(str[20]);
+
+	ele = atoi(str[21]);
+	status->def_ele = ele%10;
+	status->ele_lv = ele/20;
+	if( status->def_ele >= ELE_MAX )
 	{
-		ShowError("read_mercenarydb : can't read mercenary_db.txt\n");
-		return -1;
+		ShowWarning("Mercenary %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_MAX - 1);
+		status->def_ele = ELE_NEUTRAL;
 	}
-
-	while( fgets(line, sizeof(line), fp) && j < MAX_MERCENARY_CLASS )
+	if( status->ele_lv < 1 || status->ele_lv > 4 )
 	{
-		k++;
-		if( line[0] == '/' && line[1] == '/' )
-			continue;
-
-		i = 0;
-		p = strtok(line, ",");
-		while( p != NULL && i < 26 )
-		{
-			str[i++] = p;
-			p = strtok(NULL, ",");
-		}
-		if( i < 26 )
-		{
-			ShowError("read_mercenarydb : Incorrect number of columns at mercenary_db.txt line %d.\n", k);
-			continue;
-		}
-
-		db = &mercenary_db[j];
-		db->class_ = atoi(str[0]);
-		strncpy(db->sprite, str[1], NAME_LENGTH);
-		strncpy(db->name, str[2], NAME_LENGTH);
-		db->lv = atoi(str[3]);
-
-		status = &db->status;
-		db->vd.class_ = db->class_;
-
-		status->max_hp = atoi(str[4]);
-		status->max_sp = atoi(str[5]);
-		status->rhw.range = atoi(str[6]);
-		status->rhw.atk = atoi(str[7]);
-		status->rhw.atk2 = status->rhw.atk + atoi(str[8]);
-		status->def = atoi(str[9]);
-		status->mdef = atoi(str[10]);
-		status->str = atoi(str[11]);
-		status->agi = atoi(str[12]);
-		status->vit = atoi(str[13]);
-		status->int_ = atoi(str[14]);
-		status->dex = atoi(str[15]);
-		status->luk = atoi(str[16]);
-		db->range2 = atoi(str[17]);
-		db->range3 = atoi(str[18]);
-		status->size = atoi(str[19]);
-		status->race = atoi(str[20]);
-	
-		ele = atoi(str[21]);
-		status->def_ele = ele%10;
-		status->ele_lv = ele/20;
-		if( status->def_ele >= ELE_MAX )
-		{
-			ShowWarning("Mercenary %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_MAX - 1);
-			status->def_ele = ELE_NEUTRAL;
-		}
-		if( status->ele_lv < 1 || status->ele_lv > 4 )
-		{
-			ShowWarning("Mercenary %d has invalid element level %d (max is 4)\n", db->class_, status->ele_lv);
-			status->ele_lv = 1;
-		}
-
-		status->aspd_rate = 1000;
-		status->speed = atoi(str[22]);
-		status->adelay = atoi(str[23]);
-		status->amotion = atoi(str[24]);
-		status->dmotion = atoi(str[25]);
-
-		j++;
+		ShowWarning("Mercenary %d has invalid element level %d (max is 4)\n", db->class_, status->ele_lv);
+		status->ele_lv = 1;
 	}
 
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' mercenaries in '"CL_WHITE"db/mercenary_db.txt"CL_RESET"'.\n",j);
+	status->aspd_rate = 1000;
+	status->speed = atoi(str[22]);
+	status->adelay = atoi(str[23]);
+	status->amotion = atoi(str[24]);
+	status->dmotion = atoi(str[25]);
 
-	return 0;
+	return true;
 }
 
-int read_mercenary_skilldb(void)
+int read_mercenarydb(void)
 {
-	FILE *fp;
-	char line[1024], *p;
-	char *str[3];
+	memset(mercenary_db,0,sizeof(mercenary_db));
+	sv_readdb(db_path, "mercenary_db.txt", ',', 26, 26, MAX_MERCENARY_CLASS, &read_mercenarydb_sub);
+
+	return 0;
+}
+
+static bool read_mercenary_skilldb_sub(char* str[], int columns, int current)
+{// <merc id>,<skill id>,<skill level>
 	struct s_mercenary_db *db;
-	int i, j = 0, k = 0, class_;
+	int i, class_;
 	int skillid, skilllv;
 
-	sprintf(line, "%s/%s", db_path, "mercenary_skill_db.txt");
-	fp = fopen(line, "r");
-	if( !fp )
+	class_ = atoi(str[0]);
+	ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_);
+	if( i == MAX_MERCENARY_CLASS )
 	{
-		ShowError("read_mercenary_skilldb : can't read mercenary_skill_db.txt\n");
-		return -1;
+		ShowError("read_mercenary_skilldb : Class %d not found in mercenary_db for skill entry.\n", class_);
+		return false;
 	}
-
-	while( fgets(line, sizeof(line), fp) )
+	
+	skillid = atoi(str[1]);
+	if( skillid < MC_SKILLBASE || skillid >= MC_SKILLBASE + MAX_MERCSKILL )
 	{
-		k++;
-		if( line[0] == '/' && line[1] == '/' )
-			continue;
-
-		i = 0;
-		p = strtok(line, ",");
-		while( p != NULL && i < 3 )
-		{
-			str[i++] = p;
-			p = strtok(NULL, ",");
-		}
-		if( i < 3 )
-		{
-			ShowError("read_mercenary_skilldb : Incorrect number of columns at mercenary_skill_db.txt line %d.\n", k);
-			continue;
-		}
-
-		class_ = atoi(str[0]);
-		ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_);
-		if( i == MAX_MERCENARY_CLASS )
-		{
-			ShowError("read_mercenary_skilldb : Class not found in mercenary_db for skill entry, line %d.\n", k);
-			continue;
-		}
-		
-		skillid = atoi(str[1]);
-		if( skillid < MC_SKILLBASE || skillid >= MC_SKILLBASE + MAX_MERCSKILL )
-		{
-			ShowError("read_mercenary_skilldb : Skill out of range, line %d.\n", k);
-			continue;
-		}
-
-		db = &mercenary_db[i];
-		skilllv = atoi(str[2]);
-
-		i = skillid - MC_SKILLBASE;
-		db->skill[i].id = skillid;
-		db->skill[i].lv = skilllv;
-		j++;
+		ShowError("read_mercenary_skilldb : Skill %d out of range.\n", skillid);
+		return false;
 	}
 
-	fclose(fp);
-	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"db/mercenary_skill_db.txt"CL_RESET"'.\n",j);
+	db = &mercenary_db[i];
+	skilllv = atoi(str[2]);
+
+	i = skillid - MC_SKILLBASE;
+	db->skill[i].id = skillid;
+	db->skill[i].lv = skilllv;
+
+	return true;
+}
+
+int read_mercenary_skilldb(void)
+{
+	sv_readdb(db_path, "mercenary_skill_db.txt", ',', 3, 3, -1, &read_mercenary_skilldb_sub);
+
 	return 0;
 }