diff --git a/conf/battle/homunc.conf b/conf/battle/homunc.conf index d79ac220e0..eeab3e2aa9 100644 --- a/conf/battle/homunc.conf +++ b/conf/battle/homunc.conf @@ -43,3 +43,9 @@ homunculus_max_level: 99 // Max level for Homunculus S homunculus_S_max_level: 150 + +// Growth level for Homunculus S +// This is the level at which homunculus S can use their growth tables +// Without this, a shuffle causes all levels of a Homunculus S to use their +// growth tables, causing imbalanced stats +homunculus_S_growth_level: 99 diff --git a/src/map/battle.c b/src/map/battle.c index 8408a5f9c9..e60cd60dfb 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1157,9 +1157,9 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) pc_addspiritball(sd,skill_get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); - if (sc->data[SC_STYLE_CHANGE]) { - TBL_HOM *hd = BL_CAST(BL_HOM,bl); //when being hit - if (hd && (rnd()%100<(status_get_lv(bl)/2)) ) hom_addspiritball(hd, 10); //add a sphere + if (sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING) { + TBL_HOM *hd = BL_CAST(BL_HOM,bl); // We add a sphere for when the Homunculus is being hit + if (hd && (rnd()%100<50) ) hom_addspiritball(hd, 10); // According to WarpPortal, this is a flat 50% chance } if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) @@ -1220,9 +1220,9 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam sc_start(src,bl,(enum sc_type)sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON, 1)); if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) status_change_spread(src, bl); - if (sc->data[SC_STYLE_CHANGE]) { + if (sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING) { TBL_HOM *hd = BL_CAST(BL_HOM,src); //when attacking - if (hd && (rnd()%100<(20+status_get_lv(bl)/5)) ) hom_addspiritball(hd, 10); + if (hd && (rnd()%100<50) ) hom_addspiritball(hd, 10); // According to WarpPortal, this is a flat 50% chance } } @@ -7235,6 +7235,7 @@ static const struct _battle_data { { "drop_rateincrease", &battle_config.drop_rateincrease, 0, 0, 1, }, { "feature.banking", &battle_config.feature_banking, 1, 0, 1, }, { "mon_trans_disable_in_gvg", &battle_config.mon_trans_disable_in_gvg, 0, 0, 1, }, + { "homunculus_S_growth_level", &battle_config.hom_S_growth_level, 99, 0, MAX_LEVEL, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 30cd474438..58ab912a7f 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -462,6 +462,7 @@ extern struct Battle_Config int client_limit_unit_lv; int hom_max_level; int hom_S_max_level; + int hom_S_growth_level; // [BattleGround Settings] int bg_update_interval; diff --git a/src/map/clif.c b/src/map/clif.c index 3794a04672..d8456d8cf3 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -55,8 +55,8 @@ /* for clif_clearunit_delayed */ static struct eri *delay_clearunit_ers; -#define DUMP_UNKNOWN_PACKET -#define DUMP_INVALID_PACKET +//#define DUMP_UNKNOWN_PACKET +//#define DUMP_INVALID_PACKET struct Clif_Config { int packet_db_ver; //Preferred packet version. diff --git a/src/map/homunculus.c b/src/map/homunculus.c index a7a87ed2a2..316000cc7b 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -312,7 +312,7 @@ void merc_hom_skillup(struct homun_data *hd,uint16 skill_id) int merc_hom_levelup(struct homun_data *hd) { struct s_homunculus *hom; - struct h_stats *min, *max; + struct h_stats *min = NULL, *max = NULL; int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ; int growth_max_hp, growth_max_sp ; int m_class; @@ -322,6 +322,21 @@ int merc_hom_levelup(struct homun_data *hd) return 0; } + /// When homunculus is homunculus S, we check to see if we need to apply previous class stats + if(m_class&HOM_S && hd->homunculus.level < battle_config.hom_S_growth_level) { + int i; + if(!hd->homunculus.prev_class) { + /// We also need to be sure that the previous class exists, otherwise give it something to work with + hd->homunculus.prev_class = 6001; + } + // Give the homunculus the level up stats database it needs + i = search_homunculusDB_index(hd->homunculus.prev_class,HOMUNCULUS_CLASS); + if(i < 0) // Nothing should go wrong here, but check anyways + return 0; + max = &homunculus_db[i].gmax; + min = &homunculus_db[i].gmin; + } + if(((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) || ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) || !hd->exp_next || hd->homunculus.exp < hd->exp_next) @@ -335,8 +350,10 @@ int merc_hom_levelup(struct homun_data *hd) hom->exp -= hd->exp_next ; hd->exp_next = hexptbl[hom->level - 1] ; - max = &hd->homunculusDB->gmax; - min = &hd->homunculusDB->gmin; + if(!max) { + max = &hd->homunculusDB->gmax; + min = &hd->homunculusDB->gmin; + } growth_max_hp = rnd_value(min->HP, max->HP); growth_max_sp = rnd_value(min->SP, max->SP); @@ -1022,7 +1039,7 @@ int merc_hom_shuffle(struct homun_data *hd) for (i = 1; i < lv && hd->exp_next; i++){ hd->homunculus.exp += hd->exp_next; // Should never happen, but who knows - if( !merc_hom_levelup(hd) ){ + if( !merc_hom_levelup(hd) ) { break; } } diff --git a/src/map/skill.c b/src/map/skill.c index 2988048747..850501d018 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -679,22 +679,28 @@ bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd) if(hd->sc.data[SC_GOLDENE_FERSE]) return true; break; case MH_TINDER_BREAKER: //must be in grappling mode - if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) return true; + if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING) + || !hd->homunculus.spiritball) return true; break; case MH_SONIC_CRAW: //must be in fighting mode - if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) return true; + if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING) + || !hd->homunculus.spiritball) return true; break; case MH_SILVERVEIN_RUSH: - if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)) return true; + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW) + || hd->homunculus.spiritball < 2) return true; break; case MH_MIDNIGHT_FRENZY: - if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) return true; + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH) + || !hd->homunculus.spiritball) return true; break; case MH_CBC: - if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) return true; + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER) + || !hd->homunculus.spiritball) return true; break; case MH_EQC: - if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)) return true; + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC) + || !hd->homunculus.spiritball) return true; break; } @@ -5003,15 +5009,19 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case MH_STAHL_HORN: case MH_NEEDLE_OF_PARALYZE: - case MH_SONIC_CRAW: skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; case MH_MIDNIGHT_FRENZY: case MH_SILVERVEIN_RUSH: + case MH_SONIC_CRAW: { TBL_HOM *hd = BL_CAST(BL_HOM,src); - hom_delspiritball(hd,skill_id==MH_SILVERVEIN_RUSH?1:2,0); + short remove_sphere = (skill_id==MH_SILVERVEIN_RUSH?1:2); + + if(skill_id == MH_SONIC_CRAW) + remove_sphere = hd->homunculus.spiritball; skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); + hom_delspiritball(hd,remove_sphere,0); } break; case MH_TINDER_BREAKER: