diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/mob.c | 466 |
1 files changed, 248 insertions, 218 deletions
diff --git a/src/map/mob.c b/src/map/mob.c index 22777a70a..9e734926a 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -3787,41 +3787,38 @@ static int mob_read_randommonster(void) } /*========================================== - * mob_skill_db.txt reading + * processes one mob_skill_db entry + * @param last_mob_id ensures that only one error message per mob id is printed *------------------------------------------*/ -static int mob_readskilldb(void) +static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, int* last_mob_id) { - FILE *fp; - char line[1024]; - int i,tmp, count; - - const struct { + static const struct { char str[32]; enum MobSkillState id; } cond1[] = { - { "always", MSC_ALWAYS }, - { "myhpltmaxrate", MSC_MYHPLTMAXRATE }, - { "myhpinrate", MSC_MYHPINRATE }, - { "friendhpltmaxrate",MSC_FRIENDHPLTMAXRATE }, - { "friendhpinrate", MSC_FRIENDHPINRATE }, - { "mystatuson", MSC_MYSTATUSON }, - { "mystatusoff", MSC_MYSTATUSOFF }, - { "friendstatuson", MSC_FRIENDSTATUSON }, - { "friendstatusoff", MSC_FRIENDSTATUSOFF }, - { "attackpcgt", MSC_ATTACKPCGT }, - { "attackpcge", MSC_ATTACKPCGE }, - { "slavelt", MSC_SLAVELT }, - { "slavele", MSC_SLAVELE }, - { "closedattacked", MSC_CLOSEDATTACKED }, - { "longrangeattacked",MSC_LONGRANGEATTACKED }, - { "skillused", MSC_SKILLUSED }, - { "afterskill", MSC_AFTERSKILL }, - { "casttargeted", MSC_CASTTARGETED }, - { "rudeattacked", MSC_RUDEATTACKED }, - { "masterhpltmaxrate",MSC_MASTERHPLTMAXRATE }, - { "masterattacked", MSC_MASTERATTACKED }, - { "alchemist", MSC_ALCHEMIST }, - { "onspawn", MSC_SPAWN}, + { "always", MSC_ALWAYS }, + { "myhpltmaxrate", MSC_MYHPLTMAXRATE }, + { "myhpinrate", MSC_MYHPINRATE }, + { "friendhpltmaxrate", MSC_FRIENDHPLTMAXRATE }, + { "friendhpinrate", MSC_FRIENDHPINRATE }, + { "mystatuson", MSC_MYSTATUSON }, + { "mystatusoff", MSC_MYSTATUSOFF }, + { "friendstatuson", MSC_FRIENDSTATUSON }, + { "friendstatusoff", MSC_FRIENDSTATUSOFF }, + { "attackpcgt", MSC_ATTACKPCGT }, + { "attackpcge", MSC_ATTACKPCGE }, + { "slavelt", MSC_SLAVELT }, + { "slavele", MSC_SLAVELE }, + { "closedattacked", MSC_CLOSEDATTACKED }, + { "longrangeattacked", MSC_LONGRANGEATTACKED }, + { "skillused", MSC_SKILLUSED }, + { "afterskill", MSC_AFTERSKILL }, + { "casttargeted", MSC_CASTTARGETED }, + { "rudeattacked", MSC_RUDEATTACKED }, + { "masterhpltmaxrate", MSC_MASTERHPLTMAXRATE }, + { "masterattacked", MSC_MASTERATTACKED }, + { "alchemist", MSC_ALCHEMIST }, + { "onspawn", MSC_SPAWN }, }, cond2[] ={ { "anybad", -1 }, { "stone", SC_STONE }, @@ -3863,218 +3860,251 @@ static int mob_readskilldb(void) { "around", MST_AROUND }, }; - int x; - const char* filename[] = { "mob_skill_db.txt","mob_skill_db2.txt" }; + struct mob_skill *ms, gms; + int mob_id; + int i, j, tmp; - if( battle_config.mob_skill_rate == 0 ) { - ShowStatus("Mob skill use disabled. Not reading mob skills.\n"); - return 0; - } + mob_id = atoi(str[0]); - for( x = 0; x < ARRAYLENGTH(filename); ++x ) + if (mob_id > 0 && mob_db(mob_id) == mob_dummy) { - int last_mob_id = 0; - count = 0; - sprintf(line, "%s/%s", db_path, filename[x]); - fp=fopen(line,"r"); - if(fp==NULL){ - if(x==0) - ShowError("can't read %s\n",line); - continue; + if (mob_id != *last_mob_id) { + ShowError("mob_skill: Non existant Mob id %d at %s, line %d\n", mob_id, source, line); + *last_mob_id = mob_id; } - while(fgets(line, sizeof(line), fp)) + return false; + } + if( strcmp(str[1],"clear")==0 ){ + if (mob_id < 0) + return false; + memset(mob_db_data[mob_id]->skill,0,sizeof(struct mob_skill)); + mob_db_data[mob_id]->maxskill=0; + return true; + } + + if (mob_id < 0) + { //Prepare global skill. [Skotlex] + memset(&gms, 0, sizeof (struct mob_skill)); + ms = &gms; + } else { + ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob_db_data[mob_id]->skill[i])->skill_id == 0 ); + if( i == MAX_MOBSKILL ) { - char *sp[20],*p; - int mob_id; - struct mob_skill *ms, gms; - int j=0; + if (mob_id != *last_mob_id) { + ShowError("mob_skill: readdb: too many skills! Line %d in %d[%s]\n", line, mob_id, mob_db_data[mob_id]->sprite); + *last_mob_id = mob_id; + } + return false; + } + } - count++; - if(line[0] == '/' && line[1] == '/') - continue; + //State + ARR_FIND( 0, ARRAYLENGTH(state), j, strcmp(str[2],state[j].str) == 0 ); + if( j < ARRAYLENGTH(state) ) + ms->state = state[j].id; + else { + ShowWarning("mob_skill: Unrecognized state %s at %s, line %d\n", str[2], source, line); + ms->state = MSS_ANY; + } - memset(sp,0,sizeof(sp)); - for(i=0,p=line;i<18 && p;i++){ - sp[i]=p; - if((p=strchr(p,','))!=NULL) - *p++=0; - } - if(i == 0 || (mob_id=atoi(sp[0]))== 0) - continue; - if(i < 18) { - ShowError("mob_skill: Insufficient number of fields for skill at %s, line %d\n", filename[x], count); + //Skill ID + j=atoi(str[3]); + if (j<=0 || j>MAX_SKILL_DB) //fixed Lupus + { + if (mob_id < 0) + ShowError("Invalid Skill ID (%d) for all mobs\n", j); + else + ShowError("Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite); + return false; + } + ms->skill_id=j; + + //Skill lvl + j= atoi(str[4])<=0 ? 1 : atoi(str[4]); + ms->skill_lv= j>battle_config.mob_max_skilllvl ? battle_config.mob_max_skilllvl : j; //we strip max skill level + + //Apply battle_config modifiers to rate (permillage) and delay [Skotlex] + tmp = atoi(str[5]); + if (battle_config.mob_skill_rate != 100) + tmp = tmp*battle_config.mob_skill_rate/100; + if (tmp > 10000) + ms->permillage= 10000; + else + ms->permillage= tmp; + ms->casttime=atoi(str[6]); + ms->delay=atoi(str[7]); + if (battle_config.mob_skill_delay != 100) + ms->delay = ms->delay*battle_config.mob_skill_delay/100; + if (ms->delay < 0) //time overflow? + ms->delay = INT_MAX; + ms->cancel=atoi(str[8]); + if( strcmp(str[8],"yes")==0 ) ms->cancel=1; + + //Target + ARR_FIND( 0, ARRAYLENGTH(target), j, strcmp(str[9],target[j].str) == 0 ); + if( j < ARRAYLENGTH(target) ) + ms->target = target[j].id; + else { + ShowWarning("mob_skill: Unrecognized target %s at %s, line %d\n", str[9], source, line); + ms->target = MST_TARGET; + } + + //Check that the target condition is right for the skill type. [Skotlex] + if (skill_get_casttype(ms->skill_id) == CAST_GROUND) + { //Ground skill. + if (ms->target > MST_AROUND) + { + ShowWarning("Wrong mob skill target for ground skill %d (%s) for %s.\n", + ms->skill_id, skill_get_name(ms->skill_id), + mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); + ms->target = MST_TARGET; + } + } else if (ms->target > MST_MASTER) { + ShowWarning("Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.", + ms->skill_id, skill_get_name(ms->skill_id), + mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); + ms->target = MST_TARGET; + } + + //Cond1 + ARR_FIND( 0, ARRAYLENGTH(cond1), j, strcmp(str[10],cond1[j].str) == 0 ); + if( j < ARRAYLENGTH(cond1) ) + ms->cond1 = cond1[j].id; + else { + ShowWarning("mob_skill: Unrecognized condition 1 %s at %s, line %d\n", str[10], source, line); + ms->cond1 = -1; + } + + //Cond2 + // numeric value + ms->cond2 = atoi(str[11]); + // or special constant + ARR_FIND( 0, ARRAYLENGTH(cond2), j, strcmp(str[11],cond2[j].str) == 0 ); + if( j < ARRAYLENGTH(cond2) ) + ms->cond2 = cond2[j].id; + + ms->val[0]=(int)strtol(str[12],NULL,0); + ms->val[1]=(int)strtol(str[13],NULL,0); + ms->val[2]=(int)strtol(str[14],NULL,0); + ms->val[3]=(int)strtol(str[15],NULL,0); + ms->val[4]=(int)strtol(str[16],NULL,0); + + if(ms->skill_id == NPC_EMOTION && mob_id>0 && + ms->val[1] == mob_db(mob_id)->status.mode) + { + ms->val[1] = 0; + ms->val[4] = 1; //request to return mode to normal. + } + if(ms->skill_id == NPC_EMOTION_ON && mob_id>0 && ms->val[1]) + { //Adds a mode to the mob. + //Remove aggressive mode when the new mob type is passive. + if (!(ms->val[1]&MD_AGGRESSIVE)) + ms->val[3]|=MD_AGGRESSIVE; + ms->val[2]|= ms->val[1]; //Add the new mode. + ms->val[1] = 0; //Do not "set" it. + } + + if(str[17] != NULL && strlen(str[17])>2) + ms->emotion=atoi(str[17]); + else + ms->emotion=-1; + if (mob_id < 0) + { //Set this skill to ALL mobs. [Skotlex] + mob_id *= -1; + for (i = 1; i < MAX_MOB_DB; i++) + { + if (mob_db_data[i] == NULL) continue; - } - if (mob_id > 0 && mob_db(mob_id) == mob_dummy) + if (mob_db_data[i]->status.mode&MD_BOSS) { - if (mob_id != last_mob_id) { - ShowError("mob_skill: Non existant Mob id %d at %s, line %d\n", mob_id, filename[x], count); - last_mob_id = mob_id; - } - continue; - } - if( strcmp(sp[1],"clear")==0 ){ - if (mob_id < 0) + if (!(mob_id&2)) //Skill not for bosses continue; - memset(mob_db_data[mob_id]->skill,0,sizeof(struct mob_skill)); - mob_db_data[mob_id]->maxskill=0; + } else + if (!(mob_id&1)) //Skill not for normal enemies. + continue; + + ARR_FIND( 0, MAX_MOBSKILL, j, mob_db_data[i]->skill[j].skill_id == 0 ); + if(j==MAX_MOBSKILL) continue; - } - if (mob_id < 0) - { //Prepare global skill. [Skotlex] - memset(&gms, 0, sizeof (struct mob_skill)); - ms = &gms; - } else { - ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob_db_data[mob_id]->skill[i])->skill_id == 0 ); - if( i == MAX_MOBSKILL ) { - if (mob_id != last_mob_id) { - ShowError("mob_skill: readdb: too many skills! Line %d in %d[%s]\n", count,mob_id,mob_db_data[mob_id]->sprite); - last_mob_id = mob_id; - } - continue; - } - } + memcpy (&mob_db_data[i]->skill[j], ms, sizeof(struct mob_skill)); + mob_db_data[i]->maxskill=j+1; + } + } else //Skill set on a single mob. + mob_db_data[mob_id]->maxskill=i+1; - //State - ARR_FIND( 0, ARRAYLENGTH(state), j, strcmp(sp[2],state[j].str) == 0 ); - if( j < ARRAYLENGTH(state) ) - ms->state = state[j].id; - else { - ShowWarning("mob_skill: Unrecognized state %s at %s, line %d\n", sp[2], filename[x], count); - ms->state = MSS_ANY; - } + return true; +} - //Skill ID - j=atoi(sp[3]); - if (j<=0 || j>MAX_SKILL_DB) //fixed Lupus - { - if (mob_id < 0) - ShowError("Invalid Skill ID (%d) for all mobs\n", j); - else - ShowError("Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite); - continue; - } - ms->skill_id=j; - - //Skill lvl - j= atoi(sp[4])<=0 ? 1 : atoi(sp[4]); - ms->skill_lv= j>battle_config.mob_max_skilllvl ? battle_config.mob_max_skilllvl : j; //we strip max skill level - - //Apply battle_config modifiers to rate (permillage) and delay [Skotlex] - tmp = atoi(sp[5]); - if (battle_config.mob_skill_rate != 100) - tmp = tmp*battle_config.mob_skill_rate/100; - if (tmp > 10000) - ms->permillage= 10000; - else - ms->permillage= tmp; - ms->casttime=atoi(sp[6]); - ms->delay=atoi(sp[7]); - if (battle_config.mob_skill_delay != 100) - ms->delay = ms->delay*battle_config.mob_skill_delay/100; - if (ms->delay < 0) //time overflow? - ms->delay = INT_MAX; - ms->cancel=atoi(sp[8]); - if( strcmp(sp[8],"yes")==0 ) ms->cancel=1; - - //Target - ARR_FIND( 0, ARRAYLENGTH(target), j, strcmp(sp[9],target[j].str) == 0 ); - if( j < ARRAYLENGTH(target) ) - ms->target = target[j].id; - else { - ShowWarning("mob_skill: Unrecognized target %s at %s, line %d\n", sp[9], filename[x], count); - ms->target = MST_TARGET; - } +/*========================================== + * mob_skill_db.txt reading + *------------------------------------------*/ +static int mob_readskilldb(void) +{ + const char* filename[] = { "mob_skill_db.txt", "mob_skill_db2.txt" }; + int fi; - //Check that the target condition is right for the skill type. [Skotlex] - if (skill_get_casttype(ms->skill_id) == CAST_GROUND) - { //Ground skill. - if (ms->target > MST_AROUND) - { - ShowWarning("Wrong mob skill target for ground skill %d (%s) for %s.\n", - ms->skill_id, skill_get_name(ms->skill_id), - mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); - ms->target = MST_TARGET; - } - } else if (ms->target > MST_MASTER) { - ShowWarning("Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.", - ms->skill_id, skill_get_name(ms->skill_id), - mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); - ms->target = MST_TARGET; - } + if( battle_config.mob_skill_rate == 0 ) + { + ShowStatus("Mob skill use disabled. Not reading mob skills.\n"); + return 0; + } - //Cond1 - ARR_FIND( 0, ARRAYLENGTH(cond1), j, strcmp(sp[10],cond1[j].str) == 0 ); - if( j < ARRAYLENGTH(cond1) ) - ms->cond1 = cond1[j].id; - else { - ShowWarning("mob_skill: Unrecognized condition 1 %s at %s, line %d\n", sp[10], filename[x], count); - ms->cond1 = -1; - } + for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) + { + uint32 lines = 0, count = 0; + char line[1024]; + int i; + int tmp = 0; - //Cond2 - // numeric value - ms->cond2 = atoi(sp[11]); - // or special constant - ARR_FIND( 0, ARRAYLENGTH(cond2), j, strcmp(sp[11],cond2[j].str) == 0 ); - if( j < ARRAYLENGTH(cond2) ) - ms->cond2 = cond2[j].id; - - ms->val[0]=(int)strtol(sp[12],NULL,0); - ms->val[1]=(int)strtol(sp[13],NULL,0); - ms->val[2]=(int)strtol(sp[14],NULL,0); - ms->val[3]=(int)strtol(sp[15],NULL,0); - ms->val[4]=(int)strtol(sp[16],NULL,0); - - if(ms->skill_id == NPC_EMOTION && mob_id>0 && - ms->val[1] == mob_db(mob_id)->status.mode) + char path[256]; + FILE *fp; + + sprintf(path, "%s/%s", db_path, filename[fi]); + fp = fopen(path, "r"); + if( fp == NULL ) + { + ShowWarning("mob_readskilldb: File not found \"%s\", skipping.\n", path); + continue; + } + + // process rows one by one + while(fgets(line, sizeof(line), fp)) + { + char *str[20], *p, *np; + int j=0; + + lines++; + if(line[0] == '/' && line[1] == '/') + continue; + memset(str, 0, sizeof(str)); + + p = line; + while( ISSPACE(*p) ) + ++p; + if( *p == '\0' ) + continue;// empty line + for(i = 0; i < 18; i++) { - ms->val[1] = 0; - ms->val[4] = 1; //request to return mode to normal. + str[i] = p; + if((np = strchr(p, ',')) != NULL) { + *np = '\0'; p = np + 1; + } } - if(ms->skill_id == NPC_EMOTION_ON && mob_id>0 && ms->val[1]) - { //Adds a mode to the mob. - //Remove aggressive mode when the new mob type is passive. - if (!(ms->val[1]&MD_AGGRESSIVE)) - ms->val[3]|=MD_AGGRESSIVE; - ms->val[2]|= ms->val[1]; //Add the new mode. - ms->val[1] = 0; //Do not "set" it. + + if( i < 18 ) + { + ShowError("mob_readskilldb: Insufficient number of fields for skill at %s, line %d\n", filename[fi], lines); + continue; } - if(sp[17] != NULL && strlen(sp[17])>2) - ms->emotion=atoi(sp[17]); - else - ms->emotion=-1; - if (mob_id < 0) - { //Set this skill to ALL mobs. [Skotlex] - mob_id *= -1; - for (i = 1; i < MAX_MOB_DB; i++) - { - if (mob_db_data[i] == NULL) - continue; - if (mob_db_data[i]->status.mode&MD_BOSS) - { - if (!(mob_id&2)) //Skill not for bosses - continue; - } else - if (!(mob_id&1)) //Skill not for normal enemies. - continue; - - for(j=0;j<MAX_MOBSKILL;j++) - if( mob_db_data[i]->skill[j].skill_id == 0) - break; - if(j==MAX_MOBSKILL) - continue; + if( !mob_parse_row_mobskilldb(str, path, lines, &tmp) ) + continue; - memcpy (&mob_db_data[i]->skill[j], ms, sizeof(struct mob_skill)); - mob_db_data[i]->maxskill=j+1; - } - } else //Skill set on a single mob. - mob_db_data[mob_id]->maxskill=i+1; + count++; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",filename[x]); + ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", filename[fi]); } return 0; } |