summaryrefslogtreecommitdiff
path: root/src/map/mob.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/mob.c')
-rw-r--r--src/map/mob.c430
1 files changed, 161 insertions, 269 deletions
diff --git a/src/map/mob.c b/src/map/mob.c
index 413d88f26..d67b470af 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -82,7 +82,6 @@ const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 };
*------------------------------------------*/
static int mob_makedummymobdb(int);
static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr data);
-int mobskill_use(struct mob_data *md,unsigned int tick,int event);
int mob_skillid2skillidx(int class_,int skillid);
/*==========================================
@@ -276,7 +275,7 @@ int mob_get_random_id(int type, int flag, int lv)
(flag&8 && mob->spawn[0].qty < 1)
) && (i++) < MAX_MOB_DB);
- if(i >= MAX_MOB_DB)
+ if(i >= MAX_MOB_DB) // no suitable monster found, use fallback for given list
class_ = mob_db_data[0]->summonper[type];
return class_;
}
@@ -449,7 +448,7 @@ int mob_once_spawn(struct map_session_data* sd, int m, short x, short y, const c
if (class_ < 0 && battle_config.dead_branch_active)
//Behold Aegis's masterful decisions yet again...
//"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
- sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE, 0, 60000);
+ sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000);
}
return (md)?md->bl.id : 0; // id of last spawned mob
@@ -547,7 +546,7 @@ static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr dat
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0); //Remove guardian.
+ unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
}
return 0;
}
@@ -795,7 +794,7 @@ int mob_setdelayspawn(struct mob_data *md)
unsigned int spawntime;
if (!md->spawn) //Doesn't has respawn data!
- return unit_free(&md->bl,1);
+ return unit_free(&md->bl,CLR_DEAD);
spawntime = md->spawn->delay1; //Base respawn time
if (md->spawn->delay2) //random variance
@@ -826,7 +825,7 @@ int mob_spawn (struct mob_data *md)
md->last_thinktime = tick;
if (md->bl.prev != NULL)
- unit_remove_map(&md->bl,2);
+ unit_remove_map(&md->bl,CLR_RESPAWN);
else
if (md->spawn && md->class_ != md->spawn->class_)
{
@@ -1121,7 +1120,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
md->master_dist > MAX_MINCHASE
){
md->master_dist = 0;
- unit_warp(&md->bl,bl->m,bl->x,bl->y,3);
+ unit_warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT);
return 1;
}
@@ -1761,7 +1760,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr data)
}
//for Alchemist CANNIBALIZE [Lupus]
md->deletetimer = INVALID_TIMER;
- unit_free(bl, 3);
+ unit_free(bl, CLR_TELEPORT);
}
return 0;
}
@@ -1805,7 +1804,7 @@ int mob_respawn(int tid, unsigned int tick, int id, intptr data)
void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
{
- int char_id = 0, flag = 0;
+ int char_id = 0, flag = MDLF_NORMAL;
if( damage < 0 )
return; //Do nothing for absorbed damage.
@@ -1827,7 +1826,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
case BL_HOM:
{
struct homun_data *hd = (TBL_HOM*)src;
- flag = 1;
+ flag = MDLF_HOMUN;
if( hd->master )
char_id = hd->master->status.char_id;
if( damage )
@@ -1846,7 +1845,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
case BL_PET:
{
struct pet_data *pd = (TBL_PET*)src;
- flag = 2;
+ flag = MDLF_PET;
if( pd->msd )
{
char_id = pd->msd->status.char_id;
@@ -1960,9 +1959,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
unsigned int base_exp,job_exp;
} pt[DAMAGELOG_SIZE];
int i,temp,count,pnum=0,m=md->bl.m;
+ int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are elligible for exp distribution
unsigned int mvp_damage, tick = gettick();
- unsigned short flaghom = 1; // [Zephyrus] Does the mob only received damage from homunculus?
- bool rebirth;
+ bool rebirth, homkillonly;
status = &md->status;
@@ -2022,9 +2021,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
count++; //Only logged into same map chars are counted for the total.
if (pc_isdead(tsd))
continue; // skip dead players
- if(md->dmglog[i].flag == 1 && !merc_is_hom_active(tsd->hd))
+ if(md->dmglog[i].flag == MDLF_HOMUN && !merc_is_hom_active(tsd->hd))
continue; // skip homunc's share if inactive
- if( md->dmglog[i].flag == 2 && (!tsd->status.pet_id || !tsd->pd) )
+ if( md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd) )
continue; // skip pet's share if inactive
if(md->dmglog[i].dmg > mvp_damage)
@@ -2037,10 +2036,17 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
tmpsd[i] = tsd; // record as valid damage-log entry
- if(!md->dmglog[i].flag == 1 && flaghom)
- flaghom = 0; // Damage received from other Types != Homunculus
+ switch( md->dmglog[i].flag )
+ {
+ case MDLF_NORMAL: dmgbltypes|= BL_PC; break;
+ case MDLF_HOMUN: dmgbltypes|= BL_HOM; break;
+ case MDLF_PET: dmgbltypes|= BL_PET; break;
+ }
}
+ // determines, if the monster was killed by homunculus' damage only
+ homkillonly = (bool)( ( dmgbltypes&BL_HOM ) && !( dmgbltypes&~BL_HOM ) );
+
if(!battle_config.exp_calc_type && count > 1)
{ //Apply first-attacker 200% exp share bonus
//TODO: Determine if this should go before calculating the MVP player instead of after.
@@ -2065,9 +2071,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
temp = status_get_class(&md->bl);
if(sd->sc.data[SC_MIRACLE]) i = 2; //All mobs are Star Targets
else
- ARR_FIND(0, 3, i, temp == sd->hate_mob[i] &&
+ ARR_FIND(0, MAX_PC_FEELHATE, i, temp == sd->hate_mob[i] &&
(battle_config.allow_skill_without_day || sg_info[i].day_func()));
- if(i<3 && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
+ if(i<MAX_PC_FEELHATE && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
bonus += (i==2?20:10)*temp;
}
if(battle_config.mobs_level_up && md->level > md->db->lv) // [Valaris]
@@ -2103,7 +2109,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
else if(md->special_state.size==2)
per *=2.;
- if( md->dmglog[i].flag == 2 )
+ if( md->dmglog[i].flag == MDLF_PET )
per *= battle_config.pet_attack_exp_rate/100.;
if(battle_config.zeny_from_mobs && md->level) {
@@ -2118,12 +2124,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
else
base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].bexp/100., 1, UINT_MAX);
- if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == 1) //Homun earned job-exp is always lost.
+ if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost.
job_exp = 0;
else
job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].jexp/100., 1, UINT_MAX);
- if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == 1) //Homun-done damage (flag 1) is not given to party
+ if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == MDLF_HOMUN) //Homun-done damage (flag 1) is not given to party
{
int j;
for(j=0;j<pnum && pt[j].id!=temp;j++); //Locate party.
@@ -2155,11 +2161,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
}
if(flag) {
- if(base_exp && md->dmglog[i].flag == 1) //tmpsd[i] is null if it has no homunc.
+ if(base_exp && md->dmglog[i].flag == MDLF_HOMUN) //tmpsd[i] is null if it has no homunc.
merc_hom_gainexp(tmpsd[i]->hd, base_exp);
if(base_exp || job_exp)
{
- if( md->dmglog[i].flag != 2 || battle_config.pet_attack_exp_to_master )
+ if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master )
pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false);
}
if(zeny) // zeny from mobs [Valaris]
@@ -2241,13 +2247,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
// Announce first, or else ditem will be freed. [Lance]
// By popular demand, use base drop rate for autoloot code. [Skotlex]
- mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, flaghom);
+ mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly);
}
// Ore Discovery [Celest]
if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rand()%10000) {
ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE), 1);
- mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, 0);
+ mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly);
}
if(sd) {
@@ -2273,7 +2279,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
if (rand()%10000 >= drop_rate)
continue;
itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb_searchrandomid(sd->add_drop[i].group);
- mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, 0);
+ mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, homkillonly);
}
}
@@ -2289,7 +2295,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
// process items looted by the mob
if(md->lootitem) {
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
}
if (dlist->item) //There are drop items.
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
@@ -2305,7 +2311,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
dlist->item = NULL;
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
}
@@ -2406,12 +2412,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
{
if( sd && battle_config.mob_npc_event_type )
{
- pc_setglobalreg(sd,"killerrid",sd->bl.id);
+ pc_setparam(sd, SP_KILLERRID, sd->bl.id);
npc_event(sd,md->npc_event,0);
}
else if( mvp_sd )
{
- pc_setglobalreg(mvp_sd,"killerrid",sd?sd->bl.id:0);
+ pc_setparam(mvp_sd, SP_KILLERRID, sd?sd->bl.id:0);
npc_event(mvp_sd,md->npc_event,0);
}
else
@@ -2419,7 +2425,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
else if( mvp_sd && !md->state.npc_killmonster )
{
- pc_setglobalreg(mvp_sd,"killedrid",md->class_);
+ pc_setparam(mvp_sd, SP_KILLEDRID, md->class_);
npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance]
}
@@ -2491,7 +2497,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0); //Remove guardian.
+ unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
}
return 0;
}
@@ -2505,7 +2511,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0);
+ unit_free(&md->bl,CLR_OUTSIGHT);
return 0;
}
@@ -2631,7 +2637,7 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap)
return 0;
map_search_freecell(master, 0, &x, &y, range, range, 0);
- unit_warp(&md->bl, master->m, x, y,2);
+ unit_warp(&md->bl, master->m, x, y,CLR_RESPAWN);
return 1;
}
@@ -3409,9 +3415,7 @@ static bool mob_parse_dbrow(char** str)
double exp, maxhp;
struct mob_data data;
- class_ = str[0] ? atoi(str[0]) : 0;
- if (class_ == 0)
- return false; //Leave blank lines alone... [Skotlex]
+ class_ = atoi(str[0]);
if (class_ <= 1000 || class_ > MAX_MOB_DB) {
ShowWarning("Mob with ID: %d not loaded. ID must be in range [%d-%d]\n", class_, 1000, MAX_MOB_DB);
@@ -3552,7 +3556,7 @@ static bool mob_parse_dbrow(char** str)
//calculate and store Max available drop chance of the MVP item
if (db->mvpitem[i].p) {
id = itemdb_search(db->mvpitem[i].nameid);
- if (id->maxchance == 10000 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
+ if (id->maxchance == -1 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
//item has bigger drop chance or sold in shops
id->maxchance = db->mvpitem[i].p/10 + 1; //reduce MVP drop info to not spoil common drop rate
}
@@ -3585,6 +3589,7 @@ static bool mob_parse_dbrow(char** str)
ratemax = battle_config.item_drop_heal_max;
break;
case IT_USABLE:
+ case IT_CASH:
rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use;
ratemin = battle_config.item_drop_use_min;
ratemax = battle_config.item_drop_use_max;
@@ -3613,7 +3618,7 @@ static bool mob_parse_dbrow(char** str)
if( db->dropitem[i].p && (class_ < 1324 || class_ > 1363) && (class_ < 1938 || class_ > 1946) )
{ //Skip treasure chests.
id = itemdb_search(db->dropitem[i].nameid);
- if (id->maxchance == 10000 || (id->maxchance < db->dropitem[i].p) ) {
+ if (id->maxchance == -1 || (id->maxchance < db->dropitem[i].p) ) {
id->maxchance = db->dropitem[i].p; //item has bigger drop chance or sold in shops
}
for (k = 0; k< MAX_SEARCH; k++) {
@@ -3636,61 +3641,31 @@ static bool mob_parse_dbrow(char** str)
/*==========================================
* mob_db.txt reading
*------------------------------------------*/
-static int mob_readdb(void)
+static bool mob_readdb_sub(char* fields[], int columns, int current)
+{
+ return mob_parse_dbrow(fields);
+}
+
+static void mob_readdb(void)
{
const char* filename[] = { "mob_db.txt", "mob_db2.txt" };
int fi;
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
{
- uint32 lines = 0, count = 0;
- char line[1024];
char path[256];
- FILE* fp;
-
- sprintf(path, "%s/%s", db_path, filename[fi]);
- fp = fopen(path, "r");
- if(fp == NULL) {
- if(fi > 0)
- continue;
- return -1;
- }
-
- // process rows one by one
- while(fgets(line, sizeof(line), fp))
+
+ if(fi > 0)
{
- char *str[38+2*MAX_MOB_DROP], *p, *np;
- int i;
-
- lines++;
- if(line[0] == '/' && line[1] == '/')
- continue;
-
- for(i = 0, p = line; i < 38 + 2*MAX_MOB_DROP; i++)
+ sprintf(path, "%s/%s", db_path, filename[fi]);
+ if(!exists(path))
{
- str[i] = p;
- if((np = strchr(p, ',')) != NULL) {
- *np = '\0'; p = np + 1;
- }
- }
-
- if(i < 38 + 2*MAX_MOB_DROP) {
- ShowWarning("mob_readdb: Insufficient columns for mob with id: %d, skipping.\n", atoi(str[0]));
continue;
}
-
- if (!mob_parse_dbrow(str))
- continue;
-
- count++;
}
- fclose(fp);
-
- ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
+ sv_readdb(db_path, filename[fi], ',', 38+2*MAX_MOB_DROP, 38+2*MAX_MOB_DROP, -1, &mob_readdb_sub);
}
-
- return 0;
}
#ifndef TXT_ONLY
@@ -3753,73 +3728,42 @@ static int mob_read_sqldb(void)
/*==========================================
* MOB display graphic change data reading
*------------------------------------------*/
-static int mob_readdb_mobavail(void)
+static bool mob_readdb_mobavail(char* str[], int columns, int current)
{
- FILE *fp;
- char line[1024];
- int ln=0;
- int class_,j,k;
- char *str[20],*p,*np;
+ int class_, k;
- sprintf(line, "%s/mob_avail.txt", db_path);
- if( (fp=fopen(line,"r"))==NULL ){
- ShowError("can't read %s\n", line);
- return -1;
- }
+ class_=atoi(str[0]);
- while(fgets(line, sizeof(line), fp))
+ if(mob_db(class_) == mob_dummy) // 値が異常なら処理しない。
{
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(str,0,sizeof(str));
-
- for(j=0,p=line;j<12;j++){
- if((np=strchr(p,','))!=NULL){
- str[j]=p;
- *np=0;
- p=np+1;
- } else
- str[j]=p;
- }
-
- if(str[0]==NULL)
- continue;
-
- class_=atoi(str[0]);
- if (class_ == 0)
- continue; //Leave blank lines alone... [Skotlex]
-
- if(mob_db(class_) == mob_dummy) // 値が異常なら処理しない。
- continue;
-
- k=atoi(str[1]);
- if(k < 0)
- continue;
-
- memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
- mob_db_data[class_]->vd.class_=k;
-
- //Player sprites
- if(pcdb_checkid(k) && j>=12) {
- mob_db_data[class_]->vd.sex=atoi(str[2]);
- mob_db_data[class_]->vd.hair_style=atoi(str[3]);
- mob_db_data[class_]->vd.hair_color=atoi(str[4]);
- mob_db_data[class_]->vd.weapon=atoi(str[5]);
- mob_db_data[class_]->vd.shield=atoi(str[6]);
- mob_db_data[class_]->vd.head_top=atoi(str[7]);
- mob_db_data[class_]->vd.head_mid=atoi(str[8]);
- mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
- mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
- mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
- }
- else if(str[2] && atoi(str[2]) > 0)
- mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+ ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", class_);
+ return false;
+ }
- ln++;
+ k=atoi(str[1]);
+
+ memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
+ mob_db_data[class_]->vd.class_=k;
+
+ //Player sprites
+ if(pcdb_checkid(k) && columns==12) {
+ mob_db_data[class_]->vd.sex=atoi(str[2]);
+ mob_db_data[class_]->vd.hair_style=atoi(str[3]);
+ mob_db_data[class_]->vd.hair_color=atoi(str[4]);
+ mob_db_data[class_]->vd.weapon=atoi(str[5]);
+ mob_db_data[class_]->vd.shield=atoi(str[6]);
+ mob_db_data[class_]->vd.head_top=atoi(str[7]);
+ mob_db_data[class_]->vd.head_mid=atoi(str[8]);
+ mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
+ mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
+ mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"mob_avail.txt");
- return 0;
+ else if(columns==3)
+ mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+ else if( columns != 2 )
+ return false;
+
+ return true;
}
/*==========================================
@@ -3842,7 +3786,7 @@ static int mob_read_randommonster(void)
for( i = 0; i < ARRAYLENGTH(mobfile) && i < MAX_RANDOMMONSTER; i++ )
{
- mob_db_data[0]->summonper[i] = 1002; // 設定し忘れた場合はポリンが出るようにしておく
+ mob_db_data[0]->summonper[i] = 1002; // Default fallback value, in case the database does not provide one
sprintf(line, "%s/%s", db_path, mobfile[i]);
fp=fopen(line,"r");
if(fp==NULL){
@@ -3894,8 +3838,10 @@ static int mob_read_randommonster(void)
*------------------------------------------*/
static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id)
{
+ char* msg;
struct mob_chat *ms;
int msg_id;
+ size_t len;
msg_id = atoi(str[0]);
@@ -3917,13 +3863,29 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int*
//Color
ms->color=strtoul(str[1],NULL,0);
//Message
- if(strlen(str[2])>(CHAT_SIZE_MAX-1)){
+ msg = str[2];
+ len = strlen(msg);
+
+ while( len && ( msg[len-1]=='\r' || msg[len-1]=='\n' ) )
+ {// find EOL to strip
+ len--;
+ }
+
+ if(len>(CHAT_SIZE_MAX-1))
+ {
if (msg_id != *last_msg_id) {
ShowError("mob_chat: readdb: Message too long! Line %d, id: %d\n", line, msg_id);
*last_msg_id = msg_id;
}
return false;
}
+ else if( !len )
+ {
+ ShowWarning("mob_parse_row_chatdb: Empty message for id %d.\n", msg_id);
+ return false;
+ }
+
+ msg[len] = 0; // strip previously found EOL
strncpy(ms->msg, str[2], CHAT_SIZE_MAX);
return true;
@@ -3987,9 +3949,8 @@ static void mob_readchatdb(void)
/*==========================================
* processes one mob_skill_db entry
- * @param last_mob_id ensures that only one error message per mob id is printed
*------------------------------------------*/
-static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, int* last_mob_id)
+static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
{
static const struct {
char str[32];
@@ -4058,6 +4019,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
{ "around4", MST_AROUND4 },
{ "around", MST_AROUND },
};
+ static int last_mob_id = 0; // ensures that only one error message per mob id is printed
struct mob_skill *ms, gms;
int mob_id;
@@ -4067,9 +4029,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if (mob_id > 0 && mob_db(mob_id) == mob_dummy)
{
- 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;
+ if (mob_id != last_mob_id) {
+ ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id);
+ last_mob_id = mob_id;
}
return false;
}
@@ -4089,9 +4051,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
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", line, mob_id, mob_db_data[mob_id]->sprite);
- *last_mob_id = mob_id;
+ if (mob_id != last_mob_id) {
+ ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob_db_data[mob_id]->sprite);
+ last_mob_id = mob_id;
}
return false;
}
@@ -4102,7 +4064,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
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);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized state %s\n", str[2]);
ms->state = MSS_ANY;
}
@@ -4111,9 +4073,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if (j<=0 || j>MAX_SKILL_DB) //fixed Lupus
{
if (mob_id < 0)
- ShowError("Invalid Skill ID (%d) for all mobs\n", j);
+ ShowError("mob_parse_row_mobskilldb: 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);
+ ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
return false;
}
ms->skill_id=j;
@@ -4146,7 +4108,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
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);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized target %s for %d\n", str[9], mob_id);
ms->target = MST_TARGET;
}
@@ -4155,13 +4117,13 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
{ //Ground skill.
if (ms->target > MST_AROUND)
{
- ShowWarning("Wrong mob skill target for ground skill %d (%s) for %s.\n",
+ ShowWarning("mob_parse_row_mobskilldb: 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.",
+ ShowWarning("mob_parse_row_mobskilldb: 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;
@@ -4172,7 +4134,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
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);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized condition 1 %s for %d\n", str[10], mob_id);
ms->cond1 = -1;
}
@@ -4246,7 +4208,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
/*==========================================
* mob_skill_db.txt reading
*------------------------------------------*/
-static int mob_readskilldb(void)
+static void mob_readskilldb(void)
{
const char* filename[] = { "mob_skill_db.txt", "mob_skill_db2.txt" };
int fi;
@@ -4254,130 +4216,72 @@ static int mob_readskilldb(void)
if( battle_config.mob_skill_rate == 0 )
{
ShowStatus("Mob skill use disabled. Not reading mob skills.\n");
- return 0;
+ return;
}
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
{
- uint32 lines = 0, count = 0;
- char line[1024];
- int i;
- int tmp = 0;
-
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))
+ if(fi > 0)
{
- 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 < 19; i++)
+ sprintf(path, "%s/%s", db_path, filename[fi]);
+ if(!exists(path))
{
- str[i] = p;
- if((np = strchr(p, ',')) != NULL) {
- *np = '\0'; p = np + 1; j++;
- }
- }
-
- if ( j < 18 || str[18]==NULL )
- {
- ShowError("mob_readskilldb: Insufficient number of fields for skill at %s, line %d\n", filename[fi], lines);
continue;
}
-
- if( !mob_parse_row_mobskilldb(str, path, lines, &tmp) )
- continue;
-
- count++;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", filename[fi]);
+
+ sv_readdb(db_path, filename[fi], ',', 19, 19, -1, &mob_parse_row_mobskilldb);
}
- return 0;
}
/*==========================================
- * mob_race_db.txt reading
+ * mob_race2_db.txt reading
*------------------------------------------*/
-static int mob_readdb_race(void)
+static bool mob_readdb_race2(char* fields[], int columns, int current)
{
- FILE *fp;
- char line[1024];
- int race,j,k;
- char *str[20],*p,*np;
+ int race, mobid, i;
- sprintf(line, "%s/mob_race2_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));
+ race = atoi(fields[0]);
- for(j=0,p=line;j<12;j++){
- if((np=strchr(p,','))!=NULL){
- str[j]=p;
- *np=0;
- p=np+1;
- } else
- str[j]=p;
- }
- if(str[0]==NULL)
- continue;
+ if (race < RC2_NONE || race >= RC2_MAX)
+ {
+ ShowWarning("mob_readdb_race2: Unknown race2 %d.\n", race);
+ return false;
+ }
- race=atoi(str[0]);
- if (race < RC2_NONE || race >= RC2_MAX)
+ for(i = 1; i<columns; i++)
+ {
+ mobid = atoi(fields[i]);
+ if (mob_db(mobid) == mob_dummy)
+ {
+ ShowWarning("mob_readdb_race2: Unknown mob id %d for race2 %d.\n", mobid, race);
continue;
-
- for (j=1; j<20; j++) {
- if (!str[j])
- break;
- k=atoi(str[j]);
- if (mob_db(k) == mob_dummy)
- continue;
- mob_db_data[k]->race2 = race;
}
+ mob_db_data[mobid]->race2 = race;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","mob_race2_db.txt");
- return 0;
+ return true;
}
-void mob_reload(void)
+static void mob_load(void)
{
- int i;
#ifndef TXT_ONLY
- if(db_use_sqldbs)
- mob_read_sqldb();
- else
+ if(db_use_sqldbs)
+ mob_read_sqldb();
+ else
#endif /* TXT_ONLY */
mob_readdb();
- mob_readdb_mobavail();
+ sv_readdb(db_path, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail);
mob_read_randommonster();
+ mob_readchatdb();
+ mob_readskilldb();
+ sv_readdb(db_path, "mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2);
+}
+
+void mob_reload(void)
+{
+ int i;
//Mob skills need to be cleared before re-reading them. [Skotlex]
for (i = 0; i < MAX_MOB_DB; i++)
@@ -4386,9 +4290,8 @@ void mob_reload(void)
memset(&mob_db_data[i]->skill,0,sizeof(mob_db_data[i]->skill));
mob_db_data[i]->maxskill=0;
}
- mob_readchatdb();
- mob_readskilldb();
- mob_readdb_race();
+
+ mob_load();
}
void mob_clear_spawninfo()
@@ -4410,18 +4313,7 @@ int do_init_mob(void)
item_drop_ers = ers_new(sizeof(struct item_drop));
item_drop_list_ers = ers_new(sizeof(struct item_drop_list));
-#ifndef TXT_ONLY
- if(db_use_sqldbs)
- mob_read_sqldb();
- else
-#endif /* TXT_ONLY */
- mob_readdb();
-
- mob_readdb_mobavail();
- mob_read_randommonster();
- mob_readchatdb();
- mob_readskilldb();
- mob_readdb_race();
+ mob_load();
add_timer_func_list(mob_delayspawn,"mob_delayspawn");
add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");