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!
This commit is contained in:
Aleos
2017-04-25 13:33:05 -04:00
committed by GitHub
parent f1af3210d6
commit 452d9c60eb
5 changed files with 115 additions and 79 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
if (hom_get_intimacy_grade(hd) < HOMGRADE_CORDIAL) {
if (hd->master)
clif_skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
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 MH_GOLDENE_FERSE: //cant be used with angriff
if(&hd->sc && hd->sc.data[SC_ANGRIFFS_MODUS]) return true;
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) {
clif_skill_fail(sd, skill_id, USESKILL_FAIL_RELATIONGRADE, 0);
return true;
}
break;
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);
}

View File

@@ -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);