summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-11-05 14:45:13 +0000
committerultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-11-05 14:45:13 +0000
commit2f254cd153ba353488bb80eb3b217592e32c54cc (patch)
tree2a36d2cbd1704d80a65dce0e61758b98e4252e05
parentb37ff824d8160eb2cc8f45e435cfdb09cf7db077 (diff)
downloadhercules-2f254cd153ba353488bb80eb3b217592e32c54cc.tar.gz
hercules-2f254cd153ba353488bb80eb3b217592e32c54cc.tar.bz2
hercules-2f254cd153ba353488bb80eb3b217592e32c54cc.tar.xz
hercules-2f254cd153ba353488bb80eb3b217592e32c54cc.zip
Corrected the max. allowed skill name length, and optimized code that works with skill names according to latest changes.
Changed skill db loading code to work similarly to how itemdb/mobdb is loaded (generic file loader + specialized function to process rows). * all skill db files are now checked for inconsistencies the same way. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11659 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--Changelog-Trunk.txt5
-rw-r--r--src/map/atcommand.c10
-rw-r--r--src/map/battle.c6
-rw-r--r--src/map/clif.c10
-rw-r--r--src/map/skill.c696
-rw-r--r--src/map/skill.h2
6 files changed, 337 insertions, 392 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index ed953d723..62a6f4e02 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/11/05
+ * Changed skill db loading code to work similarly to how itemdb/mobdb
+ is loaded (generic file loader + specialized function to process rows)
+ - all skill db files are now checked for inconsistencies the same way
+ * Corrected the max. allowed skill name length, and optimized code that
+ works with skill names according to latest changes [ultramage]
* Reverted official drop rate estimation [Playtester]
- although it really exists we don't have enough information about it
- if server owners really want it they can implement it themselves
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 9b15ca0f6..0109cf290 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -5620,8 +5620,7 @@ int atcommand_skillid(const int fd, struct map_session_data* sd, const char* com
skillen = strlen(message);
for (idx = 0; idx < MAX_SKILL_DB; idx++) {
- if ((skill_db[idx].name != NULL && strnicmp(skill_db[idx].name, message, skillen) == 0) ||
- (skill_db[idx].desc != NULL && strnicmp(skill_db[idx].desc, message, skillen) == 0))
+ if (strnicmp(skill_db[idx].name, message, skillen) == 0 || strnicmp(skill_db[idx].desc, message, skillen) == 0)
{
sprintf(atcmd_output, "skill %d: %s", idx, skill_db[idx].desc);
clif_displaymessage(fd, atcmd_output);
@@ -5750,12 +5749,9 @@ int atcommand_skilltree(const int fd, struct map_session_data* sd, const char* c
ent = &skill_tree[c][skillidx];
for(j=0;j<5;j++)
- if( ent->need[j].id &&
- pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
+ if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
{
- char *desc = (skill_db[ ent->need[j].id ].desc) ? skill_db[ ent->need[j].id ].desc : "Unknown skill";
- sprintf(atcmd_output, "player requires level %d of skill %s",
- ent->need[j].lv, desc);
+ sprintf(atcmd_output, "player requires level %d of skill %s", ent->need[j].lv, skill_db[ent->need[j].id].desc);
clif_displaymessage(fd, atcmd_output);
meets = 0;
}
diff --git a/src/map/battle.c b/src/map/battle.c
index 3a865a4a4..1d283e6a1 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1244,7 +1244,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if(wflag>0)
wd.damage/= wflag;
else if(battle_config.error_log)
- ShowError("0 enemies targeted by %s, divide per 0 avoided!\n", skill_get_name(skill_num));
+ ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_num, skill_get_name(skill_num));
}
//Add any bonuses that modify the base baseatk+watk (pre-skills)
@@ -2221,7 +2221,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
if(mflag>0)
ad.damage/= mflag;
else if(battle_config.error_log)
- ShowError("0 enemies targeted by %s, divide per 0 avoided!\n", skill_get_name(skill_num));
+ ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_num, skill_get_name(skill_num));
}
switch(skill_num){
@@ -2564,7 +2564,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
if(mflag>0)
md.damage/= mflag;
else if(battle_config.error_log)
- ShowError("0 enemies targeted by %s, divide per 0 avoided!\n", skill_get_name(skill_num));
+ ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_num, skill_get_name(skill_num));
}
damage_div_fix(md.damage, md.div_);
diff --git a/src/map/clif.c b/src/map/clif.c
index 1d254cf8d..3bdaa3396 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1433,7 +1433,7 @@ int clif_homskillinfoblock(struct map_session_data *sd)
WFIFOW(fd,len+6) = hd->homunculus.hskill[j].lv ;
WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv) ;
WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,hd->homunculus.hskill[j].lv) ;
- strncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH) ;
+ safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH) ;
WFIFOB(fd,len+36) = (hd->homunculus.hskill[j].lv < merc_skill_tree_get_max(id, hd->homunculus.class_))?1:0;
len+=37;
}
@@ -4135,7 +4135,7 @@ int clif_skillinfo(struct map_session_data *sd,int skillid,int type,int range)
range = skill_get_range2(&sd->bl, id,sd->status.skill[skillid].lv);
WFIFOW(fd,12)= range;
- strncpy((char*)WFIFOP(fd,14), skill_get_name(id), NAME_LENGTH);
+ safestrncpy((char*)WFIFOP(fd,14), skill_get_name(id), NAME_LENGTH);
if(sd->status.skill[skillid].flag ==0)
WFIFOB(fd,38)= (sd->status.skill[skillid].lv < skill_tree_get_max(id, sd->status.class_))? 1:0;
else
@@ -4170,7 +4170,7 @@ int clif_skillinfoblock(struct map_session_data *sd)
WFIFOW(fd,len+6) = sd->status.skill[i].lv;
WFIFOW(fd,len+8) = skill_get_sp(id,sd->status.skill[i].lv);
WFIFOW(fd,len+10)= skill_get_range2(&sd->bl, id,sd->status.skill[i].lv);
- strncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
+ safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
if(sd->status.skill[i].flag == 0)
WFIFOB(fd,len+36) = (sd->status.skill[i].lv < skill_tree_get_max(id, sd->status.class_))? 1:0;
else
@@ -5261,7 +5261,7 @@ int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv)
WFIFOW(fd, 8)=skilllv;
WFIFOW(fd,10)=skill_get_sp(skillid,skilllv);
WFIFOW(fd,12)=skill_get_range2(&sd->bl, skillid,skilllv);
- strncpy((char*)WFIFOP(fd,14),skill_get_name(skillid),NAME_LENGTH);
+ safestrncpy((char*)WFIFOP(fd,14),skill_get_name(skillid),NAME_LENGTH);
WFIFOB(fd,38)=0;
WFIFOSET(fd,packet_len(0x147));
return 0;
@@ -6623,7 +6623,7 @@ int clif_guild_skillinfo(struct map_session_data* sd)
WFIFOW(fd,c*37+12) = g->skill[i].lv;
WFIFOW(fd,c*37+14) = skill_get_sp(id, g->skill[i].lv);
WFIFOW(fd,c*37+16) = skill_get_range(id, g->skill[i].lv);
- strncpy((char*)WFIFOP(fd,c*37+18), skill_get_name(id), NAME_LENGTH);
+ safestrncpy((char*)WFIFOP(fd,c*37+18), skill_get_name(id), NAME_LENGTH);
WFIFOB(fd,c*37+42)= (g->skill[i].lv < guild_skill_get_max(id) && sd == g->member[0].sd) ? 1 : 0;
c++;
}
diff --git a/src/map/skill.c b/src/map/skill.c
index 5c96ba3f2..d63269a7b 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -83,14 +83,12 @@ static int skill_get_index( int id )
const char* skill_get_name( int id )
{
- int index = skill_get_index(id);
- return ( index > 0 ) ? skill_db[id].name : "UNKNOWN_SKILL";
+ return skill_db[skill_get_index(id)].name;
}
const char* skill_get_desc( int id )
{
- int index = skill_get_index(id);
- return ( index > 0 ) ? skill_db[id].desc : "Unknown Skill";
+ return skill_db[skill_get_index(id)].desc;
}
// macros to check for out of bounds errors [celest]
@@ -7394,8 +7392,7 @@ static int skill_check_condition_mob_master_sub (struct block_list *bl, va_list
skill=va_arg(ap,int);
c=va_arg(ap,int *);
- if(md->master_id != src_id ||
- md->special_state.ai != (skill == AM_SPHEREMINE?2:3))
+ if( md->master_id != src_id || md->special_state.ai != (unsigned)(skill == AM_SPHEREMINE?2:3) )
return 0; //Non alchemist summoned mobs have nothing to do here.
if(md->class_==mob_class)
@@ -8549,7 +8546,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
clif_misceffect(&sd->bl,3);
if(item->refine == MAX_REFINE &&
item->card[0] == CARD0_FORGE &&
- MakeDWord(item->card[2],item->card[3]) == sd->status.char_id)
+ (int)MakeDWord(item->card[2],item->card[3]) == sd->status.char_id)
{ // Fame point system [DracoRPG]
switch(ditem->wlv){
case 1:
@@ -10710,422 +10707,369 @@ void skill_init_unit_layout (void)
/*==========================================
* DB reading.
* skill_db.txt
+ * skill_require_db.txt
* skill_cast_db.txt
+ * skill_unit_db.txt
* produce_db.txt
* create_arrow_db.txt
* abra_db.txt
+ * skill_castnodex_db.txt
+ * skill_nocast_db.txt
*------------------------------------------*/
-int skill_readdb (void)
+/// Opens and parses a CSV file into columns, feeding them to the specified callback function row by row.
+/// Tracks the progress of the operation (file position, number of successfully processed rows).
+/// Returns 'true' if it was able to process the specified file, or 'false' if it could not be read.
+static bool skill_read_csvdb( const char* directory, const char* filename, int mincolumns, bool (*parseproc)(char* split[], int columns, int current) )
{
- int i,j,k,l,lines;
- FILE *fp;
- char line[1024],path[1024],*p;
-
- // load 'skill_db.txt'
- memset(skill_db,0,sizeof(skill_db));
- sprintf(path, "%s/skill_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+ FILE* fp;
+ int lines = 0;
+ int entries = 0;
+ char path[1024], line[1024];
+
+ // open file
+ snprintf(path, sizeof(path), "%s/%s", directory, filename);
+ fp = fopen(path,"r");
+ if( fp == NULL )
+ {
+ ShowError("skill_read_db: can't read %s\n", path);
+ return false;
}
- lines = 0;
- while(fgets(line, sizeof(line), fp))
+
+ // process rows one by one
+ while( fgets(line, sizeof(line), fp) )
{
char* split[50];
+ int columns;
+
lines++;
- if(line[0]=='/' && line[1]=='/')
+ if( line[0] == '/' && line[1] == '/' )
continue;
- j = skill_split_str(line,split,17);
- if( j < 2 )
+ //TODO: strip trailing // comment
+ //TODO: strip trailing whitespace
+ //TODO: skip empty lines
+
+ memset(split,0,sizeof(split));
+ columns = skill_split_str(line,split,ARRAYLENGTH(split));
+ if( columns < 2 ) // FIXME: assumes db has at least 2 mandatory columns
continue; // empty line
- if( j < 17 )
+ if( columns < mincolumns )
{
- ShowError("skill_readdb: Insufficient columns in line %d of \"%s\" (skill with id %d), skipping.\n", lines, path, atoi(split[0]));
+ ShowError("skill_read_csvdb: Insufficient columns in line %d of \"%s\" (found %d, need at least %d).\n", lines, path, columns, mincolumns);
continue; // not enough columns
}
-
- i = atoi(split[0]);
- if (i >= GD_SKILLRANGEMIN && i <= GD_SKILLRANGEMAX) {
- ShowWarning("read skill_db: Can't use skill id %d as guild skills are placed there!\n");
- continue;
+ if( columns > ARRAYLENGTH(split) )
+ {
+ ShowError("skill_read_csvdb: Too many columns in line %d of \"%s\" (found %d, capacity %d). Increase the capacity in the source code please.\n", lines, path, columns, ARRAYLENGTH(split) );
+ continue; // source code problem
}
- i = skill_get_index(i);
- if (i == 0) // invalid skill id
- continue;
-
- skill_split_atoi(split[1],skill_db[i].range);
- skill_db[i].hit=atoi(split[2]);
- skill_db[i].inf=atoi(split[3]);
- skill_split_atoi(split[4],skill_db[i].element);
- skill_db[i].nk=(int)strtol(split[5], NULL, 0);
- skill_split_atoi(split[6],skill_db[i].splash);
- skill_db[i].max=atoi(split[7]);
- skill_split_atoi(split[8],skill_db[i].num);
-
- if(strcmpi(split[9],"yes") == 0)
- skill_db[i].castcancel=1;
- else
- skill_db[i].castcancel=0;
- skill_db[i].cast_def_rate=atoi(split[10]);
- skill_db[i].inf2=(int)strtol(split[11], NULL, 0);
- skill_split_atoi(split[12], skill_db[i].maxcount);
- if(strcmpi(split[13],"weapon") == 0)
- skill_db[i].skill_type=BF_WEAPON;
- else if(strcmpi(split[13],"magic") == 0)
- skill_db[i].skill_type=BF_MAGIC;
- else if(strcmpi(split[13],"misc") == 0)
- skill_db[i].skill_type=BF_MISC;
- else
- skill_db[i].skill_type=0;
- skill_split_atoi(split[14],skill_db[i].blewcount);
- safestrncpy(skill_db[i].name, split[15], sizeof(skill_db[i].name));
- safestrncpy(skill_db[i].desc, split[16], sizeof(skill_db[i].desc));
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
- // load 'skill_require_db.txt'
- sprintf(path, "%s/skill_require_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+ // parse this row
+ if( parseproc(split, columns, entries) )
+ entries++;
}
- while(fgets(line, sizeof(line), fp))
- {
- char *split[50];
- if(line[0]=='/' && line[1]=='/')
- continue;
- j = skill_split_str(line,split,32);
- if( j < 32 )
- continue;
- i = atoi(split[0]);
- i = skill_get_index(i);
- if(i == 0) // invalid skill id
- continue;
+ fclose(fp);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path);
- skill_split_atoi(split[1],skill_db[i].hp);
- skill_split_atoi(split[2],skill_db[i].mhp);
- skill_split_atoi(split[3],skill_db[i].sp);
- skill_split_atoi(split[4],skill_db[i].hp_rate);
- skill_split_atoi(split[5],skill_db[i].sp_rate);
- skill_split_atoi(split[6],skill_db[i].zeny);
-
- p = split[7];
- for(j=0;j<32;j++){
- l = atoi(p);
- if (l==99) {
- skill_db[i].weapon = 0xffffffff;
- break;
- }
- else
- skill_db[i].weapon |= 1<<l;
- p=strchr(p,':');
- if(!p)
- break;
- p++;
- }
+ return true;
+}
- p = split[8];
- for(j=0;j<32;j++){
- l = atoi(p);
- if (l==99) {
- skill_db[i].ammo = 0xffffffff;
- break;
- }
- else if (l)
- skill_db[i].ammo |= 1<<l;
- p=strchr(p,':');
- if(!p)
- break;
- p++;
- }
- skill_split_atoi(split[9],skill_db[i].ammo_qty);
-
- if( strcmpi(split[10],"hiding")==0 ) skill_db[i].state=ST_HIDING;
- else if( strcmpi(split[10],"cloaking")==0 ) skill_db[i].state=ST_CLOAKING;
- else if( strcmpi(split[10],"hidden")==0 ) skill_db[i].state=ST_HIDDEN;
- else if( strcmpi(split[10],"riding")==0 ) skill_db[i].state=ST_RIDING;
- else if( strcmpi(split[10],"falcon")==0 ) skill_db[i].state=ST_FALCON;
- else if( strcmpi(split[10],"cart")==0 ) skill_db[i].state=ST_CART;
- else if( strcmpi(split[10],"shield")==0 ) skill_db[i].state=ST_SHIELD;
- else if( strcmpi(split[10],"sight")==0 ) skill_db[i].state=ST_SIGHT;
- else if( strcmpi(split[10],"explosionspirits")==0 ) skill_db[i].state=ST_EXPLOSIONSPIRITS;
- else if( strcmpi(split[10],"cartboost")==0 ) skill_db[i].state=ST_CARTBOOST;
- else if( strcmpi(split[10],"recover_weight_rate")==0 ) skill_db[i].state=ST_RECOV_WEIGHT_RATE;
- else if( strcmpi(split[10],"move_enable")==0 ) skill_db[i].state=ST_MOVE_ENABLE;
- else if( strcmpi(split[10],"water")==0 ) skill_db[i].state=ST_WATER;
- else skill_db[i].state=ST_NONE;
-
- skill_split_atoi(split[11],skill_db[i].spiritball);
- for (j = 0; j < 10; j++) {
- skill_db[i].itemid[j]=atoi(split[12+ 2*j]);
- skill_db[i].amount[j]=atoi(split[13+ 2*j]);
- }
+static bool skill_parse_row_skilldb(char* split[], int columns, int current)
+{// id,range,hit,inf,element,nk,splash,max,list_num,castcancel,cast_defence_rate,inf2,maxcount,skill_type,blow_count,name,description
+ int i = atoi(split[0]);
+ if( i >= GD_SKILLRANGEMIN && i <= GD_SKILLRANGEMAX ) {
+ ShowWarning("skill_parse_row_skilldb: Skill id %d is forbidden (interferes with guild skill mapping)!\n");
+ return false;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
-
- // load 'skill_cast_db.txt'
- sprintf(path, "%s/skill_cast_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+ if( i >= HM_SKILLRANGEMIN && i <= HM_SKILLRANGEMAX ) {
+ ShowWarning("skill_parse_row_skilldb: Skill id %d is forbidden (interferes with homunculus skill mapping)!\n");
+ return false;
}
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
- l=0;
- while(fgets(line, sizeof(line), fp))
- {
- char *split[50];
- l++;
- memset(split,0,sizeof(split)); // [Valaris] thanks to fov
- if(line[0]=='/' && line[1]=='/')
- continue;
- j = skill_split_str(line,split,6);
- if( j < 2 )
- continue; //Blank line.
- if( j < 6) {
- ShowWarning("skill_cast_db.txt: Insufficient number of fields at line %d\n", l);
- continue;
- }
- i = atoi(split[0]);
- i = skill_get_index(i);
- if(i == 0) // invalid skill id
- continue;
+ skill_split_atoi(split[1],skill_db[i].range);
+ skill_db[i].hit = atoi(split[2]);
+ skill_db[i].inf = atoi(split[3]);
+ skill_split_atoi(split[4],skill_db[i].element);
+ skill_db[i].nk = (int)strtol(split[5], NULL, 0);
+ skill_split_atoi(split[6],skill_db[i].splash);
+ skill_db[i].max = atoi(split[7]);
+ skill_split_atoi(split[8],skill_db[i].num);
+
+ if( strcmpi(split[9],"yes") == 0 )
+ skill_db[i].castcancel = 1;
+ else
+ skill_db[i].castcancel = 0;
+ skill_db[i].cast_def_rate = atoi(split[10]);
+ skill_db[i].inf2 = (int)strtol(split[11], NULL, 0);
+ skill_split_atoi(split[12],skill_db[i].maxcount);
+ if( strcmpi(split[13],"weapon") == 0 )
+ skill_db[i].skill_type = BF_WEAPON;
+ else if( strcmpi(split[13],"magic") == 0 )
+ skill_db[i].skill_type = BF_MAGIC;
+ else if( strcmpi(split[13],"misc") == 0 )
+ skill_db[i].skill_type = BF_MISC;
+ else
+ skill_db[i].skill_type = 0;
+ skill_split_atoi(split[14],skill_db[i].blewcount);
+ safestrncpy(skill_db[i].name, split[15], sizeof(skill_db[i].name));
+ safestrncpy(skill_db[i].desc, split[16], sizeof(skill_db[i].desc));
- skill_split_atoi(split[1],skill_db[i].cast);
- skill_split_atoi(split[2],skill_db[i].delay);
- skill_split_atoi(split[3],skill_db[i].walkdelay);
- skill_split_atoi(split[4],skill_db[i].upkeep_time);
- skill_split_atoi(split[5],skill_db[i].upkeep_time2);
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ return true;
+}
- // load 'skill_unit_db.txt'
- sprintf(path, "%s/skill_unit_db.txt", db_path);
- fp=fopen(path,"r");
- if (fp==NULL) {
- ShowError("can't read %s\n", path);
- return 1;
- }
- k = 0;
- while (fgets(line, sizeof(line), fp))
- {
- char *split[50];
- if (line[0]=='/' && line[1]=='/')
- continue;
- j = skill_split_str(line,split,8);
- if ( j < 8 )
- continue;
+static bool skill_parse_row_requiredb(char* split[], int columns, int current)
+{// SkillID,HPCost,MaxHPTrigger,SPCost,HPRateCost,SPRateCost,ZenyCost,RequiredWeapons,RequiredAmmoTypes,RequiredAmmoAmount,RequiredState,SpiritSphereCost,RequiredItemID1,RequiredItemAmount1,RequiredItemID2,RequiredItemAmount2,RequiredItemID3,RequiredItemAmount3,RequiredItemID4,RequiredItemAmount4,RequiredItemID5,RequiredItemAmount5,RequiredItemID6,RequiredItemAmount6,RequiredItemID7,RequiredItemAmount7,RequiredItemID8,RequiredItemAmount8,RequiredItemID9,RequiredItemAmount9,RequiredItemID10,RequiredItemAmount10
+ char* p;
+ int j;
- i = atoi(split[0]);
- i = skill_get_index(i);
- if(i == 0) // invalid skill id
- continue;
- skill_db[i].unit_id[0] = strtol(split[1],NULL,16);
- skill_db[i].unit_id[1] = strtol(split[2],NULL,16);
- skill_split_atoi(split[3],skill_db[i].unit_layout_type);
- skill_split_atoi(split[4],skill_db[i].unit_range);
- skill_db[i].unit_interval = atoi(split[5]);
-
- if( strcmpi(split[6],"noenemy")==0 ) skill_db[i].unit_target=BCT_NOENEMY;
- else if( strcmpi(split[6],"friend")==0 ) skill_db[i].unit_target=BCT_NOENEMY;
- else if( strcmpi(split[6],"party")==0 ) skill_db[i].unit_target=BCT_PARTY;
- else if( strcmpi(split[6],"ally")==0 ) skill_db[i].unit_target=BCT_PARTY|BCT_GUILD;
- else if( strcmpi(split[6],"all")==0 ) skill_db[i].unit_target=BCT_ALL;
- else if( strcmpi(split[6],"enemy")==0 ) skill_db[i].unit_target=BCT_ENEMY;
- else if( strcmpi(split[6],"self")==0 ) skill_db[i].unit_target=BCT_SELF;
- else if( strcmpi(split[6],"noone")==0 ) skill_db[i].unit_target=BCT_NOONE;
- else skill_db[i].unit_target = strtol(split[6],NULL,16);
-
- skill_db[i].unit_flag = strtol(split[7],NULL,16);
-
- if (skill_db[i].unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy)
- skill_db[i].unit_target=BCT_NOENEMY;
-
- //By default, target just characters.
- skill_db[i].unit_target |= BL_CHAR;
- if (skill_db[i].unit_flag&UF_NOPC)
- skill_db[i].unit_target &= ~BL_PC;
- if (skill_db[i].unit_flag&UF_NOMOB)
- skill_db[i].unit_target &= ~BL_MOB;
- if (skill_db[i].unit_flag&UF_SKILL)
- skill_db[i].unit_target |= BL_SKILL;
- k++;
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
- skill_init_unit_layout();
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
- // load 'produce_db.txt'
- memset(skill_produce_db,0,sizeof(skill_produce_db));
- sprintf(path, "%s/produce_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n",path);
- return 1;
- }
- k = 0;
- while(fgets(line, sizeof(line), fp))
+ skill_split_atoi(split[1],skill_db[i].hp);
+ skill_split_atoi(split[2],skill_db[i].mhp);
+ skill_split_atoi(split[3],skill_db[i].sp);
+ skill_split_atoi(split[4],skill_db[i].hp_rate);
+ skill_split_atoi(split[5],skill_db[i].sp_rate);
+ skill_split_atoi(split[6],skill_db[i].zeny);
+
+ //FIXME: document this
+ p = split[7];
+ for( j = 0; j < 32; j++ )
{
- char* split[4 + MAX_PRODUCE_RESOURCE * 2];
- int x,y;
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(split,0,sizeof(split));
- j = skill_split_str(line,split,(4 + MAX_PRODUCE_RESOURCE * 2));
- if( j < 4 ) // at least base data needed
- continue;
- i=atoi(split[0]);
- if(i<=0) continue;
-
- skill_produce_db[k].nameid=i;
- skill_produce_db[k].itemlv=atoi(split[1]);
- skill_produce_db[k].req_skill=atoi(split[2]);
- skill_produce_db[k].req_skill_lv=atoi(split[3]);
-
- for(x=4,y=0; split[x] && split[x+1] && y<MAX_PRODUCE_RESOURCE; x+=2,y++){
- skill_produce_db[k].mat_id[y]=atoi(split[x]);
- skill_produce_db[k].mat_amount[y]=atoi(split[x+1]);
- }
- k++;
- if(k >= MAX_SKILL_PRODUCE_DB)
+ int l = atoi(p);
+ if( l == 99 ) // magic value?
{
- ShowError("Reached the max number of produce_db entries (%d), consider raising the value of MAX_SKILL_PRODUCE_DB and recompile.\n", MAX_SKILL_PRODUCE_DB);
+ skill_db[i].weapon = 0xffffffff;
break;
}
+ else
+ skill_db[i].weapon |= 1<<l;
+ p = strchr(p,':');
+ if(!p)
+ break;
+ p++;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,path);
-
- // load 'create_arrow_db.txt'
- memset(skill_arrow_db,0,sizeof(skill_arrow_db));
- sprintf(path, "%s/create_arrow_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
- }
- k = 0;
- while(fgets(line, sizeof(line), fp))
+
+ //FIXME: document this
+ p = split[8];
+ for( j = 0; j < 32; j++ )
{
- char* split[16];
- int x,y;
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(split,0,sizeof(split));
- j = skill_split_str(line,split,1+2*5);
- if( j < 3 ) // at least 1 entry
- continue;
- i=atoi(split[0]);
- if(i<=0)
- continue;
-
- skill_arrow_db[k].nameid=i;
-
- for(x=1,y=0;split[x] && split[x+1] && y<5;x+=2,y++){
- skill_arrow_db[k].cre_id[y]=atoi(split[x]);
- skill_arrow_db[k].cre_amount[y]=atoi(split[x+1]);
+ int l = atoi(p);
+ if( l == 99 ) // magic value?
+ {
+ skill_db[i].ammo = 0xffffffff;
+ break;
}
- k++;
- if(k >= MAX_SKILL_ARROW_DB)
+ else if( l ) // 0 not allowed?
+ skill_db[i].ammo |= 1<<l;
+ p = strchr(p,':');
+ if( !p )
break;
+ p++;
+ }
+ skill_split_atoi(split[9],skill_db[i].ammo_qty);
+
+ if( strcmpi(split[10],"hiding")==0 ) skill_db[i].state = ST_HIDING;
+ else if( strcmpi(split[10],"cloaking")==0 ) skill_db[i].state = ST_CLOAKING;
+ else if( strcmpi(split[10],"hidden")==0 ) skill_db[i].state = ST_HIDDEN;
+ else if( strcmpi(split[10],"riding")==0 ) skill_db[i].state = ST_RIDING;
+ else if( strcmpi(split[10],"falcon")==0 ) skill_db[i].state = ST_FALCON;
+ else if( strcmpi(split[10],"cart")==0 ) skill_db[i].state = ST_CART;
+ else if( strcmpi(split[10],"shield")==0 ) skill_db[i].state = ST_SHIELD;
+ else if( strcmpi(split[10],"sight")==0 ) skill_db[i].state = ST_SIGHT;
+ else if( strcmpi(split[10],"explosionspirits")==0 ) skill_db[i].state = ST_EXPLOSIONSPIRITS;
+ else if( strcmpi(split[10],"cartboost")==0 ) skill_db[i].state = ST_CARTBOOST;
+ else if( strcmpi(split[10],"recover_weight_rate")==0 ) skill_db[i].state = ST_RECOV_WEIGHT_RATE;
+ else if( strcmpi(split[10],"move_enable")==0 ) skill_db[i].state = ST_MOVE_ENABLE;
+ else if( strcmpi(split[10],"water")==0 ) skill_db[i].state = ST_WATER;
+ else skill_db[i].state = ST_NONE;
+
+ skill_split_atoi(split[11],skill_db[i].spiritball);
+ for( j = 0; j < 10; j++ ) {
+ skill_db[i].itemid[j] = atoi(split[12+ 2*j]);
+ skill_db[i].amount[j] = atoi(split[13+ 2*j]);
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,path);
- // load 'abra_db.txt'
- memset(skill_abra_db,0,sizeof(skill_abra_db));
- sprintf(path, "%s/abra_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
- }
- k = 0;
- while(fgets(line, sizeof(line), fp))
- {
- char *split[16];
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(split,0,sizeof(split));
- j = skill_split_str(line,split,4);
- if( j < 4 )
- continue;
- i=atoi(split[0]);
- if(i<=0)
- continue;
+ return true;
+}
- skill_abra_db[i].req_lv=atoi(split[2]);
- skill_abra_db[i].per=atoi(split[3]);
+static bool skill_parse_row_castdb(char* split[], int columns, int current)
+{// SkillID,CastingTime,AfterCastActDelay,AfterCastWalkDelay,Duration1,Duration2
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
+
+ skill_split_atoi(split[1],skill_db[i].cast);
+ skill_split_atoi(split[2],skill_db[i].delay);
+ skill_split_atoi(split[3],skill_db[i].walkdelay);
+ skill_split_atoi(split[4],skill_db[i].upkeep_time);
+ skill_split_atoi(split[5],skill_db[i].upkeep_time2);
- k++;
- if(k >= MAX_SKILL_ABRA_DB)
- break;
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",k,path);
+ return true;
+}
- // load 'skill_castnodex_db.txt'
- sprintf(path, "%s/skill_castnodex_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
- }
- while(fgets(line, sizeof(line), fp))
- {
- char *split[50];
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(split,0,sizeof(split));
- j = skill_split_str(line,split,3);
- if( j < 2 ) //3rd is optional
- continue;
- i = atoi(split[0]);
- i = skill_get_index(i);
- if(i == 0) // invalid skill id
- continue;
+static bool skill_parse_row_unitdb(char* split[], int columns, int current)
+{// ID,unit ID,unit ID 2,layout,range,interval,target,flag
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
+
+ skill_db[i].unit_id[0] = strtol(split[1],NULL,16);
+ skill_db[i].unit_id[1] = strtol(split[2],NULL,16);
+ skill_split_atoi(split[3],skill_db[i].unit_layout_type);
+ skill_split_atoi(split[4],skill_db[i].unit_range);
+ skill_db[i].unit_interval = atoi(split[5]);
+
+ if( strcmpi(split[6],"noenemy")==0 ) skill_db[i].unit_target = BCT_NOENEMY;
+ else if( strcmpi(split[6],"friend")==0 ) skill_db[i].unit_target = BCT_NOENEMY;
+ else if( strcmpi(split[6],"party")==0 ) skill_db[i].unit_target = BCT_PARTY;
+ else if( strcmpi(split[6],"ally")==0 ) skill_db[i].unit_target = BCT_PARTY|BCT_GUILD;
+ else if( strcmpi(split[6],"all")==0 ) skill_db[i].unit_target = BCT_ALL;
+ else if( strcmpi(split[6],"enemy")==0 ) skill_db[i].unit_target = BCT_ENEMY;
+ else if( strcmpi(split[6],"self")==0 ) skill_db[i].unit_target = BCT_SELF;
+ else if( strcmpi(split[6],"noone")==0 ) skill_db[i].unit_target = BCT_NOONE;
+ else skill_db[i].unit_target = strtol(split[6],NULL,16);
+
+ skill_db[i].unit_flag = strtol(split[7],NULL,16);
+
+ if (skill_db[i].unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy)
+ skill_db[i].unit_target = BCT_NOENEMY;
+
+ //By default, target just characters.
+ skill_db[i].unit_target |= BL_CHAR;
+ if (skill_db[i].unit_flag&UF_NOPC)
+ skill_db[i].unit_target &= ~BL_PC;
+ if (skill_db[i].unit_flag&UF_NOMOB)
+ skill_db[i].unit_target &= ~BL_MOB;
+ if (skill_db[i].unit_flag&UF_SKILL)
+ skill_db[i].unit_target |= BL_SKILL;
- skill_split_atoi(split[1],skill_db[i].castnodex);
- if (!split[2])
- continue;
- skill_split_atoi(split[2],skill_db[i].delaynodex);
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ return true;
+}
- // load 'skill_nocast_db.txt'
- sprintf(path, "%s/skill_nocast_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+static bool skill_parse_row_producedb(char* split[], int columns, int current)
+{// ProduceItemID,ItemLV,RequireSkill,RequireSkillLv,MaterialID1,MaterialAmount1,......
+ int x,y;
+
+ int i = atoi(split[0]);
+ if( !i )
+ return false;
+ if( current == MAX_SKILL_PRODUCE_DB )
+ return false;
+
+ skill_produce_db[current].nameid = i;
+ skill_produce_db[current].itemlv = atoi(split[1]);
+ skill_produce_db[current].req_skill = atoi(split[2]);
+ skill_produce_db[current].req_skill_lv = atoi(split[3]);
+
+ for( x = 4, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_PRODUCE_RESOURCE; x += 2, y++ )
+ {
+ skill_produce_db[current].mat_id[y] = atoi(split[x]);
+ skill_produce_db[current].mat_amount[y] = atoi(split[x+1]);
}
- k = 0;
- while(fgets(line, sizeof(line), fp))
+
+ if( current == MAX_SKILL_PRODUCE_DB-1 )
+ ShowWarning("Reached the max number of produce_db entries (%d), consider raising the value of MAX_SKILL_PRODUCE_DB and recompile.\n", MAX_SKILL_PRODUCE_DB);
+
+ return true;
+}
+
+static bool skill_parse_row_createarrowdb(char* split[], int columns, int current)
+{// SourceID,MakeID1,MakeAmount1,...,MakeID5,MakeAmount5
+ int x,y;
+
+ int i = atoi(split[0]);
+ if( !i )
+ return false;
+ if( current == MAX_SKILL_ARROW_DB )
+ return false;
+
+ skill_arrow_db[current].nameid = i;
+
+ for( x = 1, y = 0; x+1 < columns && split[x] && split[x+1] && y < 5; x += 2, y++ )
{
- char *split[16];
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(split,0,sizeof(split));
- j = skill_split_str(line,split,2);
- if( j < 2 )
- continue;
- i = atoi(split[0]);
- i = skill_get_index(i);
- if(i == 0) // invalid skill id
- continue;
- skill_db[i].nocast|=atoi(split[1]);
- k++;
+ skill_arrow_db[current].cre_id[y] = atoi(split[x]);
+ skill_arrow_db[current].cre_amount[y] = atoi(split[x+1]);
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ //TODO?: add capacity warning here
+
+ return true;
+}
+
+static bool skill_parse_row_abradb(char* split[], int columns, int current)
+{// SkillID,DummyName,RequiredHocusPocusLevel,Rate
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i )
+ return false;
+ if( current == MAX_SKILL_ABRA_DB )
+ return false;
+
+ skill_abra_db[i].req_lv = atoi(split[2]);
+ skill_abra_db[i].per = atoi(split[3]);
+
+ //TODO?: add capacity warning here
+
+ return true;
+}
+
+static bool skill_parse_row_castnodexdb(char* split[], int columns, int current)
+{// Skill id,Cast,Delay (optional)
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
+
+ skill_split_atoi(split[1],skill_db[i].castnodex);
+ if( !split[2] ) // optional column
+ return false;
+ skill_split_atoi(split[2],skill_db[i].delaynodex);
+
+ return true;
+}
+
+static bool skill_parse_row_nocastdb(char* split[], int columns, int current)
+{// SkillID,Flag
+ int i = atoi(split[0]);
+ i = skill_get_index(i);
+ if( !i ) // invalid skill id
+ return false;
+
+ skill_db[i].nocast |= atoi(split[1]);
+
+ return true;
+}
+
+int skill_readdb(void)
+{
+ // init skill db structures
+ memset(skill_db,0,sizeof(skill_db));
+ memset(skill_produce_db,0,sizeof(skill_produce_db));
+ memset(skill_arrow_db,0,sizeof(skill_arrow_db));
+ memset(skill_abra_db,0,sizeof(skill_abra_db));
+
+ // load skill databases
+ skill_read_csvdb(db_path, "skill_db.txt", 17, skill_parse_row_skilldb);
+ safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name));
+ safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc));
+ skill_read_csvdb(db_path, "skill_require_db.txt", 17, skill_parse_row_requiredb);
+ skill_read_csvdb(db_path, "skill_cast_db.txt", 6, skill_parse_row_castdb);
+ skill_read_csvdb(db_path, "skill_unit_db.txt", 8, skill_parse_row_unitdb);
+ skill_init_unit_layout();
+ skill_read_csvdb(db_path, "produce_db.txt", 4, skill_parse_row_producedb);
+ skill_read_csvdb(db_path, "create_arrow_db.txt", 1+2, skill_parse_row_createarrowdb);
+ skill_read_csvdb(db_path, "abra_db.txt", 4, skill_parse_row_abradb);
+ skill_read_csvdb(db_path, "skill_castnodex_db.txt", 2, skill_parse_row_castnodexdb);
+ skill_read_csvdb(db_path, "skill_nocast_db.txt", 2, skill_parse_row_nocastdb);
+
return 0;
}
diff --git a/src/map/skill.h b/src/map/skill.h
index c78607b36..5ddd5b27c 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -61,7 +61,7 @@
// スキルデ?タベ?ス
struct s_skill_db {
- char name[20];
+ char name[NAME_LENGTH];
char desc[40];
int range[MAX_SKILL_LEVEL],hit,inf,element[MAX_SKILL_LEVEL],nk,splash[MAX_SKILL_LEVEL],max;
int num[MAX_SKILL_LEVEL];