Browse Source

Homunculus Fixes

Applied a new check for Homunculus S reshuffling and leveling
-> When the Homunculus S is below the define battle config "homunculus_S_growth_level", it uses its previous class' growth rates which helps prevent imbalanced Homunculus
- If it has no previous class (command made), it will default to 6001 (Lif)

Fixed Eleanor's skills
- All skills which use spirit spheres now check for them prior
- SONIC_CLAW now deletes the spirit spheres

Fixed Eleanor obtaining spirit spheres for either FIghting or Grapple mode
- She is suppose to have a 50% chance to gain a spirit sphere when attacking in FIghting Mode and a 50% chance when being hit in Grapple Mode (according to Warp Portal)

Fixed packet dump errors - http://rathena.org/board/tracker/issue-8217-map-server-error-when-login-character/
Akinari1087 11 years ago
parent
commit
4d61cc0e14
6 changed files with 54 additions and 19 deletions
  1. 6 0
      conf/battle/homunc.conf
  2. 6 5
      src/map/battle.c
  3. 1 0
      src/map/battle.h
  4. 2 2
      src/map/clif.c
  5. 21 4
      src/map/homunculus.c
  6. 18 8
      src/map/skill.c

+ 6 - 0
conf/battle/homunc.conf

@@ -43,3 +43,9 @@ homunculus_max_level: 99
 
 
 // Max level for Homunculus S
 // Max level for Homunculus S
 homunculus_S_max_level: 150
 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

+ 6 - 5
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 )
 		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);
 			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 )
 		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));
 			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 )
 		if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 )
 			status_change_spread(src, bl);
 			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
 			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,              },
 	{ "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
 	{ "feature.banking",                    &battle_config.feature_banking,                 1,      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,              },
 	{ "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
 #ifndef STATS_OPT_OUT
 /**
 /**

+ 1 - 0
src/map/battle.h

@@ -462,6 +462,7 @@ extern struct Battle_Config
 	int client_limit_unit_lv;
 	int client_limit_unit_lv;
 	int hom_max_level;
 	int hom_max_level;
 	int hom_S_max_level;
 	int hom_S_max_level;
+	int hom_S_growth_level;
 
 
 	// [BattleGround Settings]
 	// [BattleGround Settings]
 	int bg_update_interval;
 	int bg_update_interval;

+ 2 - 2
src/map/clif.c

@@ -55,8 +55,8 @@
 /* for clif_clearunit_delayed */
 /* for clif_clearunit_delayed */
 static struct eri *delay_clearunit_ers;
 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 {
 struct Clif_Config {
 	int packet_db_ver;	//Preferred packet version.
 	int packet_db_ver;	//Preferred packet version.

+ 21 - 4
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)
 int merc_hom_levelup(struct homun_data *hd)
 {
 {
 	struct s_homunculus *hom;
 	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_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ;
 	int growth_max_hp, growth_max_sp ;
 	int growth_max_hp, growth_max_sp ;
 	int m_class;
 	int m_class;
@@ -322,6 +322,21 @@ int merc_hom_levelup(struct homun_data *hd)
 		return 0;
 		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)
 	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)
 		|| ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level)
 		|| !hd->exp_next || hd->homunculus.exp < hd->exp_next)
 		|| !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 ;
 	hom->exp -= hd->exp_next ;
 	hd->exp_next = hexptbl[hom->level - 1] ;
 	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_hp = rnd_value(min->HP, max->HP);
 	growth_max_sp = rnd_value(min->SP, max->SP);
 	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++){
 	for (i = 1; i < lv && hd->exp_next; i++){
 		hd->homunculus.exp += hd->exp_next;
 		hd->homunculus.exp += hd->exp_next;
 		// Should never happen, but who knows
 		// Should never happen, but who knows
-		if( !merc_hom_levelup(hd) ){
+		if( !merc_hom_levelup(hd) ) {
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 18 - 8
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;
 			if(hd->sc.data[SC_GOLDENE_FERSE]) return true;
 			break;
 			break;
 		case MH_TINDER_BREAKER: //must be in grappling mode
 		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;
 			break;
 		case MH_SONIC_CRAW: //must be in fighting mode
 		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;
 			break;
 		case MH_SILVERVEIN_RUSH:
 		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;
 			break;
 		case MH_MIDNIGHT_FRENZY:
 		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;
 			break;
 		case MH_CBC:
 		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;
 			break;
 		case MH_EQC:
 		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;
 			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_STAHL_HORN:
 	case MH_NEEDLE_OF_PARALYZE:
 	case MH_NEEDLE_OF_PARALYZE:
-	case MH_SONIC_CRAW:
 		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
 		skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
 		break;
 		break;
 	case MH_MIDNIGHT_FRENZY:
 	case MH_MIDNIGHT_FRENZY:
 	case MH_SILVERVEIN_RUSH:
 	case MH_SILVERVEIN_RUSH:
+	case MH_SONIC_CRAW:
 		{
 		{
 			TBL_HOM *hd = BL_CAST(BL_HOM,src);
 			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);
 			skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
+			hom_delspiritball(hd,remove_sphere,0);
 		}
 		}
 		break;
 		break;
 	case MH_TINDER_BREAKER:
 	case MH_TINDER_BREAKER: