Jelajahi Sumber

Updated Homunculus S skill failure messages (#2082)

* Fixes #2058.
* Added missing skill failure messages for Homunculus S.
* Eternal Quick Combo can no longer be used on Status Immune monsters.
* Disabled the Style Change message for Eleanor. Aegis does not display a message when switching fighting style.
Thanks to @feltenc and @Jeybla!
Aleos 8 tahun lalu
induk
melakukan
452d9c60eb
5 mengubah file dengan 114 tambahan dan 78 penghapusan
  1. 1 1
      db/pre-re/skill_require_db.txt
  2. 1 1
      db/re/skill_require_db.txt
  3. 2 2
      src/map/clif.c
  4. 109 73
      src/map/skill.c
  5. 1 1
      src/map/skill.h

+ 1 - 1
db/pre-re/skill_require_db.txt

@@ -984,7 +984,7 @@
 8025,0,0,90:100:110:120:130,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0				//MH_XENO_SLASHER
 8026,0,0,45:54:63:72:81,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SILENT_BREEZE
 8027,0,0,35,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0								//MH_STYLE_CHANGE
-8028,0,0,20:25:30:35:40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SONIC_CRAW
+8028,0,0,20:25:30:35:40,0,0,0,99,0,0,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SONIC_CRAW
 8029,0,0,10:15:20:25:30,0,0,0,99,0,0,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SILVERVEIN_RUSH
 8030,0,0,8:16:24:32:40,0,0,0,99,0,0,none,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_MIDNIGHT_FRENZY
 8031,0,0,40:45:50:55:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_STAHL_HORN

+ 1 - 1
db/re/skill_require_db.txt

@@ -1019,7 +1019,7 @@
 8025,0,0,90:100:110:120:130,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0				//MH_XENO_SLASHER
 8026,0,0,45:54:63:72:81,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SILENT_BREEZE
 8027,0,0,35,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0								//MH_STYLE_CHANGE
-8028,0,0,20:25:30:35:40,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SONIC_CRAW
+8028,0,0,20:25:30:35:40,0,0,0,99,0,0,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SONIC_CRAW
 8029,0,0,10:15:20:25:30,0,0,0,99,0,0,none,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_SILVERVEIN_RUSH
 8030,0,0,8:16:24:32:40,0,0,0,99,0,0,none,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_MIDNIGHT_FRENZY
 8031,0,0,40:45:50:55:60,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0					//MH_STAHL_HORN

+ 2 - 2
src/map/clif.c

@@ -11785,7 +11785,7 @@ static void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_sess
 
 	if( !hd )
 		return;
-	if( skill_isNotOk_hom(skill_id, hd) ) {
+	if( skill_isNotOk_hom(hd, skill_id, skill_lv) ) {
 		clif_emotion(&hd->bl, E_DOTS);
 		return;
 	}
@@ -11812,7 +11812,7 @@ static void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_ses
 	int lv;
 	if( !hd )
 		return;
-	if( skill_isNotOk_hom(skill_id, hd) ) {
+	if( skill_isNotOk_hom(hd, skill_id, skill_lv) ) {
 		clif_emotion(&hd->bl, E_DOTS);
 		return;
 	}

+ 109 - 73
src/map/skill.c

@@ -759,66 +759,123 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
 /**
  * Check if the homunculus skill is ok to be processed
  * After checking from Homunculus side, also check the master condition
- * @param skill_id: Skill ID that casted
  * @param hd: Homunculus who casted
+ * @param skill_id: Skill ID casted
+ * @param skill_lv: Skill level casted
  * @return true: Skill cannot be used, false: otherwise
  */
-bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd)
+bool skill_isNotOk_hom(struct homun_data *hd, uint16 skill_id, uint16 skill_lv)
 {
 	uint16 idx = skill_get_index(skill_id);
-	nullpo_retr(1,hd);
+	struct map_session_data *sd = NULL;
+	struct status_change *sc;
+	int8 spiritball = 0;
+
+	nullpo_retr(true, hd);
 
 	if (idx == 0)
 		return true; // invalid skill id
 
+	spiritball = skill_get_spiritball(skill_id, skill_lv);
+	sd = hd->master;
+	sc = status_get_sc(&hd->bl);
+
+	if (!sd)
+		return true;
+
+	if (sc && !sc->count)
+		sc = NULL;
+
 	if (hd->blockskill[idx] > 0)
 		return true;
 
 	switch(skill_id) {
-		case MH_LIGHT_OF_REGENE: //must be cordial
+		case HFLI_SBR44:
+			if (hom_get_intimacy_grade(hd) <= HOMGRADE_HATE_WITH_PASSION) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
+				return true;
+			}
+			break;
+		case HVAN_EXPLOSION:
+			if (hd->homunculus.intimacy < (unsigned int)battle_config.hvan_explosion_intimate) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
+				return true;
+			}
+			break;
+		case MH_LIGHT_OF_REGENE: // Must be cordial
 			if (hom_get_intimacy_grade(hd) < HOMGRADE_CORDIAL) {
-				if (hd->master)
-					clif_skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
 				return true;
 			}
 			break;
-		case MH_GOLDENE_FERSE: //cant be used with angriff
-			if(&hd->sc && hd->sc.data[SC_ANGRIFFS_MODUS]) return true;
+		case MH_GOLDENE_FERSE: // Can't be used with Angriff's Modus
+			if (sc && sc->data[SC_ANGRIFFS_MODUS])
+				return true;
 			break;
 		case MH_ANGRIFFS_MODUS:
-			if(&hd->sc && hd->sc.data[SC_GOLDENE_FERSE]) return true;
+			if (sc && sc->data[SC_GOLDENE_FERSE])
+				return true;
 			break;
-		case MH_TINDER_BREAKER: //must be in grappling mode
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)
-				|| !hd->homunculus.spiritball) return true;
+		case MH_TINDER_BREAKER: // Must be in grappling mode
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_GRAPPLER, 1);
+				return true;
+			}
 			break;
-		case MH_SONIC_CRAW: //must be in fighting mode
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)
-				|| !hd->homunculus.spiritball) return true;
+		case MH_SONIC_CRAW: // Must be in fighting mode
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_FIGHTER, 0);
+				return true;
+			}
 			break;
 		case MH_SILVERVEIN_RUSH:
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)
-				|| hd->homunculus.spiritball < 2) return true;
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_FIGHTER, 0);
+				return true;
+			}
+			if (!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MH_SONIC_CRAW)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MH_SONIC_CRAW);
+				return true;
+			}
 			break;
 		case MH_MIDNIGHT_FRENZY:
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)
-				|| !hd->homunculus.spiritball) return true;
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_FIGHTER, 0);
+				return true;
+			}
+			if (!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MH_SILVERVEIN_RUSH);
+				return true;
+			}
 			break;
 		case MH_CBC:
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)
-				|| hd->homunculus.spiritball < 2) return true;
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_GRAPPLER, 0);
+				return true;
+			}
+			if (!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MH_TINDER_BREAKER);
+				return true;
+			}
 			break;
 		case MH_EQC:
-			if(!&hd->sc
-				|| !(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)
-				|| hd->homunculus.spiritball < 3) return true;
+			if (!(sc && sc->data[SC_STYLE_CHANGE] && sc->data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_STYLE_CHANGE_GRAPPLER, 0);
+				return true;
+			}
+			if (!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MH_CBC)) {
+				clif_skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MH_CBC);
+				return true;
+			}
 			break;
 	}
+	if (spiritball) {
+		if (hd->homunculus.spiritball < spiritball) {
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_SPIRITS, spiritball);
+			return true;
+		}
+		hom_delspiritball(hd, spiritball, 1);
+	}
 
 	//Use master's criteria.
 	return skill_isNotOk(skill_id, hd->master);
@@ -3747,7 +3804,7 @@ static int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16
  * &1: finished casting the skill (invoke hp/sp/item consumption)
  * &2: picked menu entry (Warp Portal, Teleport and other menu based skills)
  *------------------------------------------*/
-static int skill_check_condition_mercenary(struct block_list *bl, int skill, int lv, int type)
+static int skill_check_condition_mercenary(struct block_list *bl, uint16 skill_id, uint16 skill_lv, int type)
 {
 	struct status_data *status;
 	struct map_session_data *sd = NULL;
@@ -3755,7 +3812,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 	uint16 idx;
 	int itemid[MAX_SKILL_ITEM_REQUIRE],amount[ARRAYLENGTH(itemid)],index[ARRAYLENGTH(itemid)];
 
-	nullpo_ret(bl);
+	nullpo_retr(0, bl);
 
 	switch( bl->type )
 	{
@@ -3764,10 +3821,11 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 	}
 
 	status = status_get_status_data(bl);
-	if( (idx = skill_get_index(skill)) == 0 )
+
+	if ((idx = skill_get_index(skill_id)) == 0)
 		return 0;
 
-	lv = cap_value(lv, 1, MAX_SKILL_LEVEL);
+	skill_lv = cap_value(skill_lv, 1, MAX_SKILL_LEVEL);
 
 	// Requirements
 	for( i = 0; i < ARRAYLENGTH(itemid); i++ )
@@ -3775,12 +3833,12 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 		itemid[i] = skill_db[idx]->require.itemid[i];
 		amount[i] = skill_db[idx]->require.amount[i];
 	}
-	hp = skill_db[idx]->require.hp[lv-1];
-	sp = skill_db[idx]->require.sp[lv-1];
-	hp_rate = skill_db[idx]->require.hp_rate[lv-1];
-	sp_rate = skill_db[idx]->require.sp_rate[lv-1];
+	hp = skill_db[idx]->require.hp[skill_lv - 1];
+	sp = skill_db[idx]->require.sp[skill_lv - 1];
+	hp_rate = skill_db[idx]->require.hp_rate[skill_lv - 1];
+	sp_rate = skill_db[idx]->require.sp_rate[skill_lv - 1];
 	state = skill_db[idx]->require.state;
-	if( (mhp = skill_db[idx]->require.mhp[lv-1]) > 0 )
+	if ((mhp = skill_db[idx]->require.mhp[skill_lv - 1]) > 0)
 		hp += (status->max_hp * mhp) / 100;
 	if( hp_rate > 0 )
 		hp += (status->hp * hp_rate) / 100;
@@ -3791,32 +3849,16 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 	else
 		sp += (status->max_sp * (-sp_rate)) / 100;
 
-	if( bl->type == BL_HOM )
-	{ // Intimacy Requeriments
-		struct homun_data *hd = BL_CAST(BL_HOM, bl);
-		switch( skill )
-		{
-			case HFLI_SBR44:
-				if( hd->homunculus.intimacy <= 200 ) // hom_intimacy_grade2intimacy(HOMGRADE_HATE_WITH_PASSION)
-					return 0;
-				break;
-			case HVAN_EXPLOSION:
-				if( hd->homunculus.intimacy < (unsigned int)battle_config.hvan_explosion_intimate )
-					return 0;
-				break;
-		}
-	}
-
 	if( !(type&2) )
 	{
 		if( hp > 0 && status->hp <= (unsigned int)hp )
 		{
-			clif_skill_fail(sd, skill, USESKILL_FAIL_HP_INSUFFICIENT, 0);
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_HP_INSUFFICIENT, 0);
 			return 0;
 		}
 		if( sp > 0 && status->sp <= (unsigned int)sp )
 		{
-			clif_skill_fail(sd, skill, USESKILL_FAIL_SP_INSUFFICIENT, 0);
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0);
 			return 0;
 		}
 	}
@@ -3827,7 +3869,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 			case ST_MOVE_ENABLE:
 				if( !unit_can_move(bl) )
 				{
-					clif_skill_fail(sd, skill, USESKILL_FAIL_LEVEL, 0);
+					clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
 					return 0;
 				}
 				break;
@@ -3843,7 +3885,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 		index[i] = pc_search_inventory(sd, itemid[i]);
 		if( index[i] < 0 || sd->inventory.u.items_inventory[index[i]].amount < amount[i] )
 		{
-			clif_skill_fail(sd, skill, USESKILL_FAIL_LEVEL, 0);
+			clif_skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0);
 			return 0;
 		}
 	}
@@ -5837,15 +5879,7 @@ 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:
-		{
-			TBL_HOM *hd = BL_CAST(BL_HOM,src);
-			skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
-			hom_delspiritball(hd,skill_id==MH_SILVERVEIN_RUSH?1:2,0);
-		}
+		skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag);
 		break;
 	case MH_TINDER_BREAKER:
 	case MH_CBC:
@@ -5858,10 +5892,12 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
 			if (skill_id == MH_TINDER_BREAKER && unit_movepos(src, bl->x, bl->y, 1, 1)) {
 				clif_blown(src);
 				clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick);
+			} else if (skill_id == MH_EQC && status_bl_has_mode(bl, MD_STATUS_IMMUNE)) {
+				clif_skill_fail(hd->master, skill_id, USESKILL_FAIL_TOTARGET, 0);
+				break;
 			}
 			clif_skill_nodamage(src,bl,skill_id,skill_lv,
 				sc_start4(src,bl,status_skill2sc(skill_id),100,skill_lv,src->id,0,0,duration));
-			hom_delspiritball(hd,skill_id==MH_EQC?3:2,0); //only EQC consume 3 in grp 2
 			skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
 		}
 		break;
@@ -10612,11 +10648,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			if((sce=hd->sc.data[SC_STYLE_CHANGE])!=NULL){ //in preparation for other bl usage
 				if(sce->val1 == MH_MD_FIGHTING) sce->val1 = MH_MD_GRAPPLING;
 				else sce->val1 = MH_MD_FIGHTING;
-				if(hd->master && hd->sc.data[SC_STYLE_CHANGE]) {
-					char output[128];
-					safesnprintf(output,sizeof(output),msg_txt(sd,378),(sce->val1==MH_MD_FIGHTING?"fighthing":"grappling"));
-					clif_messagecolor(&hd->master->bl, color_table[COLOR_RED], output, false, SELF);
-				}
+				//if(hd->master && hd->sc.data[SC_STYLE_CHANGE]) { // Aegis does not show any message when switching fighting style
+				//	char output[128];
+				//	safesnprintf(output,sizeof(output),msg_txt(sd,378),(sce->val1==MH_MD_FIGHTING?"fighthing":"grappling"));
+				//	clif_messagecolor(&hd->master->bl, color_table[COLOR_RED], output, false, SELF);
+				//}
 			}
 			else sc_start(&hd->bl,&hd->bl, SC_STYLE_CHANGE, 100, MH_MD_FIGHTING, -1);
 		}

+ 1 - 1
src/map/skill.h

@@ -498,7 +498,7 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce
 // Abnormal status
 void skill_enchant_elemental_end(struct block_list *bl, int type);
 bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd);
-bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd);
+bool skill_isNotOk_hom(struct homun_data *hd, uint16 skill_id, uint16 skill_lv);
 bool skill_isNotOk_mercenary(uint16 skill_id, struct mercenary_data *md);
 
 bool skill_isNotOk_npcRange(struct block_list *src, uint16 skill_id, uint16 skill_lv, int pos_x, int pos_y);