Fixes reflected damage from overflowing (#6717)

* Fixes #6693.
* Reflected damage should never be negative.
* Reflect Damage no longer has a 'reflect counter'.
* Reflect Damage is removed on log out.
* Reflect Damage Reduction should only reduce in normal cases (outside of WoE/BG).
* Adjusts the variable names to better match their use.
* General cleanups to speed up certain scenarios.
Thanks to @kaninhot004 and @Lemongrass3110's review!
This commit is contained in:
Aleos
2022-05-19 12:24:34 -04:00
committed by GitHub
parent 2726770c1c
commit 33a99b5993
3 changed files with 56 additions and 60 deletions

View File

@@ -3727,6 +3727,7 @@ Body:
NoDispell: true
NoBanishingBuster: true
RequireShield: true
NoSave: true
End:
Reflectshield: true
- Status: Forceofvanguard

View File

@@ -8266,100 +8266,96 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl
* Initial refactoring by Baalberith
* Refined and optimized by helvetica
*/
int64 battle_calc_return_damage(struct block_list* bl, struct block_list *src, int64 *dmg, int flag, uint16 skill_id, bool status_reflect){
struct map_session_data* sd;
int64 battle_calc_return_damage(struct block_list* tbl, struct block_list *src, int64 *dmg, int flag, uint16 skill_id, bool status_reflect){
status_change *tsc = status_get_sc(tbl);
if (tsc) { // These statuses do not reflect any damage (off the target)
if (tsc->data[SC_WHITEIMPRISON] || tsc->data[SC_DARKCROW] || tsc->data[SC_KYOMU])
return 0;
}
status_change *sc = status_get_sc(src);
if (sc) {
if (sc->data[SC_HELLS_PLANT])
return 0;
if (sc->data[SC_REF_T_POTION])
return 1; // Returns 1 damage
}
map_session_data *tsd = BL_CAST(BL_PC, tbl);
int64 rdamage = 0, damage = *dmg;
int max_damage = status_get_max_hp(bl);
struct status_change *sc, *ssc;
sd = BL_CAST(BL_PC, bl);
sc = status_get_sc(bl);
ssc = status_get_sc(src);
if (sc) { // These statuses do not reflect any damage (off the target)
if (sc->data[SC_WHITEIMPRISON] || sc->data[SC_DARKCROW] || sc->data[SC_KYOMU])
return 0;
}
if (ssc) {
if (ssc->data[SC_HELLS_PLANT])
return 0;
}
if (flag & BF_SHORT) {//Bounces back part of the damage.
if ( (skill_get_inf2(skill_id, INF2_ISTRAP) || !status_reflect) && sd && sd->bonus.short_weapon_damage_return ) {
rdamage += damage * sd->bonus.short_weapon_damage_return / 100;
if ( (skill_get_inf2(skill_id, INF2_ISTRAP) || !status_reflect) && tsd && tsd->bonus.short_weapon_damage_return ) {
rdamage += damage * tsd->bonus.short_weapon_damage_return / 100;
rdamage = i64max(rdamage, 1);
} else if( status_reflect && sc && sc->count ) {
if( sc->data[SC_REFLECTSHIELD] ) {
struct status_change_entry *sce_d;
struct block_list *d_bl = NULL;
} else if( status_reflect && tsc && tsc->count ) {
if( tsc->data[SC_REFLECTSHIELD] ) {
status_change_entry *sce_d;
block_list *d_bl;
if( (sce_d = sc->data[SC_DEVOTION]) && (d_bl = map_id2bl(sce_d->val1)) &&
((d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == bl->id) ||
(d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce_d->val2] == bl->id)) )
if( (sce_d = tsc->data[SC_DEVOTION]) && (d_bl = map_id2bl(sce_d->val1)) &&
((d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == tbl->id) ||
(d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce_d->val2] == tbl->id)) )
{ //Don't reflect non-skill attack if has SC_REFLECTSHIELD from Devotion bonus inheritance
if( (!skill_id && battle_config.devotion_rdamage_skill_only && sc->data[SC_REFLECTSHIELD]->val4) ||
!check_distance_bl(bl,d_bl,sce_d->val3) )
if( (!skill_id && battle_config.devotion_rdamage_skill_only && tsc->data[SC_REFLECTSHIELD]->val4) ||
!check_distance_bl(tbl,d_bl,sce_d->val3) )
return 0;
}
}
if ( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
if ( tsc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) {
// Don't reflect non-skill attack if has SC_REFLECTSHIELD from Devotion bonus inheritance
if (!skill_id && battle_config.devotion_rdamage_skill_only && sc->data[SC_REFLECTSHIELD]->val4)
if (!skill_id && battle_config.devotion_rdamage_skill_only && tsc->data[SC_REFLECTSHIELD]->val4)
rdamage = 0;
else {
rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
rdamage += damage * tsc->data[SC_REFLECTSHIELD]->val2 / 100;
rdamage = i64max(rdamage, 1);
}
}
if (sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && skill_id != GN_HELLS_PLANT_ATK && !status_bl_has_mode(src,MD_STATUSIMMUNE)) {
if (distance_bl(src,bl) <= 0 || !map_check_dir(map_calc_dir(bl,src->x,src->y), unit_getdir(bl))) {
int64 rd1 = i64min(damage, status_get_max_hp(bl)) * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage.
if (tsc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && skill_id != GN_HELLS_PLANT_ATK && !status_bl_has_mode(src,MD_STATUSIMMUNE)) {
if (distance_bl(src,tbl) <= 0 || !map_check_dir(map_calc_dir(tbl,src->x,src->y), unit_getdir(tbl))) {
int64 rd1 = i64min(damage, status_get_max_hp(tbl)) * tsc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage.
*dmg = rd1 * 30 / 100; // Received damage = 30% of amplified damage.
clif_skill_damage(src, bl, gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, DMG_SINGLE);
skill_blown(bl, src, skill_get_blewcount(RK_DEATHBOUND, 1), unit_getdir(src), BLOWN_NONE);
status_change_end(bl, SC_DEATHBOUND, INVALID_TIMER);
clif_skill_damage(src, tbl, gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, tsc->data[SC_DEATHBOUND]->val1, DMG_SINGLE);
skill_blown(tbl, src, skill_get_blewcount(RK_DEATHBOUND, tsc->data[SC_DEATHBOUND]->val1), unit_getdir(src), BLOWN_NONE);
status_change_end(tbl, SC_DEATHBOUND, INVALID_TIMER);
rdamage += rd1 * 70 / 100; // Target receives 70% of the amplified damage. [Rytech]
}
}
}
} else {
if (!status_reflect && sd && sd->bonus.long_weapon_damage_return) {
rdamage += damage * sd->bonus.long_weapon_damage_return / 100;
if (!status_reflect && tsd && tsd->bonus.long_weapon_damage_return) {
rdamage += damage * tsd->bonus.long_weapon_damage_return / 100;
rdamage = i64max(rdamage, 1);
}
}
if (rdamage > 0) {
map_session_data* ssd = BL_CAST(BL_PC, src);
if (ssd && ssd->bonus.reduce_damage_return != 0) {
rdamage -= rdamage * ssd->bonus.reduce_damage_return / 100;
map_session_data* sd = BL_CAST(BL_PC, src);
if (sd && sd->bonus.reduce_damage_return != 0) {
rdamage -= rdamage * sd->bonus.reduce_damage_return / 100;
rdamage = i64max(rdamage, 1);
}
}
if (ssc) {
if (ssc->data[SC_REFLECTDAMAGE]) {
rdamage -= damage * ssc->data[SC_REFLECTDAMAGE]->val2 / 100;
if (--(ssc->data[SC_REFLECTDAMAGE]->val3) < 1) // TODO: Confirm if reflect count still exists
status_change_end(bl, SC_REFLECTDAMAGE, INVALID_TIMER);
}
if (ssc->data[SC_VENOMBLEED] && ssc->data[SC_VENOMBLEED]->val3 == 0)
rdamage -= damage * ssc->data[SC_VENOMBLEED]->val2 / 100;
if (rdamage > 0 && ssc->data[SC_REF_T_POTION])
return 1; // Returns 1 damage
}
if (sc) {
if (sc->data[SC_MAXPAIN])
rdamage = damage * sc->data[SC_MAXPAIN]->val1 * 10 / 100;
if (status_reflect && sc->data[SC_REFLECTDAMAGE])
rdamage -= damage * sc->data[SC_REFLECTDAMAGE]->val2 / 100;
if (sc->data[SC_VENOMBLEED] && sc->data[SC_VENOMBLEED]->val3 == 0)
rdamage -= damage * sc->data[SC_VENOMBLEED]->val2 / 100;
rdamage = i64max(rdamage, 1);
}
return cap_value(i64min(rdamage,max_damage),INT_MIN,INT_MAX);
if (tsc) {
if (tsc->data[SC_MAXPAIN])
rdamage = damage * tsc->data[SC_MAXPAIN]->val1 * 10 / 100;
}
return cap_value(rdamage, 1, status_get_max_hp(tbl));
}
/**

View File

@@ -11079,7 +11079,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break;
case SC_REFLECTDAMAGE:
val2 = 10 * val1; // Reflect reduction amount
val3 = val1*5 + 25; // Number of reflects
val4 = tick/1000; // Number of SP cycles (duration)
tick_time = 1000; // [GodLesZ] tick time
break;