Fix NPC_MAXPAIN skill mechanism (#5820)
* Max Pain will deal reflect damage to all characters on screen. * Caster of Max Pain will get damaged. * Max Pain will reflect both weapon and magic damage. * Max Pain damages as special physical melee attack. PR_KYRIE, MG_SAFETYWALL, etc. can block the damage. Co-authored-by: Aleos <aleos89@users.noreply.github.com> Co-authored-by: Daegaladh <Daegaladh@users.noreply.github.com>
This commit is contained in:
parent
73112801c6
commit
2896ae21b0
@ -17164,11 +17164,12 @@ Body:
|
|||||||
Name: NPC_MAXPAIN_ATK
|
Name: NPC_MAXPAIN_ATK
|
||||||
Description: Max Pain Attack
|
Description: Max Pain Attack
|
||||||
MaxLevel: 10
|
MaxLevel: 10
|
||||||
Type: Misc
|
Type: Weapon
|
||||||
TargetType: Attack
|
TargetType: Attack
|
||||||
DamageFlags:
|
DamageFlags:
|
||||||
Splash: true
|
Splash: true
|
||||||
IgnoreElement: true
|
IgnoreElement: true
|
||||||
|
IgnoreDefense: true
|
||||||
IgnoreFlee: true
|
IgnoreFlee: true
|
||||||
IgnoreDefCard: true
|
IgnoreDefCard: true
|
||||||
Flags:
|
Flags:
|
||||||
|
|||||||
@ -1450,9 +1450,6 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
|
|||||||
if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
|
if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (sc && sc->data[SC_MAXPAIN])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (skill_id) {
|
switch (skill_id) {
|
||||||
#ifndef RENEWAL
|
#ifndef RENEWAL
|
||||||
case PA_PRESSURE:
|
case PA_PRESSURE:
|
||||||
@ -2483,6 +2480,7 @@ static int battle_range_type(struct block_list *src, struct block_list *target,
|
|||||||
case MT_RUSH_QUAKE: // 9 cell cast range.
|
case MT_RUSH_QUAKE: // 9 cell cast range.
|
||||||
case ABC_UNLUCKY_RUSH: // 7 cell cast range.
|
case ABC_UNLUCKY_RUSH: // 7 cell cast range.
|
||||||
//case ABC_DEFT_STAB: // 2 cell cast range???
|
//case ABC_DEFT_STAB: // 2 cell cast range???
|
||||||
|
case NPC_MAXPAIN_ATK:
|
||||||
return BF_SHORT;
|
return BF_SHORT;
|
||||||
case CD_PETITIO: { // Skill range is 2 but damage is melee with books and ranged with mace.
|
case CD_PETITIO: { // Skill range is 2 but damage is melee with books and ranged with mace.
|
||||||
map_session_data *sd = BL_CAST(BL_PC, src);
|
map_session_data *sd = BL_CAST(BL_PC, src);
|
||||||
@ -6359,6 +6357,12 @@ void battle_do_reflect(int attack_type, struct Damage *wd, struct block_list* sr
|
|||||||
if (!tsc)
|
if (!tsc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (tsc->data[SC_MAXPAIN]) {
|
||||||
|
tsc->data[SC_MAXPAIN]->val2 = (int)damage;
|
||||||
|
if (!tsc->data[SC_KYOMU] && !(tsc->data[SC_DARKCROW] && (wd->flag&BF_SHORT))) //SC_KYOMU invalidates reflecting ability. SC_DARKCROW also does, but only for short weapon attack.
|
||||||
|
skill_castend_damage_id(target, src, NPC_MAXPAIN_ATK, tsc->data[SC_MAXPAIN]->val1, tick, ((wd->flag & 1) ? wd->flag - 1 : wd->flag));
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate skill reflect damage separately
|
// Calculate skill reflect damage separately
|
||||||
if ((ud && !ud->immune_attack) || !status_bl_has_mode(target, MD_SKILLIMMUNE))
|
if ((ud && !ud->immune_attack) || !status_bl_has_mode(target, MD_SKILLIMMUNE))
|
||||||
rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id,true);
|
rdamage = battle_calc_return_damage(target, src, &damage, wd->flag, skill_id,true);
|
||||||
@ -6368,12 +6372,7 @@ void battle_do_reflect(int attack_type, struct Damage *wd, struct block_list* sr
|
|||||||
|
|
||||||
if (sc && sc->data[SC_VITALITYACTIVATION])
|
if (sc && sc->data[SC_VITALITYACTIVATION])
|
||||||
rdamage /= 2;
|
rdamage /= 2;
|
||||||
if (tsc->data[SC_MAXPAIN]) {
|
if( attack_type == BF_WEAPON && tsc->data[SC_REFLECTDAMAGE] ) // Don't reflect your own damage (Grand Cross)
|
||||||
tsc->data[SC_MAXPAIN]->val2 = (int)rdamage;
|
|
||||||
skill_castend_damage_id(target, src, NPC_MAXPAIN_ATK, tsc->data[SC_MAXPAIN]->val1, tick, wd->flag);
|
|
||||||
tsc->data[SC_MAXPAIN]->val2 = 0;
|
|
||||||
}
|
|
||||||
else if( attack_type == BF_WEAPON && tsc->data[SC_REFLECTDAMAGE] ) // Don't reflect your own damage (Grand Cross)
|
|
||||||
map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd->amotion,sstatus->dmotion,rdamage,wd->flag);
|
map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd->amotion,sstatus->dmotion,rdamage,wd->flag);
|
||||||
else if( attack_type == BF_WEAPON || attack_type == BF_MISC) {
|
else if( attack_type == BF_WEAPON || attack_type == BF_MISC) {
|
||||||
rdelay = clif_damage(src, (!d_bl) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0, false);
|
rdelay = clif_damage(src, (!d_bl) ? src : d_bl, tick, wd->amotion, sstatus->dmotion, rdamage, 1, DMG_ENDURE, 0, false);
|
||||||
@ -6675,6 +6674,16 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
|
|||||||
case MH_EQC:
|
case MH_EQC:
|
||||||
ATK_ADD(wd.damage, wd.damage2, 6000 * skill_lv + status_get_lv(src)); // !TODO: Confirm base level bonus
|
ATK_ADD(wd.damage, wd.damage2, 6000 * skill_lv + status_get_lv(src)); // !TODO: Confirm base level bonus
|
||||||
break;
|
break;
|
||||||
|
case NPC_MAXPAIN_ATK:
|
||||||
|
if (sc && sc->data[SC_MAXPAIN]) {
|
||||||
|
if (sc->data[SC_MAXPAIN]->val2)
|
||||||
|
wd.damage = sc->data[SC_MAXPAIN]->val2 * skill_lv / 10;
|
||||||
|
else if (sc->data[SC_MAXPAIN]->val3)
|
||||||
|
wd.damage = sc->data[SC_MAXPAIN]->val3 * skill_lv / 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wd.damage = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sd) {
|
if(sd) {
|
||||||
@ -8149,12 +8158,6 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
|
|||||||
if (status_bl_has_mode(target, MD_STATUSIMMUNE))
|
if (status_bl_has_mode(target, MD_STATUSIMMUNE))
|
||||||
md.damage /= 10;
|
md.damage /= 10;
|
||||||
break;
|
break;
|
||||||
case NPC_MAXPAIN_ATK:
|
|
||||||
if (ssc && ssc->data[SC_MAXPAIN])
|
|
||||||
md.damage = ssc->data[SC_MAXPAIN]->val2;
|
|
||||||
else
|
|
||||||
md.damage = 0;
|
|
||||||
break;
|
|
||||||
case NPC_WIDESUCK:
|
case NPC_WIDESUCK:
|
||||||
md.damage = tstatus->max_hp * 15 / 100;
|
md.damage = tstatus->max_hp * 15 / 100;
|
||||||
break;
|
break;
|
||||||
@ -8425,7 +8428,7 @@ int64 battle_calc_return_damage(struct block_list* tbl, struct block_list *src,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( tsc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
|
if ( tsc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION && skill_id != NPC_MAXPAIN_ATK ) {
|
||||||
// Don't reflect non-skill attack if has SC_REFLECTSHIELD from Devotion bonus inheritance
|
// Don't reflect non-skill attack if has SC_REFLECTSHIELD from Devotion bonus inheritance
|
||||||
if (!skill_id && battle_config.devotion_rdamage_skill_only && tsc->data[SC_REFLECTSHIELD]->val4)
|
if (!skill_id && battle_config.devotion_rdamage_skill_only && tsc->data[SC_REFLECTSHIELD]->val4)
|
||||||
rdamage = 0;
|
rdamage = 0;
|
||||||
@ -8473,11 +8476,6 @@ int64 battle_calc_return_damage(struct block_list* tbl, struct block_list *src,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tsc) {
|
|
||||||
if (tsc->data[SC_MAXPAIN])
|
|
||||||
rdamage = damage * tsc->data[SC_MAXPAIN]->val1 * 10 / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config damage adjustment
|
// Config damage adjustment
|
||||||
map_data *mapdata = map_getmapdata(src->m);
|
map_data *mapdata = map_getmapdata(src->m);
|
||||||
|
|
||||||
|
|||||||
@ -3674,6 +3674,13 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
|
|||||||
|
|
||||||
damage = dmg.damage + dmg.damage2;
|
damage = dmg.damage + dmg.damage2;
|
||||||
|
|
||||||
|
if ((dmg.flag & BF_MAGIC) && tsc && tsc->data[SC_MAXPAIN]) {
|
||||||
|
tsc->data[SC_MAXPAIN]->val3 = (int)damage;
|
||||||
|
tsc->data[SC_MAXPAIN]->val2 = 0;
|
||||||
|
if (!tsc->data[SC_KYOMU]) //SC_KYOMU invalidates reflecting ability.
|
||||||
|
skill_castend_damage_id(bl, src, NPC_MAXPAIN_ATK, tsc->data[SC_MAXPAIN]->val1, tick, flag);
|
||||||
|
}
|
||||||
|
|
||||||
if( (skill_id == AL_INCAGI || skill_id == AL_BLESSING ||
|
if( (skill_id == AL_INCAGI || skill_id == AL_BLESSING ||
|
||||||
skill_id == CASH_BLESSING || skill_id == CASH_INCAGI ||
|
skill_id == CASH_BLESSING || skill_id == CASH_INCAGI ||
|
||||||
skill_id == MER_INCAGI || skill_id == MER_BLESSING) && tsc && tsc->data[SC_CHANGEUNDEAD] )
|
skill_id == MER_INCAGI || skill_id == MER_BLESSING) && tsc && tsc->data[SC_CHANGEUNDEAD] )
|
||||||
@ -7617,6 +7624,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|||||||
}
|
}
|
||||||
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
sc_start(src, bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv));
|
||||||
break;
|
break;
|
||||||
|
case CR_REFLECTSHIELD:
|
||||||
|
case MS_REFLECTSHIELD:
|
||||||
|
if (tsc && tsc->data[SC_DARKCROW]) { // SC_DARKCROW prevents using reflecting skills
|
||||||
|
if (sd)
|
||||||
|
clif_skill_fail(sd, skill_id, USESKILL_FAIL, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PR_SLOWPOISON:
|
case PR_SLOWPOISON:
|
||||||
case PR_LEXAETERNA:
|
case PR_LEXAETERNA:
|
||||||
#ifndef RENEWAL
|
#ifndef RENEWAL
|
||||||
@ -7629,8 +7643,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
|
|||||||
case KN_ONEHAND:
|
case KN_ONEHAND:
|
||||||
case MER_QUICKEN:
|
case MER_QUICKEN:
|
||||||
case CR_SPEARQUICKEN:
|
case CR_SPEARQUICKEN:
|
||||||
case CR_REFLECTSHIELD:
|
|
||||||
case MS_REFLECTSHIELD:
|
|
||||||
case AS_POISONREACT:
|
case AS_POISONREACT:
|
||||||
#ifndef RENEWAL
|
#ifndef RENEWAL
|
||||||
case MC_LOUD:
|
case MC_LOUD:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user