Skip to content

Commit

Permalink
Coma Rework, Exp Calc Type, Fiber Lock Range (#8287)
Browse files Browse the repository at this point in the history
- Coma item bonus is no longer an additional effect / status change, but instead replaces the attack damage with setting HP/SP to 1
  * That means Coma attacks will never kill someone, even if the original attack would be lethal
  * When doing a Coma attack, the attack displays the original damage and this is also what counts towards the mob damage log
- Coma is checked for every single event that applies damage, including reflect damage, and for Provoke / Self Provoke
  * Some Renewal-only effects couldn't be tested and were left unchanged (e.g. damage from White Imprison)
- Coma now sets SP to 1 instead of 0
- bComaRace, bWeaponComaRace and bWeaponComaEle won't work on bosses, GVG and battlefield objects
- bComaClass and bWeaponComaClass no longer work on GVG and battlefield objects, but can work on bosses if you specify Class_Boss or Class_All
- Edge is now defined to only work on normal monster
- The default exp_calc_type 0 no longer counts the first attacker twice and instead works like on official servers
- Added a new exp_calc_type 2 that counts the first attacker twice as previously
- The damage logged will now include overkill damage on exp_calc_type 0 and 2, but not count Coma damage (it will count the damage you would have originally dealt instead)
- Fiber Lock now has a range of 9 instead of 7
- Fixes #8279
  • Loading branch information
Playtester committed May 1, 2024
1 parent 9e959f7 commit cad5cab
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 61 deletions.
3 changes: 1 addition & 2 deletions conf/battle/exp.conf
Expand Up @@ -33,8 +33,7 @@ max_exp_gain_rate: 0
// Method of calculating earned experience when defeating a monster:
// 0 = uses damage given / total damage as damage ratio
// 1 = uses damage given / max_hp as damage ratio
// NOTE: Using type 1 disables the bonus where the first attacker gets
// his share of the exp doubled when multiple people attack the mob.
// 2 = 0 + first attacker counts twice
exp_calc_type: 0

// Experience increase per attacker. That is, every additional attacker to the
Expand Down
2 changes: 1 addition & 1 deletion db/pre-re/skill_db.yml
Expand Up @@ -11062,7 +11062,7 @@ Body:
TargetType: Attack
DamageFlags:
NoDamage: true
Range: 7
Range: 9
Hit: Single
HitCount: 1
ActiveInstance: 3
Expand Down
2 changes: 1 addition & 1 deletion db/re/item_db_equip.yml
Expand Up @@ -948,7 +948,7 @@ Body:
Refineable: true
Script: |
bonus2 bAddEff,Eff_Curse,30;
bonus2 bComaClass,Class_All,10;
bonus2 bComaClass,Class_Normal,10;
- Id: 1133
AegisName: Fire_Brand
Name: Fireblend
Expand Down
2 changes: 1 addition & 1 deletion db/re/skill_db.yml
Expand Up @@ -11312,7 +11312,7 @@ Body:
TargetType: Attack
DamageFlags:
NoDamage: true
Range: 7
Range: 9
Hit: Single
HitCount: 1
ActiveInstance: 3
Expand Down
76 changes: 58 additions & 18 deletions src/map/battle.cpp
Expand Up @@ -34,6 +34,8 @@
#include "pc_groups.hpp"
#include "pet.hpp"

using namespace rathena;

struct Battle_Config battle_config;
static struct eri *delay_damage_ers; //For battle delay damage structures.

Expand Down Expand Up @@ -254,33 +256,42 @@ struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int
return bl_list[rnd()%c];
}

/*========================================== [Playtester]
/**
* Deals damage without delay, applies additional effects and triggers monster events
* This function is called from battle_delay_damage or battle_delay_damage_sub
* All other instances of battle damage should also go through this function (i.e. anything that displays a damage number)
* Consider calling this function or battle_fix_damage instead status_fix_damage directly
* @param src: Source of damage
* @param target: Target of damage
* @param damage: Damage to be dealt
* @param delay: Damage delay
* @param skill_lv: Level of skill used
* @param skill_id: ID o skill used
* @param skill_id: ID of skill used
* @param dmg_lv: State of the attack (miss, etc.)
* @param attack_type: Type of the attack (BF_NORMAL|BF_SKILL|BF_SHORT|BF_LONG|BF_WEAPON|BF_MAGIC|BF_MISC)
* @param additional_effects: Whether additional effect should be applied
* @param additional_effects: Whether additional effects should be applied (otherwise it's just damage+coma)
* @param isspdamage: If the damage is done to SP
* @param tick: Current tick
*------------------------------------------*/
void battle_damage(struct block_list *src, struct block_list *target, int64 damage, t_tick delay, uint16 skill_lv, uint16 skill_id, enum damage_lv dmg_lv, unsigned short attack_type, bool additional_effects, t_tick tick, bool isspdamage) {
* @return HP+SP+AP (0 if HP/SP/AP remained unchanged)
*/
int battle_damage(struct block_list *src, struct block_list *target, int64 damage, t_tick delay, uint16 skill_lv, uint16 skill_id, enum damage_lv dmg_lv, unsigned short attack_type, bool additional_effects, t_tick tick, bool isspdamage) {
int dmg_change;
map_session_data* sd = nullptr;
if (src)
sd = BL_CAST(BL_PC, src);
map_freeblock_lock();
if (isspdamage)
status_fix_spdamage(src, target, damage, delay, skill_id);
dmg_change = status_fix_spdamage(src, target, damage, delay, skill_id);
else if (sd && battle_check_coma(*sd, *target, (e_battle_flag)attack_type))
dmg_change = status_damage(src, target, damage, 0, delay, 16, skill_id); // Coma attack
else
status_fix_damage(src, target, damage, delay, skill_id); // We have to separate here between reflect damage and others [icescope]
dmg_change = status_fix_damage(src, target, damage, delay, skill_id);
if (attack_type && !status_isdead(target) && additional_effects)
skill_additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, tick);
if (dmg_lv > ATK_BLOCK && attack_type)
if (dmg_lv > ATK_BLOCK && attack_type && additional_effects)
skill_counter_additional_effect(src, target, skill_id, skill_lv, attack_type, tick);
// This is the last place where we have access to the actual damage type, so any monster events depending on type must be placed here
if (target->type == BL_MOB) {
if (target->type == BL_MOB && additional_effects) {
mob_data *md = BL_CAST(BL_MOB, target);

if (md != nullptr) {
Expand All @@ -298,6 +309,7 @@ void battle_damage(struct block_list *src, struct block_list *target, int64 dama
}
}
map_freeblock_unlock();
return dmg_change;
}

/// Damage Delayed Structure
Expand Down Expand Up @@ -331,9 +343,7 @@ TIMER_FUNC(battle_delay_damage_sub){
//Deal damage
battle_damage(src, target, dat->damage, dat->delay, dat->skill_lv, dat->skill_id, dat->dmg_lv, dat->attack_type, dat->additional_effects, tick, dat->isspdamage);
} else if( !src && dat->skill_id == CR_REFLECTSHIELD ) { // it was monster reflected damage, and the monster died, we pass the damage to the character as expected
map_freeblock_lock();
status_fix_damage(target, target, dat->damage, dat->delay, dat->skill_id);
map_freeblock_unlock();
battle_fix_damage(target, target, dat->damage, dat->delay, dat->skill_id);
}
}

Expand Down Expand Up @@ -6956,7 +6966,7 @@ static void battle_calc_weapon_final_atk_modifiers(struct Damage* wd, struct blo
{
ATK_RATER(wd->damage, 50)
clif_skill_nodamage(target,target,ST_REJECTSWORD, tsc->getSCE(SC_REJECTSWORD)->val1,1);
status_fix_damage(target,src,wd->damage,clif_damage(target,src,gettick(),0,0,wd->damage,0,DMG_NORMAL,0,false),ST_REJECTSWORD);
battle_fix_damage(target,src,wd->damage,clif_damage(target,src,gettick(),0,0,wd->damage,0,DMG_NORMAL,0,false),ST_REJECTSWORD);
if (status_isdead(target))
return;
if( --(tsc->getSCE(SC_REJECTSWORD)->val3) <= 0 )
Expand All @@ -6974,7 +6984,7 @@ static void battle_calc_weapon_final_atk_modifiers(struct Damage* wd, struct blo
clif_skill_damage(target, src, gettick(), status_get_amotion(src), 0, rdamage,
1, SR_CRESCENTELBOW_AUTOSPELL, tsc->getSCE(SC_CRESCENTELBOW)->val1, DMG_SINGLE); // This is how official does
clif_damage(src, target, gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, DMG_NORMAL, 0, false);
status_damage(target, src, rdamage, 0, 0, 0, 0);
battle_fix_damage(target, src, rdamage, 0, SR_CRESCENTELBOW);
status_damage(src, target, rdamage/10, 0, 0, 1, 0);
status_change_end(target, SC_CRESCENTELBOW);
}
Expand Down Expand Up @@ -9515,6 +9525,36 @@ int64 battle_calc_return_damage(struct block_list* tbl, struct block_list *src,
return cap_value(rdamage, 1, status_get_max_hp(tbl));
}

/** Check for Coma damage
* @param sd: Source player
* @param bl: Target
* @param attack_type: Attack type
* @return True if Coma applies, false if Coma does not apply
*/
bool battle_check_coma(map_session_data& sd, struct block_list& target, e_battle_flag attack_type)
{
struct status_data* tstatus = status_get_status_data(&target);
mob_data* dstmd = BL_CAST(BL_MOB, &target);

// Coma
if (sd.special_state.bonus_coma && (!dstmd || (!util::vector_exists(status_get_race2(&dstmd->bl), RC2_GVG) && status_get_class(&dstmd->bl) != CLASS_BATTLEFIELD))) {
int rate = 0;
rate += sd.indexed_bonus.coma_class[tstatus->class_] + sd.indexed_bonus.coma_class[CLASS_ALL];
if(!status_bl_has_mode(&target, MD_STATUSIMMUNE))
rate += sd.indexed_bonus.coma_race[tstatus->race] + sd.indexed_bonus.coma_race[RC_ALL];
if (attack_type&BF_WEAPON) {
rate += sd.indexed_bonus.weapon_coma_class[tstatus->class_] + sd.indexed_bonus.weapon_coma_class[CLASS_ALL];
if (!status_bl_has_mode(&target, MD_STATUSIMMUNE)) {
rate += sd.indexed_bonus.weapon_coma_ele[tstatus->def_ele] + sd.indexed_bonus.weapon_coma_ele[ELE_ALL];
rate += sd.indexed_bonus.weapon_coma_race[tstatus->race] + sd.indexed_bonus.weapon_coma_race[RC_ALL];
}
}
if (rate > 0 && rnd_chance(rate, 10000))
return true;
}
return false;
}

/**
* Calculate Vellum damage on a target
* @param sd: Player with vanish item
Expand Down Expand Up @@ -9649,7 +9689,7 @@ int battle_damage_area(struct block_list *bl, va_list ap) {
if( amotion )
battle_delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true,false);
else
status_fix_damage(src,bl,damage,0,LG_REFLECTDAMAGE);
battle_fix_damage(src,bl,damage,0,LG_REFLECTDAMAGE);
clif_damage(bl,bl,tick,amotion,dmotion,damage,1,DMG_ENDURE,0,false);
skill_additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
map_freeblock_unlock();
Expand Down Expand Up @@ -10016,7 +10056,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
devotion_damage -= devotion_damage * d_sc->getSCE(SC_REBOUND_S)->val2 / 100;

clif_damage(d_bl, d_bl, gettick(), wd.amotion, wd.dmotion, devotion_damage, 1, DMG_NORMAL, 0, false);
status_fix_damage(NULL, d_bl, devotion_damage, 0, CR_DEVOTION);
battle_fix_damage(src, d_bl, devotion_damage, 0, CR_DEVOTION);
}
}
else
Expand All @@ -10035,7 +10075,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t

if (e_bl && !status_isdead(e_bl)) {
clif_damage(e_bl, e_bl, tick, 0, 0, damage, wd.div_, DMG_NORMAL, 0, false);
status_fix_damage(NULL, e_bl, damage, 0, EL_WATER_SCREEN);
battle_fix_damage(src, e_bl, damage, 0, EL_WATER_SCREEN);
}
}
}
Expand Down Expand Up @@ -11103,7 +11143,7 @@ static const struct _battle_data {
{ "skill_steal_random_options", &battle_config.skill_steal_random_options, 0, 0, 1, },
{ "motd_type", &battle_config.motd_type, 0, 0, 1, },
{ "finding_ore_rate", &battle_config.finding_ore_rate, 100, 0, INT_MAX, },
{ "exp_calc_type", &battle_config.exp_calc_type, 0, 0, 1, },
{ "exp_calc_type", &battle_config.exp_calc_type, 0, 0, 2, },
{ "exp_bonus_attacker", &battle_config.exp_bonus_attacker, 25, 0, INT_MAX, },
{ "exp_bonus_max_attacker", &battle_config.exp_bonus_max_attacker, 12, 2, INT_MAX, },
{ "min_skill_delay_limit", &battle_config.min_skill_delay_limit, 100, 10, INT_MAX, },
Expand Down
6 changes: 5 additions & 1 deletion src/map/battle.hpp
Expand Up @@ -122,8 +122,11 @@ int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64
int64 battle_calc_bg_damage(struct block_list *src,struct block_list *bl,int64 damage,uint16 skill_id,int flag);
int64 battle_calc_pk_damage(block_list &src, block_list &bl, int64 damage, uint16 skill_id, int flag);

void battle_damage(struct block_list *src, struct block_list *target, int64 damage, t_tick delay, uint16 skill_lv, uint16 skill_id, enum damage_lv dmg_lv, unsigned short attack_type, bool additional_effects, t_tick tick, bool spdamage);
int battle_damage(struct block_list *src, struct block_list *target, int64 damage, t_tick delay, uint16 skill_lv, uint16 skill_id, enum damage_lv dmg_lv, unsigned short attack_type, bool additional_effects, t_tick tick, bool spdamage);
int battle_delay_damage (t_tick tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, t_tick ddelay, bool additional_effects, bool spdamage);
static int battle_fix_damage(struct block_list* src, struct block_list* target, int64 damage, t_tick walkdelay, uint16 skill_id) {
return battle_damage(src, target, damage, walkdelay, 0, skill_id, ATK_DEF, BF_MISC, false, gettick(), false);
}

int battle_calc_chorusbonus(map_session_data *sd);

Expand All @@ -140,6 +143,7 @@ uint16 battle_getcurrentskill(struct block_list *bl);
int battle_check_undead(int race,int element);
int battle_check_target(struct block_list *src, struct block_list *target,int flag);
bool battle_check_range(struct block_list *src,struct block_list *bl,int range);
bool battle_check_coma(map_session_data& sd, struct block_list& target, e_battle_flag attack_type);

void battle_consume_ammo(map_session_data* sd, int skill, int lv);

Expand Down
17 changes: 9 additions & 8 deletions src/map/mob.cpp
Expand Up @@ -2631,8 +2631,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
// determines if the monster was killed by mercenary damage only
merckillonly = (bool)((dmgbltypes & BL_MER) && !(dmgbltypes & ~BL_MER));

if(!battle_config.exp_calc_type && count > 1) { //Apply first-attacker 200% exp share bonus
//TODO: Determine if this should go before calculating the MVP player instead of after.
if(battle_config.exp_calc_type == 2 && count > 1) { //Apply first-attacker 200% exp share bonus
if (UINT_MAX - md->dmglog[0].dmg > md->tdmg) {
md->tdmg += md->dmglog[0].dmg;
md->dmglog[0].dmg *= 2;
Expand Down Expand Up @@ -2675,14 +2674,16 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)

if (!tmpsd[i]) continue;

if (!battle_config.exp_calc_type && md->tdmg)
//jAthena's exp formula based on total damage.
per = (double)md->dmglog[i].dmg/(double)md->tdmg;
if (battle_config.exp_calc_type == 1 || md->tdmg == 0) {
// eAthena's exp formula based on max hp
per = (double)md->dmglog[i].dmg / (double)status->max_hp;
}
else {
//eAthena's exp formula based on max hp.
per = (double)md->dmglog[i].dmg/(double)status->max_hp;
if (per > 2) per = 2; // prevents unlimited exp gain
// Aegis's exp formula based on total damage
per = (double)md->dmglog[i].dmg / (double)md->tdmg;
}
// To prevent exploits
if (per > 1) per = 1;

//Exclude rebirth tap from this calculation
count -= md->state.rebirth;
Expand Down
41 changes: 14 additions & 27 deletions src/map/skill.cpp
Expand Up @@ -2222,23 +2222,6 @@ int skill_additional_effect( struct block_list* src, struct block_list *bl, uint
src = sd?&sd->bl:src;
}

// Coma
if (sd && sd->special_state.bonus_coma && (!md || util::vector_exists(status_get_race2(&md->bl), RC2_GVG) || status_get_class(&md->bl) != CLASS_BATTLEFIELD)) {
int rate = 0;
//! TODO: Filter the skills that shouldn't inflict coma bonus, to avoid some non-damage skills inflict coma. [Cydh]
if (!skill_id || !skill_get_nk(skill_id, NK_NODAMAGE)) {
rate += sd->indexed_bonus.coma_class[tstatus->class_] + sd->indexed_bonus.coma_class[CLASS_ALL];
rate += sd->indexed_bonus.coma_race[tstatus->race] + sd->indexed_bonus.coma_race[RC_ALL];
}
if (attack_type&BF_WEAPON) {
rate += sd->indexed_bonus.weapon_coma_ele[tstatus->def_ele] + sd->indexed_bonus.weapon_coma_ele[ELE_ALL];
rate += sd->indexed_bonus.weapon_coma_race[tstatus->race] + sd->indexed_bonus.weapon_coma_race[RC_ALL];
rate += sd->indexed_bonus.weapon_coma_class[tstatus->class_] + sd->indexed_bonus.weapon_coma_class[CLASS_ALL];
}
if (rate > 0)
status_change_start(src,bl, SC_COMA, rate, 0, 0, src->id, 0, 0, SCSTART_NONE);
}

if( attack_type&BF_WEAPON )
{ // Breaking Equipment
if( sd && battle_config.equip_self_break_rate )
Expand Down Expand Up @@ -3749,7 +3732,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
nbl = battle_getenemyarea(bl,bl->x,bl->y,2,BL_CHAR,bl->id);
if( nbl ){ // Only one target is chosen.
damage = damage / 2; // Deflect half of the damage to a target nearby
clif_skill_damage(bl, nbl, tick, status_get_amotion(src), 0, status_fix_damage(bl,nbl,damage,0,0), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, DMG_SINGLE);
clif_skill_damage(bl, nbl, tick, status_get_amotion(src), 0, battle_fix_damage(bl,nbl,damage,0,0), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, DMG_SINGLE);
}
}

Expand Down Expand Up @@ -3997,12 +3980,13 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *

// Instant damage
if( !dmg.amotion ) {
//Deal damage before knockback to allow stuff like firewall+storm gust combo.
if( (!tsc || (!tsc->getSCE(SC_DEVOTION) && skill_id != CR_REFLECTSHIELD && !tsc->getSCE(SC_WATER_SCREEN_OPTION))
#ifndef RENEWAL
|| skill_id == HW_GRAVITATION
#endif
|| skill_id == NPC_EVILLAND) && !shadow_flag )
status_fix_damage(src,bl,damage,dmg.dmotion,skill_id); //Deal damage before knockback to allow stuff like firewall+storm gust combo.
battle_damage(src, bl, damage, dmg.dmotion, skill_lv, skill_id, dmg.dmg_lv, dmg.flag, false, tick, false);
if( !status_isdead(bl) && additional_effects )
skill_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,dmg.dmg_lv,tick);
if( damage > 0 ) //Counter status effects [Skotlex]
Expand Down Expand Up @@ -4064,7 +4048,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *

if (!rmdamage) {
clif_damage(d_bl, d_bl, gettick(), 0, 0, devotion_damage, 0, DMG_NORMAL, 0, false);
status_fix_damage(NULL, d_bl, devotion_damage, 0, 0);
battle_fix_damage(src, d_bl, devotion_damage, 0, 0);
} else {
bool isDevotRdamage = false;

Expand All @@ -4074,12 +4058,12 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
// This check is only for magical skill.
// For BF_WEAPON skills types track var rdamage and function battle_calc_return_damage
clif_damage(bl, (!isDevotRdamage) ? bl : d_bl, gettick(), 0, 0, devotion_damage, 0, DMG_NORMAL, 0, false);
status_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, devotion_damage, 0, 0);
battle_fix_damage(bl, (!isDevotRdamage) ? bl : d_bl, devotion_damage, 0, 0);
}
} else {
status_change_end(bl, SC_DEVOTION);
if (!dmg.amotion)
status_fix_damage(src, bl, damage, dmg.dmotion, 0);
battle_fix_damage(src, bl, damage, dmg.dmotion, 0);
}
}
if (tsc->getSCE(SC_WATER_SCREEN_OPTION)) {
Expand All @@ -4089,10 +4073,10 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
if (e_bl) {
if (!rmdamage) {
clif_skill_damage(e_bl, e_bl, gettick(), 0, 0, damage, dmg.div_, skill_id, -1, skill_get_hit(skill_id));
status_fix_damage(NULL, e_bl, damage, 0, 0);
battle_fix_damage(src, e_bl, damage, 0, 0);
} else {
clif_skill_damage(bl, bl, gettick(), 0, 0, damage, dmg.div_, skill_id, -1, skill_get_hit(skill_id));
status_fix_damage(bl, bl, damage, 0, 0);
battle_fix_damage(bl, bl, damage, 0, 0);
}
}
}
Expand Down Expand Up @@ -5021,7 +5005,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
}
case 4: // THE CHARIOT - 1000 damage, random armor destroyed
{
status_fix_damage(src, target, 1000, 0, skill_id);
battle_fix_damage(src, target, 1000, 0, skill_id);
clif_damage(src, target, tick, 0, 0, 1000, 0, DMG_NORMAL, 0, false);
if (!status_isdead(target))
{
Expand Down Expand Up @@ -5075,7 +5059,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
}
case 11: // THE DEVIL - 6666 damage, atk and matk halved, cursed
{
status_fix_damage(src, target, 6666, 0, skill_id);
battle_fix_damage(src, target, 6666, 0, skill_id);
clif_damage(src, target, tick, 0, 0, 6666, 0, DMG_NORMAL, 0, false);
sc_start(src, target, SC_INCATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv));
sc_start(src, target, SC_INCMATKRATE, 100, -50, skill_get_time2(skill_id, skill_lv));
Expand All @@ -5084,7 +5068,7 @@ static int skill_tarotcard(struct block_list* src, struct block_list *target, ui
}
case 12: // THE TOWER - 4444 damage
{
status_fix_damage(src, target, 4444, 0, skill_id);
battle_fix_damage(src, target, 4444, 0, skill_id);
clif_damage(src, target, tick, 0, 0, 4444, 0, DMG_NORMAL, 0, false);
break;
}
Expand Down Expand Up @@ -8371,6 +8355,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
dstmd->state.provoke_flag = src->id;
mob_target(dstmd, src, skill_get_range2(src, skill_id, skill_lv, true));
}
// Provoke can cause Coma even though it's a nodamage skill
if (sd && battle_check_coma(*sd, *bl, BF_MISC))
status_change_start(src, bl, SC_COMA, 10000, skill_lv, 0, src->id, 0, 0, SCSTART_NONE);
break;

case ML_DEVOTION:
Expand Down

0 comments on commit cad5cab

Please sign in to comment.