From 2f254cd153ba353488bb80eb3b217592e32c54cc Mon Sep 17 00:00:00 2001 From: ultramage Date: Mon, 5 Nov 2007 14:45:13 +0000 Subject: 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 --- Changelog-Trunk.txt | 5 + src/map/atcommand.c | 10 +- src/map/battle.c | 6 +- src/map/clif.c | 10 +- src/map/skill.c | 696 ++++++++++++++++++++++++---------------------------- src/map/skill.h | 2 +- 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<= 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_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<= MAX_SKILL_ARROW_DB) + else if( l ) // 0 not allowed? + skill_db[i].ammo |= 1<= 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]; -- cgit v1.2.3-60-g2f50