From 28677f9e8071015f65a81254232d12da6393f144 Mon Sep 17 00:00:00 2001 From: Fate Date: Mon, 1 Dec 2008 14:05:09 -0700 Subject: Added mutations to mobs (must change mob_db.txt) --- src/map/battle.c | 39 ++++++------ src/map/clif.c | 2 +- src/map/map.h | 18 +++++- src/map/mob.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++---- src/map/mob.h | 1 + src/map/npc.c | 1 - src/map/skill.c | 4 +- 7 files changed, 210 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/map/battle.c b/src/map/battle.c index b49e90a..918853b 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -98,7 +98,7 @@ int battle_get_lv(struct block_list *bl) { nullpo_retr(0, bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - return mob_db[((struct mob_data *)bl)->class].lv; + return ((struct mob_data *)bl)->stats[MOB_LV]; else if(bl->type==BL_PC && (struct map_session_data *)bl) return ((struct map_session_data *)bl)->status.base_level; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -152,7 +152,7 @@ int battle_get_max_hp(struct block_list *bl) struct status_change *sc_data=battle_get_sc_data(bl); int max_hp=1; if(bl->type==BL_MOB && ((struct mob_data*)bl)) { - max_hp = mob_db[((struct mob_data*)bl)->class].max_hp; + max_hp = ((struct mob_data*)bl)->stats[MOB_MAX_HP]; if(mob_db[((struct mob_data*)bl)->class].mexp > 0) { if(battle_config.mvp_hp_rate != 100) max_hp = (max_hp * battle_config.mvp_hp_rate)/100; @@ -196,7 +196,7 @@ int battle_get_str(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && ((struct mob_data *)bl)) - str = mob_db[((struct mob_data *)bl)->class].str; + str = ((struct mob_data *)bl)->stats[MOB_STR]; else if(bl->type==BL_PC && ((struct map_session_data *)bl)) return ((struct map_session_data *)bl)->paramc[0]; else if(bl->type==BL_PET && ((struct pet_data *)bl)) @@ -230,7 +230,7 @@ int battle_get_agi(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - agi=mob_db[((struct mob_data *)bl)->class].agi; + agi=((struct mob_data *)bl)->stats[MOB_AGI]; else if(bl->type==BL_PC && (struct map_session_data *)bl) agi=((struct map_session_data *)bl)->paramc[1]; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -268,7 +268,7 @@ int battle_get_vit(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - vit=mob_db[((struct mob_data *)bl)->class].vit; + vit=((struct mob_data *)bl)->stats[MOB_VIT]; else if(bl->type==BL_PC && (struct map_session_data *)bl) vit=((struct map_session_data *)bl)->paramc[2]; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -296,7 +296,7 @@ int battle_get_int(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - int_=mob_db[((struct mob_data *)bl)->class].int_; + int_=((struct mob_data *)bl)->stats[MOB_INT]; else if(bl->type==BL_PC && (struct map_session_data *)bl) int_=((struct map_session_data *)bl)->paramc[3]; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -329,7 +329,7 @@ int battle_get_dex(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - dex=mob_db[((struct mob_data *)bl)->class].dex; + dex=((struct mob_data *)bl)->stats[MOB_DEX]; else if(bl->type==BL_PC && (struct map_session_data *)bl) dex=((struct map_session_data *)bl)->paramc[4]; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -366,7 +366,7 @@ int battle_get_luk(struct block_list *bl) nullpo_retr(0, bl); sc_data=battle_get_sc_data(bl); if(bl->type==BL_MOB && (struct mob_data *)bl) - luk=mob_db[((struct mob_data *)bl)->class].luk; + luk=((struct mob_data *)bl)->stats[MOB_LUK]; else if(bl->type==BL_PC && (struct map_session_data *)bl) luk=((struct map_session_data *)bl)->paramc[5]; else if(bl->type==BL_PET && (struct pet_data *)bl) @@ -550,7 +550,7 @@ int battle_get_atk(struct block_list *bl) if(bl->type==BL_PC && (struct map_session_data *)bl) atk = ((struct map_session_data*)bl)->watk; else if(bl->type==BL_MOB && (struct mob_data *)bl) - atk = mob_db[((struct mob_data*)bl)->class].atk1; + atk = ((struct mob_data*)bl)->stats[MOB_ATK1]; else if(bl->type==BL_PET && (struct pet_data *)bl) atk = mob_db[((struct pet_data*)bl)->class].atk1; @@ -597,7 +597,7 @@ int battle_get_atk2(struct block_list *bl) struct status_change *sc_data=battle_get_sc_data(bl); int atk2=0; if(bl->type==BL_MOB && (struct mob_data *)bl) - atk2 = mob_db[((struct mob_data*)bl)->class].atk2; + atk2 = ((struct mob_data*)bl)->stats[MOB_ATK2]; else if(bl->type==BL_PET && (struct pet_data *)bl) atk2 = mob_db[((struct pet_data*)bl)->class].atk2; if(sc_data) { @@ -716,7 +716,7 @@ int battle_get_def(struct block_list *bl) skillid = ((struct map_session_data *)bl)->skillid; } else if(bl->type==BL_MOB && (struct mob_data *)bl) { - def = mob_db[((struct mob_data *)bl)->class].def; + def = ((struct mob_data *)bl)->stats[MOB_DEF]; skilltimer = ((struct mob_data *)bl)->skilltimer; skillid = ((struct mob_data *)bl)->skillid; } @@ -778,7 +778,7 @@ int battle_get_mdef(struct block_list *bl) if(bl->type==BL_PC && (struct map_session_data *)bl) mdef = ((struct map_session_data *)bl)->mdef; else if(bl->type==BL_MOB && (struct mob_data *)bl) - mdef = mob_db[((struct mob_data *)bl)->class].mdef; + mdef = ((struct mob_data *)bl)->stats[MOB_MDEF]; else if(bl->type==BL_PET && (struct pet_data *)bl) mdef = mob_db[((struct pet_data *)bl)->class].mdef; @@ -817,7 +817,7 @@ int battle_get_def2(struct block_list *bl) if(bl->type==BL_PC) def2 = ((struct map_session_data *)bl)->def2; else if(bl->type==BL_MOB) - def2 = mob_db[((struct mob_data *)bl)->class].vit; + def2 = ((struct mob_data *)bl)->stats[MOB_VIT]; else if(bl->type==BL_PET) def2 = mob_db[((struct pet_data *)bl)->class].vit; @@ -847,7 +847,7 @@ int battle_get_mdef2(struct block_list *bl) nullpo_retr(0, bl); if(bl->type==BL_MOB) - mdef2 = mob_db[((struct mob_data *)bl)->class].int_ + (mob_db[((struct mob_data *)bl)->class].vit>>1); + mdef2 = ((struct mob_data *)bl)->stats[MOB_INT] + (((struct mob_data *)bl)->stats[MOB_VIT]>>1); else if(bl->type==BL_PC) mdef2 = ((struct map_session_data *)bl)->mdef2 + (((struct map_session_data *)bl)->paramc[2]>>1); else if(bl->type==BL_PET) @@ -874,8 +874,7 @@ int battle_get_speed(struct block_list *bl) struct status_change *sc_data=battle_get_sc_data(bl); int speed = 1000; if(bl->type==BL_MOB && (struct mob_data *)bl) -// speed = mob_db[((struct mob_data *)bl)->class].speed; - speed = ((struct mob_data *)bl)->speed; + speed = ((struct mob_data *)bl)->stats[MOB_SPEED]; else if(bl->type==BL_PET && (struct pet_data *)bl) speed = ((struct pet_data *)bl)->msd->petDB->speed; @@ -928,7 +927,7 @@ int battle_get_adelay(struct block_list *bl) struct status_change *sc_data=battle_get_sc_data(bl); int adelay=4000,aspd_rate = 100,i; if(bl->type==BL_MOB && (struct mob_data *)bl) - adelay = mob_db[((struct mob_data *)bl)->class].adelay; + adelay = ((struct mob_data *)bl)->stats[MOB_ADELAY]; else if(bl->type==BL_PET && (struct pet_data *)bl) adelay = mob_db[((struct pet_data *)bl)->class].adelay; @@ -1203,7 +1202,10 @@ int battle_get_mexp(struct block_list *bl) { nullpo_retr(0, bl); if(bl->type==BL_MOB && (struct mob_data *)bl) { - return mob_db[((struct mob_data *)bl)->class].mexp; + const struct mob_data *mob = (struct mob_data *) bl; + const int retval = (mob_db[mob->class].mexp * (int) (mob->stats[MOB_XP_BONUS])) >> MOB_XP_BONUS_SHIFT; + fprintf(stderr, "Modifier of %x: -> %d\n", mob->stats[MOB_XP_BONUS], retval); + return retval; } else if(bl->type==BL_PET && (struct pet_data *)bl) return mob_db[((struct pet_data *)bl)->class].mexp; @@ -4334,7 +4336,6 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target, short *opt1; int race = 7, ele = 0; int damage,rdamage = 0; - int i; struct Damage wd; nullpo_retr(0, src); diff --git a/src/map/clif.c b/src/map/clif.c index 418e56a..426ee53 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1388,7 +1388,7 @@ int clif_spawnmob(struct mob_data *md) WBUFW(buf,0)=0x7c; WBUFL(buf,2)=md->bl.id; - WBUFW(buf,6)=md->speed; + WBUFW(buf,6)=md->stats[MOB_SPEED]; WBUFW(buf,8)=md->opt1; WBUFW(buf,10)=md->opt2; WBUFW(buf,12)=md->option; diff --git a/src/map/map.h b/src/map/map.h index 54179ac..afaf61e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -410,6 +410,22 @@ struct npc_data { #define MOB_SENSIBLE_MASK 0xf000 // fate: mob mode flags that I actually understand +enum mob_stat { + MOB_LV, + MOB_MAX_HP, + MOB_STR, MOB_AGI, MOB_VIT, MOB_INT, MOB_DEX, MOB_LUK, + MOB_ATK1, MOB_ATK2, // low and high attacks + MOB_ADELAY, // attack delay + MOB_DEF, MOB_MDEF, + MOB_SPEED, + // These must come last: + MOB_XP_BONUS, /* [Fate] Encoded as base to 1024: 1024 means 100% */ + MOB_LAST +}; + +#define MOB_XP_BONUS_BASE 1024 +#define MOB_XP_BONUS_SHIFT 10 + struct mob_data { struct block_list bl; short n; @@ -431,7 +447,6 @@ struct mob_data { } state; int timer; short to_x,to_y; - short speed; int hp; int target_id,attacked_id; short target_lv; @@ -468,6 +483,7 @@ struct mob_data { struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP]; struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET]; char npc_event[50]; + unsigned short stats[MOB_LAST]; // [Fate] mob-specific stats short size; }; struct pet_data { diff --git a/src/map/mob.c b/src/map/mob.c index dc40630..f43e049 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -74,6 +74,9 @@ int mobdb_checkid(const int id) return id; } +static void +mob_init(struct mob_data *md); + /*========================================== * The minimum data set for MOB spawning *------------------------------------------ @@ -82,8 +85,6 @@ int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class) { nullpo_retr(0, md); - md->bl.prev=NULL; - md->bl.next=NULL; if(strcmp(mobname,"--en--")==0) memcpy(md->name,mob_db[class].name,24); else if(strcmp(mobname,"--ja--")==0) @@ -91,6 +92,8 @@ int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class) else memcpy(md->name,mobname,24); + md->bl.prev=NULL; + md->bl.next=NULL; md->n = 0; md->base_class = md->class = class; md->bl.id= npc_get_new_npc_id(); @@ -99,11 +102,157 @@ int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class) md->timer = -1; md->target_id=0; md->attacked_id=0; - md->speed=mob_db[class].speed; + + mob_init(md); return 0; } +// Mutation values indicate how `valuable' a change to each stat is, XP wise. +// For one 256th of change, we give out that many 1024th fractions of XP change +// (i.e., 1024 means a 100% XP increase for a single point of adjustment, 4 means 100% XP bonus for doubling the value) +static int +mutation_value[MOB_XP_BONUS] = +{ + 2, // MOB_LV + 3, // MOB_MAX_HP + 1, // MOB_STR + 2, // MOB_AGI + 1, // MOB_VIT + 0, // MOB_INT + 2, // MOB_DEX + 2, // MOB_LUK + 1, // MOB_ATK1 + 1, // MOB_ATK2 + 2, // MOB_ADELAY + 2, // MOB_DEF + 2, // MOB_MDEF + 2, // MOB_SPEED +}; + +// The mutation scale indicates how far `up' we can go, with 256 indicating 100% Note that this may stack with multiple +// calls to `mutate'. +static int +mutation_scale[MOB_XP_BONUS] = +{ + 16, // MOB_LV + 256, // MOB_MAX_HP + 32, // MOB_STR + 48, // MOB_AGI + 48, // MOB_VIT + 48, // MOB_INT + 48, // MOB_DEX + 64, // MOB_LUK + 48, // MOB_ATK1 + 48, // MOB_ATK2 + 80, // MOB_ADELAY + 48, // MOB_DEF + 48, // MOB_MDEF + 80, // MOB_SPEED +}; + + +/*======================================== + * Mutates a MOB. For large `direction' values, calling this multiple times will give bigger XP boni. + *---------------------------------------- + */ +static void +mob_mutate(struct mob_data *md, int stat, int intensity) // intensity: positive: strengthen, negative: weaken. 256 = 100%. +{ + int old_stat; + int new_stat; + int real_intensity; + int sign = 1; + + if (!md || stat < 0 || stat >= MOB_XP_BONUS || intensity == 0) + return; + + while (intensity > mutation_scale[stat]) { + mob_mutate(md, stat, mutation_scale[stat]); // give better XP assignments + intensity -= mutation_scale[stat]; + } + while (intensity < -mutation_scale[stat]) { + mob_mutate(md, stat, mutation_scale[stat]); // give better XP assignments + intensity += mutation_scale[stat]; + } + + if (!intensity) + return; + + // MOB_ADELAY and MOB_SPEED are special because going DOWN is good here. + if (stat == MOB_ADELAY || stat == MOB_SPEED) + sign = -1; + + // Now compute the new stat + old_stat = md->stats[stat]; + new_stat = old_stat + ((old_stat * sign * intensity) / 256); + + if (new_stat < 0) + new_stat = 0; + + if (old_stat == 0) + real_intensity = 0; + else + real_intensity = sign * (((new_stat - old_stat) << 8) / old_stat); + + md->stats[stat] = new_stat; + + // Adjust XP value + md->stats[MOB_XP_BONUS] += mutation_value[stat] * real_intensity; + if (md->stats[MOB_XP_BONUS] <= 0) + md->stats[MOB_XP_BONUS] = 1; + + // Sanitise + if (md->stats[MOB_ATK1] > md->stats[MOB_ATK2]) { + int swap = md->stats[MOB_ATK2]; + md->stats[MOB_ATK2] = md->stats[MOB_ATK1]; + md->stats[MOB_ATK1] = swap; + } +} + + +static void +mob_init(struct mob_data *md) +{ + int i; + const int class = md->class; + const int mutations_nr = mob_db[class].mutations_nr; + const int mutation_power = mob_db[class].mutation_power; + + md->stats[MOB_LV] = mob_db[class].lv; + md->stats[MOB_MAX_HP] = mob_db[class].max_hp; + md->stats[MOB_STR] = mob_db[class].str; + md->stats[MOB_AGI] = mob_db[class].agi; + md->stats[MOB_VIT] = mob_db[class].vit; + md->stats[MOB_INT] = mob_db[class].int_; + md->stats[MOB_DEX] = mob_db[class].dex; + md->stats[MOB_LUK] = mob_db[class].luk; + md->stats[MOB_ATK1] = mob_db[class].atk1; + md->stats[MOB_ATK2] = mob_db[class].atk2; + md->stats[MOB_ADELAY] = mob_db[class].adelay; + md->stats[MOB_DEF] = mob_db[class].def; + md->stats[MOB_MDEF] = mob_db[class].mdef; + md->stats[MOB_SPEED] = mob_db[class].speed; + md->stats[MOB_XP_BONUS] = MOB_XP_BONUS_BASE; + + for (i = 0; i < mutations_nr; i++) { + int stat_nr = MRAND(MOB_XP_BONUS + 1); + int strength; + + if (stat_nr >= MOB_XP_BONUS) + stat_nr = MOB_MAX_HP; + + strength = ((MRAND((mutation_power >> 1)) + (MRAND((mutation_power >> 1))) + 2) * mutation_scale[stat_nr]) / 100; + + strength = MRAND(2)? strength : -strength; + + if (strength < -240) + strength = -240; /* Don't go too close to zero */ + + mob_mutate(md, stat_nr, strength); + } +} + /*========================================== * The MOB appearance for one time (for scripts) @@ -845,7 +994,7 @@ int mob_spawn(int id) if(!md || !md->bl.type || md->bl.type!=BL_MOB) return -1; - + md->last_spawntime=tick; if( md->bl.prev!=NULL ){ // clif_clearchar_area(&md->bl,3); @@ -884,9 +1033,10 @@ int mob_spawn(int id) md->attacked_id = 0; md->target_id = 0; md->move_fail_count = 0; + mob_init(md); - if(!md->speed) - md->speed = mob_db[md->class].speed; + if(!md->stats[MOB_SPEED]) + md->stats[MOB_SPEED] = mob_db[md->class].speed; md->def_ele = mob_db[md->class].element; md->master_id=0; md->master_dist=0; @@ -2304,7 +2454,8 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type) per=(double)md->dmglog[i].dmg*256*(9+(double)((count > 6)? 6:count))/10/(double)max_hp; if(per>512) per=512; if(per<1) per=1; - base_exp=mob_db[md->class].base_exp*per/256; + + base_exp = ((mob_db[md->class].base_exp * md->stats[MOB_XP_BONUS]) >> MOB_XP_BONUS_SHIFT) * per/256; if(base_exp < 1) base_exp = 1; if(sd && md && battle_config.pk_mode==1 && (mob_db[md->class].lv - sd->status.base_level >= 20)) { base_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris] @@ -2421,8 +2572,8 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type) // mvp処理 if(mvp_sd && mob_db[md->class].mexp > 0 ){ int j; - int mexp; - temp = ((double)mob_db[md->class].mexp * (double)battle_config.mvp_exp_rate * (9.+(double)count)/1000.); + int mexp = battle_get_mexp(&md->bl); + temp = ((double)mexp * (double)battle_config.mvp_exp_rate * (9.+(double)count)/1000.); mexp = (temp > 2147483647.)? 0x7fffffff:(int)temp; if(mexp < 1) mexp = 1; clif_mvp_effect(mvp_sd); // エフェクト @@ -2543,7 +2694,7 @@ int mob_class_change(struct mob_data *md,int *value) md->target_id = 0; md->move_fail_count = 0; - md->speed = mob_db[md->class].speed; + md->stats[MOB_SPEED] = mob_db[md->class].speed; md->def_ele = mob_db[md->class].element; mob_changestate(md,MS_IDLE,0); @@ -2781,6 +2932,8 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int flag) } mob_spawn_dataset(md,"--ja--",class); + md->bl.prev=NULL; + md->bl.next=NULL; md->bl.m=m; md->bl.x=x; md->bl.y=y; @@ -2790,7 +2943,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int flag) md->y0=y; md->xs=0; md->ys=0; - md->speed=md2->speed; + md->stats[MOB_SPEED]=md2->stats[MOB_SPEED]; md->spawndelay1=-1; // 一度のみフラグ md->spawndelay2=-1; // 一度のみフラグ @@ -3647,12 +3800,12 @@ static int mob_readdb(void) } while(fgets(line,1020,fp)){ int class,i; - char *str[55],*p,*np; + char *str[57],*p,*np; if(line[0] == '/' && line[1] == '/') continue; - for(i=0,p=line;i<55;i++){ + for(i=0,p=line;i<57;i++){ while (*p == '\t' || *p == ' ') p++; if((np=strchr(p,','))!=NULL){ str[i]=p; @@ -3753,6 +3906,9 @@ static int mob_readdb(void) mob_db[class].mvpitem[i].nameid=atoi(str[47+i*2]); mob_db[class].mvpitem[i].p=atoi(str[48+i*2])*battle_config.mvp_item_rate/100; } + mob_db[class].mutations_nr = atoi(str[55]); + mob_db[class].mutation_power = atoi(str[56]); + for(i=0;itimer = -1; md->target_id=0; md->attacked_id=0; - md->speed=mob_db[class].speed; if (mob_db[class].mode&0x02) md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item)); diff --git a/src/map/skill.c b/src/map/skill.c index 9047e7f..460a328 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -8227,8 +8227,8 @@ int skill_status_change_timer(int tid, unsigned int tick, int id, int data) case SC_SELFDESTRUCTION: /* 自爆 */ if(--sc_data[type].val3>0){ struct mob_data *md; - if(bl->type==BL_MOB && (md=(struct mob_data *)bl) && md->speed > 250){ - md->speed -= 250; + if(bl->type==BL_MOB && (md=(struct mob_data *)bl) && md->stats[MOB_SPEED] > 250){ + md->stats[MOB_SPEED] -= 250; md->next_walktime=tick; } sc_data[type].timer=add_timer( /* タイマー再設定 */ -- cgit v1.2.3-70-g09d2