From 0395610469ffcd3b71c93ef90861f73e0ab8d16f Mon Sep 17 00:00:00 2001 From: malufett Date: Thu, 13 Jun 2013 01:56:21 +0800 Subject: Hercules Renewal Phase : Renewal Rename SC names to eagis standard. Implement SC Configuration.(see db/sc_config.txt) Skill updates and fixes. Some code optimization. Signed-off-by: malufett --- src/char/char.c | 2 + src/common/mmo.h | 2 +- src/config/const.h | 4 +- src/map/atcommand.c | 8 +- src/map/battle.c | 7521 +++++++++++++++++++++-------------------- src/map/battle.h | 22 +- src/map/clif.c | 181 +- src/map/clif.h | 12 +- src/map/itemdb.h | 3 + src/map/map.c | 58 +- src/map/mercenary.c | 2 +- src/map/mob.c | 10 +- src/map/packets.h | 1 + src/map/party.c | 2 +- src/map/pc.c | 258 +- src/map/pc.h | 18 +- src/map/script.c | 4 +- src/map/skill.c | 9261 +++++++++++++++++++++++++-------------------------- src/map/skill.h | 25 +- src/map/status.c | 2787 ++++++++-------- src/map/status.h | 770 +++-- src/map/unit.c | 63 +- src/map/vending.c | 2 +- 23 files changed, 10871 insertions(+), 10145 deletions(-) (limited to 'src') diff --git a/src/char/char.c b/src/char/char.c index f889c1a25..7dfb6861c 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2027,6 +2027,8 @@ static void char_auth_ok(int fd, struct char_session_data *sd) mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); if (character->waiting_disconnect == INVALID_TIMER) character->waiting_disconnect = iTimer->add_timer(iTimer->gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); + if (character) + character->pincode_enable = -1; WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x81; WFIFOB(fd,2) = 8; diff --git a/src/common/mmo.h b/src/common/mmo.h index c2fdfe43a..eaffdf7df 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -83,7 +83,7 @@ #define MAX_ZENY 1000000000 #define MAX_FAME 1000000000 #define MAX_CART 100 -#define MAX_SKILL 1477 +#define MAX_SKILL 1478 #define MAX_SKILL_ID 10015 // [Ind/Hercules] max used skill ID #define GLOBAL_REG_NUM 256 // Max permanent character variables per char #define ACCOUNT_REG_NUM 64 // Max permanent local account variables per account diff --git a/src/config/const.h b/src/config/const.h index 756c681c1..7acdea688 100644 --- a/src/config/const.h +++ b/src/config/const.h @@ -60,8 +60,8 @@ /* ATCMD_FUNC(mobinfo) HIT and FLEE calculations */ #ifdef RENEWAL - #define MOB_FLEE(mob) ( mob->lv + mob->status.agi + mob->status.luk/5 + 100 ) - #define MOB_HIT(mob) ( mob->lv + mob->status.dex + mob->status.luk/3 + 175 ) + #define MOB_FLEE(mob) ( mob->lv + mob->status.agi + 100 ) + #define MOB_HIT(mob) ( mob->lv + mob->status.dex + 150 ) #else #define MOB_FLEE(mob) ( mob->lv + mob->status.agi ) #define MOB_HIT(mob) ( mob->lv + mob->status.dex ) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index f96c7920a..d9810e77c 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -6148,7 +6148,7 @@ ACMD(npctalk) unsigned long color=0; if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -6199,7 +6199,7 @@ ACMD(pettalk) } if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -6965,7 +6965,7 @@ ACMD(homtalk) } if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -7348,7 +7348,7 @@ ACMD(me) memset(atcmd_output, '\0', sizeof(atcmd_output)); if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; diff --git a/src/map/battle.c b/src/map/battle.c index a2cc7692c..a4908982c 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -363,14 +363,14 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag if( tsc->data[SC_SPIDERWEB]->val2 == 0 ) status_change_end(target, SC_SPIDERWEB, INVALID_TIMER); } - if( tsc->data[SC_THORNSTRAP]) - status_change_end(target, SC_THORNSTRAP, INVALID_TIMER); + if( tsc->data[SC_THORNS_TRAP]) + status_change_end(target, SC_THORNS_TRAP, INVALID_TIMER); if( tsc->data[SC_FIRE_CLOAK_OPTION]) damage -= damage * tsc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100; if( tsc->data[SC_CRYSTALIZE] && target->type != BL_MOB) status_change_end(target, SC_CRYSTALIZE, INVALID_TIMER); if( tsc->data[SC_EARTH_INSIGNIA]) damage += damage/2; - if( tsc->data[SC_ASH]) damage += damage/2; //150% + if( tsc->data[SC_VOLCANIC_ASH]) damage += damage/2; //150% break; case ELE_HOLY: if( tsc->data[SC_ORATIO]) ratio += tsc->data[SC_ORATIO]->val1 * 2; @@ -394,1833 +394,1365 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag struct map_session_data *sd = BL_CAST(BL_PC, src); int s; - ARR_FIND(1, 6, s, sd->talisman[s] > 0); + ARR_FIND(1, 6, s, sd->charm[s] > 0); if( s < 5 && atk_elem == s ) - ratio += sd->talisman[s] * 2; // +2% custom value + ratio += sd->charm[s] * 2; // +2% custom value } if( target && target->type == BL_PC ) { struct map_session_data *tsd = BL_CAST(BL_PC, target); int t; - ARR_FIND(1, 6, t, tsd->talisman[t] > 0); + ARR_FIND(1, 6, t, tsd->charm[t] > 0); if( t < 5 && atk_elem == t ) - damage -= damage * ( tsd->talisman[t] * 3 ) / 100;// -3% custom value + damage -= damage * ( tsd->charm[t] * 3 ) / 100;// -3% custom value } return damage*ratio/100; } -/*========================================== - * Calculates card bonuses damage adjustments. - *------------------------------------------*/ -int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int damage, int left, int flag){ - struct map_session_data *sd, *tsd; - short cardfix = 1000, t_class, s_class, s_race2, t_race2; - struct status_data *sstatus, *tstatus; - int i; +int battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2){ // [malufett] + int damage, eatk = 0; + struct status_change *sc; + struct map_session_data *sd; - if( !damage ) + if( !src || !bl ) return 0; + sc = status_get_sc(src); sd = BL_CAST(BL_PC, src); - tsd = BL_CAST(BL_PC, target); - t_class = status_get_class(target); - s_class = status_get_class(src); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(target); - s_race2 = status_get_race2(src); - switch(attack_type){ - case BF_MAGIC: - if ( sd && !(nk&NK_NO_CARDFIX_ATK) ) { - cardfix=cardfix*(100+sd->magic_addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) - cardfix=cardfix*(100+sd->magic_addele[tstatus->def_ele])/100; - cardfix=cardfix*(100+sd->magic_addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - cardfix=cardfix*(100+sd->magic_atk_ele[s_ele])/100; - for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate;i++) { - if(sd->add_mdmg[i].class_ == t_class) { - cardfix=cardfix*(100+sd->add_mdmg[i].rate)/100; - break; - } - } - if (cardfix != 1000) - damage = damage * cardfix / 1000; - } + damage = status_get_weapon_atk(src, watk, flag); + + if( sd ){ + if( type == EQI_HAND_R ) + damage = battle->calc_sizefix(sd, damage, EQI_HAND_R, size, flag&8); + else + damage = battle->calc_sizefix(sd, damage, EQI_HAND_L, size, flag&8); - if( tsd && !(nk&NK_NO_CARDFIX_DEF) ) - { // Target cards. - if (!(nk&NK_NO_ELEFIX)) - { - int ele_fix = tsd->subele[s_ele]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix)/100; - } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; - if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + if( sd->bonus.eatk > 0 ) + eatk = sd->bonus.eatk; + if( flag&2 && sd->bonus.arrow_atk ) + eatk += sd->bonus.arrow_atk; + } + + if( sc && sc->count ){ + if( sc->data[SC_ZENKAI] && watk->ele == sc->data[SC_ZENKAI]->val2 ) + eatk += 200; + #ifdef RENEWAL_EDP + if( sc->data[SC_EDP] && skill_id != AS_GRIMTOOTH && skill_id != AS_VENOMKNIFE ){ + eatk = eatk * sc->data[SC_EDP]->val3 / 100; // 400% + damage = damage * sc->data[SC_EDP]->val4 / 100; // 500% + damage--; // temporary until we find the correct formula [malufett] + } + #endif + } - for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) { - if(tsd->add_mdef[i].class_ == s_class) { - cardfix=cardfix*(100-tsd->add_mdef[i].rate)/100; - break; - } - } - //It was discovered that ranged defense also counts vs magic! [Skotlex] - if ( flag&BF_SHORT ) - cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; - else - cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; + /* [malufett] + some unknown factors that needs to be discovered. PS: it's something related with ranged attacks + if( eatk ){ + eatk += unknown value; + eatk = eatk * (unknown value) / 100; + } + */ - cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100; + if( sc && sc->data[SC_WATK_ELEMENT] ) + damage = damage + eatk; + else + damage = battle->calc_elefix(src, bl, skill_id, skill_lv, damage + eatk, nk, n_ele, s_ele, s_ele_, false, flag); + + /** + * In RE Shield Bommerang takes weapon element only for damage calculation, + * - resist calculation is always against neutral + **/ + if ( skill_id == CR_SHIELDBOOMERANG ) + s_ele = s_ele_ = ELE_NEUTRAL; + + if( type == EQI_HAND_R ) + damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 2, flag2); + else + damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 3, flag2); + + return damage; +} +/*========================================== + * Calculates the standard damage of a normal attack assuming it hits, + * it calculates nothing extra fancy, is needed for magnum break's WATK_ELEMENT bonus. [Skotlex] + *------------------------------------------ + * Pass damage2 as NULL to not calc it. + * Flag values: + * &1: Critical hit + * &2: Arrow attack + * &4: Skill is Magic Crasher + * &8: Skip target size adjustment (Extremity Fist?) + *&16: Arrow attack but BOW, REVOLVER, RIFLE, SHOTGUN, GATLING or GRENADE type weapon not equipped (i.e. shuriken, kunai and venom knives not affected by DEX) + */ - if( tsd->sc.data[SC_MDEF_RATE] ) - cardfix = cardfix * ( 100 - tsd->sc.data[SC_MDEF_RATE]->val1 ) / 100; +#ifdef RENEWAL +int battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) +{ + int damage, batk; + struct status_change *sc = status_get_sc(src); + struct status_data *status = status_get_status_data(src); + + if( sc && sc->data[SC_TK_SEVENWIND] && !sc->data[SC_WATK_ELEMENT] ) + batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->batk, nk, n_ele, s_ele, s_ele_, false, flag); + else + batk = status->batk; - if (cardfix != 1000) - damage = damage * cardfix / 1000; - } - break; - case BF_WEAPON: - t_race2 = status_get_race2(target); - if( sd && !(nk&NK_NO_CARDFIX_ATK) && (left&2) ) - { - short cardfix_ = 1000; - if(sd->state.arrow_atk) - { - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->arrow_addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) - { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { - if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->right_weapon.addele2[i].rate; - } - cardfix=cardfix*(100+ele_fix)/100; - } - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN])/100; - } - else - { // Melee attack - if( !battle_config.left_cardfix_to_right ) - { - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { - if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->right_weapon.addele2[i].rate; - } - cardfix=cardfix*(100+ele_fix)/100; - } - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN])/100; + if( type == EQI_HAND_L ) + damage = batk + 3 * battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &status->lhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2) / 4; + else + damage = (batk << 1) + battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &status->rhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2); +#else +static int battle_calc_base_damage(struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) +{ + unsigned int atkmin=0, atkmax=0; + short type = 0; + int damage = 0; - if( left&1 ) - { - cardfix_=cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) { - int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { - if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix_lh += sd->left_weapon.addele2[i].rate; - } - cardfix=cardfix*(100+ele_fix_lh)/100; - } - cardfix_=cardfix_*(100+sd->left_weapon.addsize[tstatus->size])/100; - cardfix_=cardfix_*(100+sd->left_weapon.addrace2[t_race2])/100; - cardfix_=cardfix_*(100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix_=cardfix_*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; - } - } - else - { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { - if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->right_weapon.addele2[i].rate; - } - for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { - if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->left_weapon.addele2[i].rate; - } + if (!sd) { //Mobs/Pets + if(flag&4) { + atkmin = status->matk_min; + atkmax = status->matk_max; + } else { + atkmin = wa->atk; + atkmax = wa->atk2; + } + if (atkmin > atkmax) + atkmin = atkmax; + } else { //PCs + atkmax = wa->atk; + type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R; - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->left_weapon.addrace[tstatus->race])/100; - cardfix=cardfix*(100+ele_fix)/100; - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->left_weapon.addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2]+sd->left_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; - } - } - for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ ) - { - if( sd->right_weapon.add_dmg[i].class_ == t_class ) - { - cardfix=cardfix*(100+sd->right_weapon.add_dmg[i].rate)/100; - break; - } - } + if (!(flag&1) || (flag&2)) { //Normal attacks + atkmin = status->dex; - if( left&1 ) - { - for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ ) - { - if( sd->left_weapon.add_dmg[i].class_ == t_class ) - { - cardfix_=cardfix_*(100+sd->left_weapon.add_dmg[i].rate)/100; - break; - } - } - } + if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]]) + atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[type]]->wlv*20)/100; - if( flag&BF_LONG ) - cardfix = cardfix * ( 100 + sd->bonus.long_attack_atk_rate ) / 100; -#ifdef RENEWAL_EDP - if( sd->sc.data[SC_EDP] ){ - cardfix = cardfix * (100 + sd->sc.data[SC_EDP]->val1 * 60 ) / 100; - cardfix_ = cardfix_ * (100 + sd->sc.data[SC_EDP]->val1 * 60 ) / 100; - } -#endif - if( (left&1) && cardfix_ != 1000 ) - damage = damage * cardfix_ / 1000; - else if( cardfix != 1000 ) - damage = damage * cardfix / 1000; + if (atkmin > atkmax) + atkmin = atkmax; - }else if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ - if( !(nk&NK_NO_ELEFIX) ) - { - int ele_fix = tsd->subele[s_ele]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix)/100; - if( left&1 && s_ele_ != s_ele ) - { - int ele_fix_lh = tsd->subele[s_ele_]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele_) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix_lh += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix_lh)/100; - } + if(flag&2 && !(flag&16)) { //Bows + atkmin = atkmin*atkmax/100; + if (atkmin > atkmax) + atkmax = atkmin; } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; - if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + } + } - for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ) { - if( tsd->add_def[i].class_ == s_class ) { - cardfix=cardfix*(100-tsd->add_def[i].rate)/100; - break; - } - } + if (sc && sc->data[SC_MAXIMIZEPOWER]) + atkmin = atkmax; - if( flag&BF_SHORT ) - cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; - else // BF_LONG (there's no other choice) - cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; + //Weapon Damage calculation + if (!(flag&1)) + damage = (atkmax>atkmin? rnd()%(atkmax-atkmin):0)+atkmin; + else + damage = atkmax; + + if (sd) { + //rodatazone says the range is 0~arrow_atk-1 for non crit + if (flag&2 && sd->bonus.arrow_atk) + damage += ( (flag&1) ? sd->bonus.arrow_atk : rnd()%sd->bonus.arrow_atk ); - if( tsd->sc.data[SC_DEF_RATE] ) - cardfix = cardfix * ( 100 - tsd->sc.data[SC_DEF_RATE]->val1 ) / 100; + //SizeFix only for players + if (!(sd->special_state.no_sizefix || (flag&8))) + DAMAGE_RATE(type==EQI_HAND_L? + sd->left_weapon.atkmods[t_size]: + sd->right_weapon.atkmods[t_size]) + } - if( cardfix != 1000 ) - damage = damage * cardfix / 1000; + //Finally, add baseatk + if(flag&4) + damage += status->matk_min; + else + damage += status->batk; + + //rodatazone says that Overrefine bonuses are part of baseatk + //Here we also apply the weapon_atk_rate bonus so it is correctly applied on left/right hands. + if(sd) { + if (type == EQI_HAND_L) { + if(sd->left_weapon.overrefine) + damage += rnd()%sd->left_weapon.overrefine+1; + if (sd->weapon_atk_rate[sd->weapontype2]) + DAMAGE_ADDRATE(sd->weapon_atk_rate[sd->weapontype2]) + } else { //Right hand + if(sd->right_weapon.overrefine) + damage += rnd()%sd->right_weapon.overrefine+1; + if (sd->weapon_atk_rate[sd->weapontype1]) + DAMAGE_ADDRATE(sd->weapon_atk_rate[sd->weapontype1]) } - break; - case BF_MISC: - if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ - // misc damage reduction from equipment - if (!(nk&NK_NO_ELEFIX)) - { - int ele_fix = tsd->subele[s_ele]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix)/100; - } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; - if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + } +#endif + return damage; +} - cardfix = cardfix * ( 100 - tsd->bonus.misc_def_rate ) / 100; - if( flag&BF_SHORT ) - cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; - else // BF_LONG (there's no other choice) - cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; +int battle_calc_sizefix(struct map_session_data *sd, int damage, int type, int size, bool ignore){ + //SizeFix only for players + if (!(sd->special_state.no_sizefix || (ignore))) + damage = damage * ( type == EQI_HAND_L ? sd->left_weapon.atkmods[size] : sd->right_weapon.atkmods[size] ) / 100; + return damage; +} - if (cardfix != 10000) - damage = damage * cardfix / 1000; +/*========================================== + * Passive skill damages increases + *------------------------------------------*/ +int battle_addmastery(struct map_session_data *sd,struct block_list *target,int dmg,int type) +{ + int damage,skill; + struct status_data *status = status_get_status_data(target); + int weapon; + damage = dmg; + + nullpo_ret(sd); + + if((skill = pc->checkskill(sd,AL_DEMONBANE)) > 0 && + target->type == BL_MOB && //This bonus doesnt work against players. + (battle->check_undead(status->race,status->def_ele) || status->race==RC_DEMON) ) + damage += (int)(skill*(3+sd->status.base_level/20.0)); + //damage += (skill * 3); + if( (skill = pc->checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) ) + damage += (skill * 5); + if( (skill = pc->checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) ) + damage += (skill * 10); + if( pc_ismadogear(sd) ) + damage += 20 + 20 * pc->checkskill(sd, NC_MADOLICENCE); +#ifdef RENEWAL + if( (skill = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0 ) + damage += (skill * 2); +#endif + if((skill = pc->checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) { + damage += (skill * 4); + if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_HUNTER) + damage += sd->status.str; + } + + if(type == 0) + weapon = sd->weapontype1; + else + weapon = sd->weapontype2; + switch(weapon) + { + case W_1HSWORD: + #ifdef RENEWAL + if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill * 3); + #endif + case W_DAGGER: + if((skill = pc->checkskill(sd,SM_SWORD)) > 0) + damage += (skill * 4); + if((skill = pc->checkskill(sd,GN_TRAINING_SWORD)) > 0) + damage += skill * 10; + break; + case W_2HSWORD: + #ifdef RENEWAL + if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill * 3); + #endif + if((skill = pc->checkskill(sd,SM_TWOHAND)) > 0) + damage += (skill * 4); + break; + case W_1HSPEAR: + case W_2HSPEAR: + if((skill = pc->checkskill(sd,KN_SPEARMASTERY)) > 0) { + + if(!pc_isriding(sd)) + damage += (skill * 4); + else if(pc_isridingdragon(sd)) + damage += (skill * 10); + else + damage += (skill * 5); } break; + case W_1HAXE: + case W_2HAXE: + if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill * 3); + if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill * 5); + break; + case W_MACE: + case W_2HMACE: + if((skill = pc->checkskill(sd,PR_MACEMASTERY)) > 0) + damage += (skill * 3); + if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill * 5); + break; + case W_FIST: + if((skill = pc->checkskill(sd,TK_RUN)) > 0) + damage += (skill * 10); + // No break, fallthrough to Knuckles + case W_KNUCKLE: + if((skill = pc->checkskill(sd,MO_IRONHAND)) > 0) + damage += (skill * 3); + break; + case W_MUSICAL: + if((skill = pc->checkskill(sd,BA_MUSICALLESSON)) > 0) + damage += (skill * 3); + break; + case W_WHIP: + if((skill = pc->checkskill(sd,DC_DANCINGLESSON)) > 0) + damage += (skill * 3); + break; + case W_BOOK: + if((skill = pc->checkskill(sd,SA_ADVANCEDBOOK)) > 0) + damage += (skill * 3); + break; + case W_KATAR: + if((skill = pc->checkskill(sd,AS_KATAR)) > 0) + damage += (skill * 3); + break; } return damage; } /*========================================== - * Check dammage trough status. - * ATK may be MISS, BLOCKED FAIL, reduc, increase, end status... - * After this we apply bg/gvg reduction + * Calculates ATK masteries. *------------------------------------------*/ -int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int damage,uint16 skill_id,uint16 skill_lv) -{ - struct map_session_data *sd = NULL; +int battle_calc_masteryfix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int div, bool left, bool weapon){ + int skill, i; + struct map_session_data *sd; struct status_change *sc; - struct status_change_entry *sce; - int div_ = d->div_, flag = d->flag; - - nullpo_ret(bl); - if( !damage ) - return 0; - if( battle_config.ksprotection && mob_ksprotected(src, bl) ) - return 0; + nullpo_ret(src); + nullpo_ret(target); - if (bl->type == BL_PC) { - sd=(struct map_session_data *)bl; - //Special no damage states - if(flag&BF_WEAPON && sd->special_state.no_weapon_damage) - damage -= damage * sd->special_state.no_weapon_damage / 100; + sd = BL_CAST(BL_PC, src); + sc = status_get_sc(src); - if(flag&BF_MAGIC && sd->special_state.no_magic_damage) - damage -= damage * sd->special_state.no_magic_damage / 100; + if ( !sd ) + return damage; - if(flag&BF_MISC && sd->special_state.no_misc_damage) - damage -= damage * sd->special_state.no_misc_damage / 100; + switch( skill_id ){ // specific skill masteries + case MO_INVESTIGATE: + case MO_EXTREMITYFIST: + case CR_GRANDCROSS: + case NJ_ISSEN: + case CR_ACIDDEMONSTRATION: + return damage; + case NJ_SYURIKEN: + if( (skill = pc->checkskill(sd,NJ_TOBIDOUGU)) > 0 && weapon ) + damage += 3 * skill; + break; + case NJ_KUNAI: + if( weapon ) + damage += 60; + break; + case RA_WUGDASH: + case RA_WUGSTRIKE: + case RA_WUGBITE: + damage += 30*pc->checkskill(sd, RA_TOOTHOFWUG); + break; + } - if(!damage) return 0; + if ( sc && sc->data[SC_MIRACLE] ) i = 2; //Star anger + else + ARR_FIND(0, MAX_PC_FEELHATE, i, status_get_class(target) == sd->hate_mob[i]); + if ( i < MAX_PC_FEELHATE && (skill=pc->checkskill(sd,sg_info[i].anger_id)) && weapon ){ + int ratio = sd->status.base_level + status_get_dex(src) + status_get_luk(src); + if ( i == 2 ) ratio += status_get_str(src); //Star Anger + if (skill < 4 ) + ratio /= 12 - 3 * skill; + damage += damage * ratio; + } + + if( sc ){ + if(sc->data[SC_GN_CARTBOOST]) + damage += 10 * sc->data[SC_GN_CARTBOOST]->val1; + if(sc->data[SC_CAMOUFLAGE]) + damage += 30 * ( 10 - sc->data[SC_CAMOUFLAGE]->val4 ); } - sc = status_get_sc(bl); + // general skill masteries +#ifdef RENEWAL + if( skill_id == MO_FINGEROFFENSIVE )//The finger offensive spheres on moment of attack do count. [Skotlex] + damage += div * sd->spiritball_old * 3; + else + damage += div * sd->spiritball * 3; + if( skill_id != CR_SHIELDBOOMERANG ) // Only Shield boomerang doesn't takes the Star Crumbs bonus. + damage += div * (left ? sd->left_weapon.star : sd->right_weapon.star); +#else + if( skill_id != ASC_BREAKER && weapon ) // Adv Katar Mastery is does not applies to ASC_BREAKER, but other masteries DO apply >_> + if( sd->status.weapon == W_KATAR && (skill=pc->checkskill(sd,ASC_KATAR)) > 0 ) + damage += damage * (10 + 2 * skill) / 100; +#endif - if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) - return 1; - if (skill_id == PA_PRESSURE) - return damage; //This skill bypass everything else. - - if( sc && sc->count ) - { - //First, sc_*'s that reduce damage to 0. - if( sc->data[SC_BASILICA] && !(status_get_mode(src)&MD_BOSS) ) - { - d->dmg_lv = ATK_BLOCK; - return 0; - } - if( sc->data[SC_WHITEIMPRISON] && skill_id != HW_GRAVITATION ) { // Gravitation and Pressure do damage without removing the effect - if( skill_id == MG_NAPALMBEAT || - skill_id == MG_SOULSTRIKE || - skill_id == WL_SOULEXPANSION || - (skill_id && skill->get_ele(skill_id, skill_lv) == ELE_GHOST) || - (!skill_id && (status_get_status_data(src))->rhw.ele == ELE_GHOST) - ){ - if( skill_id == WL_SOULEXPANSION ) - damage <<= 1; // If used against a player in White Imprison, the skill deals double damage. - status_change_end(bl,SC_WHITEIMPRISON,INVALID_TIMER); // Those skills do damage and removes effect - }else{ - d->dmg_lv = ATK_BLOCK; - return 0; - } - } - - if(sc->data[SC_ZEPHYR] && - flag&(BF_LONG|BF_SHORT)){ - d->dmg_lv = ATK_BLOCK; - return 0; - } - - if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT ) - { - struct skill_unit_group* group = skill->id2group(sc->data[SC_SAFETYWALL]->val3); - uint16 skill_id = sc->data[SC_SAFETYWALL]->val2; - if (group) { - if(skill_id == MH_STEINWAND){ - if (--group->val2<=0) - skill->del_unitgroup(group,ALC_MARK); - d->dmg_lv = ATK_BLOCK; - return 0; - } - /** - * in RE, SW possesses a lifetime equal to 3 times the caster's health - **/ - #ifdef RENEWAL - d->dmg_lv = ATK_BLOCK; - if ( ( group->val2 - damage) > 0 ) { - group->val2 -= damage; - } else - skill->del_unitgroup(group,ALC_MARK); - return 0; - #else - if (--group->val2<=0) - skill->del_unitgroup(group,ALC_MARK); - d->dmg_lv = ATK_BLOCK; - return 0; - #endif - } - status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER); - } - - if( ( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) || sc->data[SC__MANHOLE] ) { - d->dmg_lv = ATK_BLOCK; - return 0; - } - if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rnd()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) - { - clif->skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1); - d->dmg_lv = ATK_BLOCK; - sc_start2(bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000); - return 0; - } - if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) - { - int delay; - clif->skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1); - // different delay depending on skill level [celest] - if (sce->val1 <= 5) - delay = 300; - else if (sce->val1 > 5 && sce->val1 <= 9) - delay = 200; - else - delay = 100; - unit_set_walkdelay(bl, iTimer->gettick(), delay, 1); - - if(sc->data[SC_SHRINK] && rnd()%100<5*sce->val1) - skill->blown(bl,src,skill->get_blewcount(CR_SHRINK,1),-1,0); - return 0; - } - - if( (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 ) { - clif->skill_nodamage(bl, bl, RK_MILLENNIUMSHIELD, 1, 1); - sce->val3 -= damage; // absorb damage - d->dmg_lv = ATK_BLOCK; - sc_start(bl,SC_STUN,15,0,skill->get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stuned when one shield is broken. - if( sce->val3 <= 0 ) { // Shield Down - sce->val2--; - if( sce->val2 > 0 ) { - if( sd ) - clif->millenniumshield(sd,sce->val2); - sce->val3 = 1000; // Next Shield - } else - status_change_end(bl,SC_MILLENNIUMSHIELD,INVALID_TIMER); // All shields down - } - return 0; - } + damage = battle->add_mastery(sd, target, damage, left); + if((skill = pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && + (status_get_status_data(target)->race == RC_DEMON || status_get_status_data(target)->def_ele == ELE_DARK) ) + damage += damage * skill / 100; - if( (sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON && skill_id != WS_CARTTERMINATION && rnd()%100 < sce->val2 ) - { // attack blocked by Parrying - clif->skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1); - return 0; - } + return damage; +} +/*========================================== + * Elemental attribute fix. + *------------------------------------------*/ +int battle_calc_elefix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag){ + struct status_data *sstatus, *tstatus; + struct status_change *sc; - if(sc->data[SC_DODGE] && ( !sc->opt1 || sc->opt1 == OPT1_BURNING ) && - (flag&BF_LONG || sc->data[SC_SPURT]) - && rnd()%100 < 20) { - if (sd && pc_issit(sd)) pc->setstand(sd); //Stand it to dodge. - clif->skill_nodamage(bl,bl,TK_DODGE,1,1); - if (!sc->data[SC_COMBO]) - sc_start4(bl, SC_COMBO, 100, TK_JUMPKICK, src->id, 1, 0, 2000); - return 0; - } + nullpo_ret(src); + nullpo_ret(target); - if(sc->data[SC_HERMODE] && flag&BF_MAGIC) - return 0; + sstatus = status_get_status_data(src); + tstatus = status_get_status_data(target); + sc = status_get_sc(src); - if(sc->data[SC_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG) - return 0; + if( (nk&NK_NO_ELEFIX) && n_ele ) + return damage; - if( sc->data[SC_NEUTRALBARRIER] && (flag&(BF_MAGIC|BF_LONG)) == (BF_MAGIC|BF_LONG) ) { - d->dmg_lv = ATK_MISS; - return 0; + if( damage > 0 ) + { + if( left ) + damage = battle->attr_fix(src, target, damage, s_ele_, tstatus->def_ele, tstatus->ele_lv); + else{ + damage=battle->attr_fix(src, target, damage, s_ele, tstatus->def_ele, tstatus->ele_lv); + if( skill_id == MC_CARTREVOLUTION ) //Cart Revolution applies the element fix once more with neutral element + damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); + if( skill_id == GS_GROUNDDRIFT ) //Additional 50*lv Neutral damage. + damage += battle_attr_fix(src,target,50*skill_lv,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); } + } + if( sc && sc->data[SC_WATK_ELEMENT] ) + { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex] + damage = +#ifndef RENEWAL + battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, ((TBL_PC*)src), (flag?2:0)) +#else + battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (flag?2:0)|(sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), 0) +#endif + * sc->data[SC_WATK_ELEMENT]->val2 / 100; + + damage += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); + if( left ){ + damage = +#ifndef RENEWAL + battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, ((TBL_PC*)src), (flag?2:0)) +#else + battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_L, (flag?2:0)|(sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), 0) +#endif + * sc->data[SC_WATK_ELEMENT]->val2 / 100; + damage += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); + } + } - if((sce=sc->data[SC_KAUPE]) && rnd()%100 < sce->val2) - { //Kaupe blocks damage (skill or otherwise) from players, mobs, homuns, mercenaries. - clif->specialeffect(bl, 462, AREA); - //Shouldn't end until Breaker's non-weapon part connects. - if (skill_id != ASC_BREAKER || !(flag&BF_WEAPON)) - if (--(sce->val3) <= 0) //We make it work like Safety Wall, even though it only blocks 1 time. - status_change_end(bl, SC_KAUPE, INVALID_TIMER); - return 0; - } + return damage; +} +/*========================================== + * Calculates card bonuses damage adjustments. + *------------------------------------------*/ +int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int damage, int left, int flag){ + struct map_session_data *sd, *tsd; + short cardfix = 1000, t_class, s_class, s_race2, t_race2; + struct status_data *sstatus, *tstatus; + int i; - if( flag&BF_MAGIC && (sce=sc->data[SC_PRESTIGE]) && rnd()%100 < sce->val2) { - clif->specialeffect(bl, 462, AREA); // Still need confirm it. - return 0; - } + if( !damage ) + return 0; + + nullpo_ret(src); + nullpo_ret(target); - if (((sce=sc->data[SC_UTSUSEMI]) || sc->data[SC_BUNSINJYUTSU]) - && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK)) { + sd = BL_CAST(BL_PC, src); + tsd = BL_CAST(BL_PC, target); + t_class = status_get_class(target); + s_class = status_get_class(src); + sstatus = status_get_status_data(src); + tstatus = status_get_status_data(target); + s_race2 = status_get_race2(src); - skill->additional_effect (src, bl, skill_id, skill_lv, flag, ATK_BLOCK, iTimer->gettick() ); - if( !status_isdead(src) ) - skill->counter_additional_effect( src, bl, skill_id, skill_lv, flag, iTimer->gettick() ); - if (sce) { - clif->specialeffect(bl, 462, AREA); - skill->blown(src,bl,sce->val3,-1,0); + switch(attack_type){ + case BF_MAGIC: + if ( sd && !(nk&NK_NO_CARDFIX_ATK) ) { + cardfix=cardfix*(100+sd->magic_addrace[tstatus->race])/100; + if (!(nk&NK_NO_ELEFIX)) + cardfix=cardfix*(100+sd->magic_addele[tstatus->def_ele])/100; + cardfix=cardfix*(100+sd->magic_addsize[tstatus->size])/100; + cardfix=cardfix*(100+sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + cardfix=cardfix*(100+sd->magic_atk_ele[s_ele])/100; + for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate;i++) { + if(sd->add_mdmg[i].class_ == t_class) { + cardfix=cardfix*(100+sd->add_mdmg[i].rate)/100; + break; + } + } + if (cardfix != 1000) + damage = damage * cardfix / 1000; } - //Both need to be consumed if they are active. - if (sce && --(sce->val2) <= 0) - status_change_end(bl, SC_UTSUSEMI, INVALID_TIMER); - if ((sce=sc->data[SC_BUNSINJYUTSU]) && --(sce->val2) <= 0) - status_change_end(bl, SC_BUNSINJYUTSU, INVALID_TIMER); - return 0; - } + if( tsd && !(nk&NK_NO_CARDFIX_DEF) ) + { // Target cards. + if (!(nk&NK_NO_ELEFIX)) + { + int ele_fix = tsd->subele[s_ele]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) + { + if(tsd->subele2[i].ele != s_ele) continue; + if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && + tsd->subele2[i].flag&flag&BF_RANGEMASK && + tsd->subele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += tsd->subele2[i].rate; + } + cardfix=cardfix*(100-ele_fix)/100; + } + cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; + cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; + cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; + cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; + if( sstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; - //Now damage increasing effects - if( sc->data[SC_AETERNA] && skill_id != PF_SOULBURN ) - { - if( src->type != BL_MER || skill_id == 0 ) - damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries + for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) { + if(tsd->add_mdef[i].class_ == s_class) { + cardfix=cardfix*(100-tsd->add_mdef[i].rate)/100; + break; + } + } + //It was discovered that ranged defense also counts vs magic! [Skotlex] + if ( flag&BF_SHORT ) + cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; + else + cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; - if( skill_id != ASC_BREAKER || !(flag&BF_WEAPON) ) - status_change_end(bl, SC_AETERNA, INVALID_TIMER); //Shouldn't end until Breaker's non-weapon part connects. - } + cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100; -#ifdef RENEWAL - if( sc->data[SC_RAID] ) { - damage += damage * 20 / 100; + if( tsd->sc.data[SC_PROTECT_MDEF] ) + cardfix = cardfix * ( 100 - tsd->sc.data[SC_PROTECT_MDEF]->val1 ) / 100; - if (--sc->data[SC_RAID]->val1 == 0) - status_change_end(bl, SC_RAID, INVALID_TIMER); - } -#endif - - if( damage ) { - struct map_session_data *tsd = BL_CAST(BL_PC, src); - if( sc->data[SC_DEEPSLEEP] ) { - damage += damage / 2; // 1.5 times more damage while in Deep Sleep. - status_change_end(bl,SC_DEEPSLEEP,INVALID_TIMER); + if (cardfix != 1000) + damage = damage * cardfix / 1000; } - if( tsd && sd && sc->data[SC_CRYSTALIZE] && flag&BF_WEAPON ){ - switch(tsd->status.weapon){ - case W_MACE: - case W_2HMACE: - case W_1HAXE: - case W_2HAXE: - damage = damage * 150/100; - break; - case W_MUSICAL: - case W_WHIP: - if(!sd->state.arrow_atk) - break; - case W_BOW: - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - case W_GRENADE: - case W_DAGGER: - case W_1HSWORD: - case W_2HSWORD: - damage = damage * 50/100; - break; + break; + case BF_WEAPON: + t_race2 = status_get_race2(target); + if( sd && !(nk&NK_NO_CARDFIX_ATK) && (left&2) ) + { + short cardfix_ = 1000; + if(sd->state.arrow_atk) + { + cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->arrow_addrace[tstatus->race])/100; + if (!(nk&NK_NO_ELEFIX)) + { + int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { + if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += sd->right_weapon.addele2[i].rate; + } + cardfix=cardfix*(100+ele_fix)/100; + } + cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN])/100; } - } - if( sc->data[SC_VOICEOFSIREN] ) - status_change_end(bl,SC_VOICEOFSIREN,INVALID_TIMER); - } + else + { // Melee attack + if( !battle_config.left_cardfix_to_right ) + { + cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100; + if (!(nk&NK_NO_ELEFIX)) { + int ele_fix = sd->right_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { + if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += sd->right_weapon.addele2[i].rate; + } + cardfix=cardfix*(100+ele_fix)/100; + } + cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN])/100; - //Finally damage reductions.... - // Assumptio doubles the def & mdef on RE mode, otherwise gives a reduction on the final damage. [Igniz] -#ifndef RENEWAL - if( sc->data[SC_ASSUMPTIO] ) { - if( map_flag_vs(bl->m) ) - damage = damage*2/3; //Receive 66% damage - else - damage >>= 1; //Receive 50% damage - } -#endif + if( left&1 ) + { + cardfix_=cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100; + if (!(nk&NK_NO_ELEFIX)) { + int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { + if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && + sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && + sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix_lh += sd->left_weapon.addele2[i].rate; + } + cardfix=cardfix*(100+ele_fix_lh)/100; + } + cardfix_=cardfix_*(100+sd->left_weapon.addsize[tstatus->size])/100; + cardfix_=cardfix_*(100+sd->left_weapon.addrace2[t_race2])/100; + cardfix_=cardfix_*(100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix_=cardfix_*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; + } + } + else + { + int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { + if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += sd->right_weapon.addele2[i].rate; + } + for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { + if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && + sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && + sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += sd->left_weapon.addele2[i].rate; + } - if(sc->data[SC_DEFENDER] && - (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) - damage = damage * ( 100 - sc->data[SC_DEFENDER]->val2 ) / 100; + cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->left_weapon.addrace[tstatus->race])/100; + cardfix=cardfix*(100+ele_fix)/100; + cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->left_weapon.addsize[tstatus->size])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2]+sd->left_weapon.addrace2[t_race2])/100; + cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; + } + } + for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ ) + { + if( sd->right_weapon.add_dmg[i].class_ == t_class ) + { + cardfix=cardfix*(100+sd->right_weapon.add_dmg[i].rate)/100; + break; + } + } - if(sc->data[SC_ADJUSTMENT] && - (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) - damage -= damage * 20 / 100; + if( left&1 ) + { + for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ ) + { + if( sd->left_weapon.add_dmg[i].class_ == t_class ) + { + cardfix_=cardfix_*(100+sd->left_weapon.add_dmg[i].rate)/100; + break; + } + } + } - if(sc->data[SC_FOGWALL] && skill_id != RK_DRAGONBREATH) { - if(flag&BF_SKILL) //25% reduction - damage -= damage * 25 / 100; - else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) - damage >>= 2; //75% reduction - } + if( flag&BF_LONG ) + cardfix = cardfix * ( 100 + sd->bonus.long_attack_atk_rate ) / 100; + if( (left&1) && cardfix_ != 1000 ) + damage = damage * cardfix_ / 1000; + else if( cardfix != 1000 ) + damage = damage * cardfix / 1000; - // Compressed code, fixed by map.h [Epoque] - if (src->type == BL_MOB) { - int i; - if (sc->data[SC_MANU_DEF]) - for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) - if (mob_manuk[i]==((TBL_MOB*)src)->class_) { - damage -= damage * sc->data[SC_MANU_DEF]->val1 / 100; - break; - } - if (sc->data[SC_SPL_DEF]) - for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) - if (mob_splendide[i]==((TBL_MOB*)src)->class_) { - damage -= damage * sc->data[SC_SPL_DEF]->val1 / 100; - break; + }else if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ + if( !(nk&NK_NO_ELEFIX) ) + { + int ele_fix = tsd->subele[s_ele]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) + { + if(tsd->subele2[i].ele != s_ele) continue; + if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && + tsd->subele2[i].flag&flag&BF_RANGEMASK && + tsd->subele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += tsd->subele2[i].rate; + } + cardfix=cardfix*(100-ele_fix)/100; + if( left&1 && s_ele_ != s_ele ) + { + int ele_fix_lh = tsd->subele[s_ele_]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) + { + if(tsd->subele2[i].ele != s_ele_) continue; + if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && + tsd->subele2[i].flag&flag&BF_RANGEMASK && + tsd->subele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix_lh += tsd->subele2[i].rate; } - } + cardfix=cardfix*(100-ele_fix_lh)/100; + } + } + cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; + cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; + cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; + cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; + if( sstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; - if((sce=sc->data[SC_ARMOR]) && //NPC_DEFENDER - sce->val3&flag && sce->val4&flag) - damage -= damage * sc->data[SC_ARMOR]->val2 / 100; + for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ) { + if( tsd->add_def[i].class_ == s_class ) { + cardfix=cardfix*(100-tsd->add_def[i].rate)/100; + break; + } + } -#ifdef RENEWAL - if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON || flag&BF_MAGIC) && skill_id != WS_CARTTERMINATION) -#else - if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON && skill_id != WS_CARTTERMINATION)) -#endif - { - struct status_data *status = status_get_status_data(bl); - int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval - per /=20; //Uses 20% SP intervals. - //SP Cost: 1% + 0.5% per every 20% SP - if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000)) - status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER); - //Reduction: 6% + 6% every 20% - damage -= damage * (6 * (1+per)) / 100; - } - if(sc->data[SC_GRANITIC_ARMOR]){ - damage -= damage * sc->data[SC_GRANITIC_ARMOR]->val2 / 100; - } - if(sc->data[SC_PAIN_KILLER]){ - damage -= damage * sc->data[SC_PAIN_KILLER]->val3 / 100; - } - if((sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) ){ - skill->castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,iTimer->gettick(),0); + if( flag&BF_SHORT ) + cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; + else // BF_LONG (there's no other choice) + cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; + + if( tsd->sc.data[SC_PROTECT_DEF] ) + cardfix = cardfix * ( 100 - tsd->sc.data[SC_PROTECT_DEF]->val1 ) / 100; + + if( cardfix != 1000 ) + damage = damage * cardfix / 1000; } + break; + case BF_MISC: + if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ + // misc damage reduction from equipment + if (!(nk&NK_NO_ELEFIX)) + { + int ele_fix = tsd->subele[s_ele]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) + { + if(tsd->subele2[i].ele != s_ele) continue; + if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && + tsd->subele2[i].flag&flag&BF_RANGEMASK && + tsd->subele2[i].flag&flag&BF_SKILLMASK)) + continue; + ele_fix += tsd->subele2[i].rate; + } + cardfix=cardfix*(100-ele_fix)/100; + } + cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; + cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; + cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; + cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; + if( sstatus->race != RC_DEMIHUMAN ) + cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; - if( (sce = sc->data[SC_STONEHARDSKIN]) && flag&BF_WEAPON && damage > 0 ) { - sce->val2 -= damage; - if( src->type == BL_PC ) { - TBL_PC *ssd = BL_CAST(BL_PC, src); - if (ssd && ssd->status.weapon != W_BOW) - skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); - } else - skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); - // 30% chance to reduce monster's ATK by 25% for 10 seconds. - if( src->type == BL_MOB ) - sc_start(src, SC_STRIPWEAPON, 30, 0, skill->get_time2(RK_STONEHARDSKIN, sce->val1)); - if( sce->val2 <= 0 ) - status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER); - } + cardfix = cardfix * ( 100 - tsd->bonus.misc_def_rate ) / 100; + if( flag&BF_SHORT ) + cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; + else // BF_LONG (there's no other choice) + cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; -/** - * In renewal steel body reduces all incoming damage by 1/10 - **/ -#ifdef RENEWAL - if( sc->data[SC_STEELBODY] ) { - damage = damage > 10 ? damage / 10 : 1; - } -#endif + if (cardfix != 1000) + damage = damage * cardfix / 1000; + } + break; + } - //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie] - if( skill_id == RA_AIMEDBOLT && (sc->data[SC_BITE] || sc->data[SC_ANKLE] || sc->data[SC_ELECTRICSHOCKER]) ) - { - status_change_end(bl, SC_BITE, INVALID_TIMER); - status_change_end(bl, SC_ANKLE, INVALID_TIMER); - status_change_end(bl, SC_ELECTRICSHOCKER, INVALID_TIMER); - } + return damage; +} - //Finally Kyrie because it may, or not, reduce damage to 0. - if((sce = sc->data[SC_KYRIE]) && damage > 0){ - sce->val2-=damage; - if(flag&BF_WEAPON || skill_id == TF_THROWSTONE){ - if(sce->val2>=0) - damage=0; - else - damage=-sce->val2; +/*========================================== + * Calculates defense reduction. [malufett] + * flag: + * &1 - idef/imdef(Ignore defense) + * &2 - pdef(Pierce defense) + * &4 - tdef(Total defense reduction) + *------------------------------------------*/ +int battle_calc_defense(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int flag, int pdef){ + struct status_data *sstatus, *tstatus; + struct map_session_data *sd, *tsd; + struct status_change *sc, *tsc; + int i; + + if( !damage ) + return 0; + + nullpo_ret(src); + nullpo_ret(target); + + sd = BL_CAST(BL_PC, src); + tsd = BL_CAST(BL_PC, target); + sstatus = status_get_status_data(src); + tstatus = status_get_status_data(target); + sc = status_get_sc(src); + tsc = status_get_sc(target); + + switch(attack_type){ + case BF_WEAPON: + { + /** Take note in RE + * def1 = equip def + * def2 = status def + **/ + defType def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions. + short def2 = tstatus->def2, vit_def; + + def1 = status_calc_def2(target, tsc, def1, false); // equip def(RE) + def2 = status_calc_def(target, tsc, def2, false); // status def(RE) + + if( sd ){ + i = sd->ignore_def[is_boss(target)?RC_BOSS:RC_NONBOSS]; + i += sd->ignore_def[tstatus->race]; + if( i ){ + if( i > 100 ) i = 100; + def1 -= def1 * i / 100; + def2 -= def2 * i / 100; + } } - if((--sce->val3)<=0 || (sce->val2<=0) || skill_id == AL_HOLYLIGHT) - status_change_end(bl, SC_KYRIE, INVALID_TIMER); - } - if( sc->data[SC_MEIKYOUSISUI] && rand()%100 < 40 ) // custom value - damage = 0; + if( sc && sc->data[SC_EXPIATIO] ){ + i = 5 * sc->data[SC_EXPIATIO]->val1; // 5% per level + def1 -= def1 * i / 100; + def2 -= def2 * i / 100; + } + + if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { + unsigned char target_count; //256 max targets should be a sane max + target_count = unit_counttargeted(target); + if(target_count >= battle_config.vit_penalty_count) { + if(battle_config.vit_penalty_type == 1) { + if( !tsc || !tsc->data[SC_STEELBODY] ) + def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; + def2 = (def2 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; + } else { //Assume type 2 + if( !tsc || !tsc->data[SC_STEELBODY] ) + def1 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; + def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; + } + } + if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex] + if(def2 < 1) def2 = 1; + } + //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def + if (tsd) //Sd vit-eq + { +#ifndef RENEWAL + //[VIT*0.5] + rnd([VIT*0.3], max([VIT*0.3],[VIT^2/150]-1)) + vit_def = def2*(def2-15)/150; + vit_def = def2/2 + (vit_def>0?rnd()%vit_def:0); +#else + vit_def = def2; +#endif + if((battle->check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players + src->type == BL_MOB && (i=pc->checkskill(tsd,AL_DP)) > 0) + vit_def += i*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn + if( src->type == BL_MOB && (i=pc->checkskill(tsd,RA_RANGERMAIN))>0 && + (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) ) + vit_def += i*5; + } + else { //Mob-Pet vit-eq +#ifndef RENEWAL + //VIT + rnd(0,[VIT/20]^2-1) + vit_def = (def2/20)*(def2/20); + vit_def = def2 + (vit_def>0?rnd()%vit_def:0); +#else + vit_def = def2; +#endif + } + + if (battle_config.weapon_defense_type) { + vit_def += def1*battle_config.weapon_defense_type; + def1 = 0; + } + #ifdef RENEWAL + /** + * RE DEF Reduction + * Damage = Attack * (4000+eDEF)/(4000+eDEF*10) - sDEF + * Pierce defence gains 1 atk per def/2 + **/ + if( def1 == -400 ) /* being hit by a gazillion units, you hit the jackpot and got -400 which creates a division by 0 and subsequently crashes */ + def1 = -399; - if (!damage) return 0; + if( flag&2 ) + damage += def1 >> 1; - if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) { - int dx[8]={0,-1,-1,-1,0,1,1,1}; - int dy[8]={1,1,0,-1,-1,-1,0,1}; - uint8 dir = iMap->calc_dir(bl, src->x, src->y); - if( unit_movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) { - clif->slide(bl,src->x-dx[dir],src->y-dy[dir]); - unit_setdir(bl, dir); + if( !(flag&1) && !(flag&2) ) + if( flag&4 ) + damage -= (def1 + vit_def); + else + damage = damage * (4000+def1) / (4000+10*def1) - vit_def; + + #else + if( def1 > 100 ) def1 = 100; + if( !(flag&1) ){ + if( flag&2 ) + damage = damage * pdef * (def1+vit_def) / 100; + else + damage = damage * (100-def1) / 100; + } + if( !(flag&1 || flag&2) ) + damage -= vit_def; + #endif } - d->dmg_lv = ATK_DEF; - status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER); - return 0; - } + break; - //Probably not the most correct place, but it'll do here - //(since battle_drain is strictly for players currently) - if ((sce=sc->data[SC_BLOODLUST]) && flag&BF_WEAPON && damage > 0 && - rnd()%100 < sce->val3) - status_heal(src, damage*sce->val4/100, 0, 3); + case BF_MAGIC: + { + defType mdef = tstatus->mdef; + short mdef2= tstatus->mdef2; - if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) - pc->addspiritball(sd,skill->get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); - if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { - TBL_HOM *hd = BL_CAST(BL_HOM,bl); - if (hd) homun->addspiritball(hd, 10); //add a sphere - } + mdef2 = status_calc_mdef(target, tsc, mdef2, false); // status mdef(RE) + mdef = status_calc_mdef2(target, tsc, mdef, false); // equip mde(RE) - if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) - status_change_spread(bl, src); // Deadly infect attacked side + if( flag&1 ) + mdef = 0; - if( sc && sc->data[SC__SHADOWFORM] ) { - struct block_list *s_bl = iMap->id2bl(sc->data[SC__SHADOWFORM]->val2); - if( !s_bl || s_bl->m != bl->m ) { // If the shadow form target is not present remove the sc. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - } else if( status_isdead(s_bl) || !battle->check_target(src,s_bl,BCT_ENEMY)) { // If the shadow form target is dead or not your enemy remove the sc in both. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - if( s_bl->type == BL_PC ) - ((TBL_PC*)s_bl)->shadowform_id = 0; - } else { - if( (--sc->data[SC__SHADOWFORM]->val3) < 0 ) { // If you have exceded max hits supported, remove the sc in both. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - if( s_bl->type == BL_PC ) - ((TBL_PC*)s_bl)->shadowform_id = 0; - } else { - status_damage(bl, s_bl, damage, 0, clif->damage(s_bl, s_bl, iTimer->gettick(), 500, 500, damage, -1, 0, 0), 0); - return ATK_NONE; + if(sd) { + i = sd->ignore_mdef[is_boss(target)?RC_BOSS:RC_NONBOSS]; + i += sd->ignore_mdef[tstatus->race]; + if (i) + { + if (i > 100) i = 100; + mdef -= mdef * i/100; + //mdef2-= mdef2* i/100; } } - } - + #ifdef RENEWAL + /** + * RE MDEF Reduction + * Damage = Magic Attack * (1000+eMDEF)/(1000+eMDEF) - sMDEF + **/ + damage = damage * (1000 + mdef) / (1000 + mdef * 10) - mdef2; + #else + if(battle_config.magic_defense_type) + damage = damage - mdef*battle_config.magic_defense_type - mdef2; + else + damage = damage * (100-mdef)/100 - mdef2; + #endif + } + break; } + return damage; +} - //SC effects from caster side. - sc = status_get_sc(src); +int battle_calc_skillratio(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag){ + int i, addedratio; + struct status_change *sc, *tsc; + struct map_session_data *sd, *tsd; + struct status_data *status, *tstatus; - if (sc && sc->count) { - if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) - damage += damage * 75 / 100; - // [Epoque] - if (bl->type == BL_MOB) { - int i; + nullpo_ret(src); + nullpo_ret(target); - if ( ((sce=sc->data[SC_MANU_ATK]) && (flag&BF_WEAPON)) || - ((sce=sc->data[SC_MANU_MATK]) && (flag&BF_MAGIC)) - ) - for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) - if (((TBL_MOB*)bl)->class_==mob_manuk[i]) { - damage += damage * sce->val1 / 100; - break; + sd = BL_CAST(BL_PC, src); + tsd = BL_CAST(BL_PC, target); + sc = status_get_sc(src); + tsc = status_get_sc(target); + status = status_get_status_data(src); + tstatus = status_get_status_data(target); + + addedratio = skillratio - 100; + + switch(attack_type){ + case BF_MAGIC: + switch(skill_id){ + case MG_NAPALMBEAT: + skillratio += skill_lv * 10 - 30; + break; + case MG_FIREBALL: + #ifdef RENEWAL + skillratio += 20 * skill_lv; + #else + skillratio += skill_lv * 10 - 30; + #endif + break; + case MG_SOULSTRIKE: + if (battle->check_undead(tstatus->race,tstatus->def_ele)) + skillratio += 5*skill_lv; + break; + case MG_FIREWALL: + skillratio -= 50; + break; + case MG_THUNDERSTORM: + /** + * in Renewal Thunder Storm boost is 100% (in pre-re, 80%) + **/ + #ifndef RENEWAL + skillratio -= 20; + #endif + break; + case MG_FROSTDIVER: + skillratio += 10 * skill_lv; + break; + case AL_HOLYLIGHT: + skillratio += 25; + if (sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_PRIEST) + skillratio *= 5; //Does 5x damage include bonuses from other skills? + break; + case AL_RUWACH: + skillratio += 45; + break; + case WZ_FROSTNOVA: + skillratio += (100+skill_lv*10) * 2 / 3 - 100; + break; + case WZ_FIREPILLAR: + if (skill_lv > 10) + skillratio += 100; + else + skillratio -= 80; + break; + case WZ_SIGHTRASHER: + skillratio += 20 * skill_lv; + break; + case WZ_WATERBALL: + skillratio += 30 * skill_lv; + break; + case WZ_STORMGUST: + skillratio += 40 * skill_lv; + break; + case HW_NAPALMVULCAN: + skillratio += 10 * skill_lv - 30; + break; + case SL_STIN: + skillratio += (tstatus->size!=SZ_SMALL?-99:10*skill_lv); //target size must be small (0) for full damage. + break; + case SL_STUN: + skillratio += (tstatus->size!=SZ_BIG?5*skill_lv:-99); //Full damage is dealt on small/medium targets + break; + case SL_SMA: + skillratio += -60 + status_get_lv(src); //Base damage is 40% + lv% + break; + case NJ_KOUENKA: + skillratio -= 10; + break; + case NJ_KAENSIN: + skillratio -= 50; + break; + case NJ_BAKUENRYU: + skillratio += 50 * (skill_lv-1); + break; + case NJ_HYOUSYOURAKU: + skillratio += 50 * skill_lv; + break; + case NJ_RAIGEKISAI: + skillratio += 60 + 40 * skill_lv; + break; + case NJ_KAMAITACHI: + case NPC_ENERGYDRAIN: + skillratio += 100 * skill_lv; + break; + case NPC_EARTHQUAKE: + skillratio += 100 + 100 * skill_lv + 100 * (skill_lv/2); + break; + #ifdef RENEWAL + case WZ_HEAVENDRIVE: + case WZ_METEOR: + skillratio += 25; + break; + case WZ_VERMILION: + { + int interval = 0, per = interval, ratio = per; + while( (per++) < skill_lv ){ + ratio += interval; + if(per%3==0) interval += 20; + } + if( skill_lv > 9 ) + ratio -= 10; + skillratio += ratio; } - if ( ((sce=sc->data[SC_SPL_ATK]) && (flag&BF_WEAPON)) || - ((sce=sc->data[SC_SPL_MATK]) && (flag&BF_MAGIC)) - ) - for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) - if (((TBL_MOB*)bl)->class_==mob_splendide[i]) { - damage += damage * sce->val1 / 100; - break; + break; + case NJ_HUUJIN: + skillratio += 50; + break; + #else + case WZ_VERMILION: + skillratio += 20*skill_lv-20; + break; + #endif + /** + * Arch Bishop + **/ + case AB_JUDEX: + skillratio += 180 + 20 * skill_lv; + if (skill_lv > 4) skillratio += 20; + RE_LVL_DMOD(100); + break; + case AB_ADORAMUS: + skillratio += 400 + 100 * skill_lv; + RE_LVL_DMOD(100); + break; + case AB_DUPLELIGHT_MAGIC: + skillratio += 100 + 20 * skill_lv; + break; + /** + * Warlock + **/ + case WL_SOULEXPANSION: // MATK [{( Skill Level + 4 ) x 100 ) + ( Caster?s INT )} x ( Caster?s Base Level / 100 )] % + skillratio += 300 + 100 * skill_lv + status_get_int(src); + RE_LVL_DMOD(100); + break; + case WL_FROSTMISTY: // MATK [{( Skill Level x 100 ) + 200 } x ( Caster’s Base Level / 100 )] % + skillratio += 100 + 100 * skill_lv; + RE_LVL_DMOD(100); + break; + case WL_JACKFROST: + if( tsc && tsc->data[SC_FROSTMISTY] ){ + skillratio += 900 + 300 * skill_lv; + RE_LVL_DMOD(100); + }else{ + skillratio += 400 + 100 * skill_lv; + RE_LVL_DMOD(150); } - } - if( sc->data[SC_POISONINGWEAPON] && skill_id != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 ) - sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON, 1)); - if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) - status_change_spread(src, bl); - if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { - TBL_HOM *hd = BL_CAST(BL_HOM,bl); - if (hd) homun->addspiritball(hd, 10); - } - } - /* no data claims these settings affect anything other than players */ - if( damage && sd && bl->type == BL_PC ) { - switch( skill_id ) { - //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so dont worry about it */ - case HW_GRAVITATION: - case NJ_ZENYNAGE: - case KO_MUCHANAGE: - break; - default: - if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] - if (flag&BF_WEAPON) - damage = damage * map[bl->m].weapon_damage_rate / 100; - if (flag&BF_MAGIC) - damage = damage * map[bl->m].magic_damage_rate / 100; - if (flag&BF_MISC) - damage = damage * map[bl->m].misc_damage_rate / 100; - } else { //Normal attacks get reductions based on range. - if (flag & BF_SHORT) - damage = damage * map[bl->m].short_damage_rate / 100; - if (flag & BF_LONG) - damage = damage * map[bl->m].long_damage_rate / 100; + break; + case WL_DRAINLIFE: + skillratio = 200 * skill_lv + status_get_int(src); + RE_LVL_DMOD(100); + break; + case WL_CRIMSONROCK: + skillratio = 300 * skill_lv; + RE_LVL_DMOD(100); + skillratio += 1300; + break; + case WL_HELLINFERNO: + skillratio = 300 * skill_lv; + RE_LVL_DMOD(100); + // Shadow: MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) x 4/5 }] % + // Fire : MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) /5 }] % + if( flag&ELE_DARK ) + skillratio *= 4; + skillratio /= 5; + break; + case WL_COMET: + i = ( sc ? distance_xy(target->x, target->y, sc->comet_x, sc->comet_y) : 8 ); + if( i <= 3 ) skillratio += 2400 + 500 * skill_lv; // 7 x 7 cell + else + if( i <= 5 ) skillratio += 1900 + 500 * skill_lv; // 11 x 11 cell + else + if( i <= 7 ) skillratio += 1400 + 500 * skill_lv; // 15 x 15 cell + else + skillratio += 900 + 500 * skill_lv; // 19 x 19 cell + + if( sd && sd->status.party_id ){ + struct map_session_data* psd; + int static p_sd[5] = {0, 0, 0, 0, 0}, c; // just limit it to 5 + + c = 0; + memset (p_sd, 0, sizeof(p_sd)); + party_foreachsamemap(skill->check_condition_char_sub, sd, 3, &sd->bl, &c, &p_sd, skill_id); + c = ( c > 1 ? rand()%c : 0 ); + + if( (psd = iMap->id2sd(p_sd[c])) && pc->checkskill(psd,WL_COMET) > 0 ){ + skillratio = skill_lv * 400; //MATK [{( Skill Level x 400 ) x ( Caster's Base Level / 120 )} + 2500 ] % + RE_LVL_DMOD(120); + skillratio += 2500; + status_zap(&psd->bl, 0, skill->get_sp(skill_id, skill_lv) / 2); + } + } + break; + case WL_CHAINLIGHTNING_ATK: + skillratio += 400 + 100 * skill_lv; + RE_LVL_DMOD(100); + if(flag > 0) + skillratio += 100 * flag; + break; + case WL_EARTHSTRAIN: + skillratio += 1900 + 100 * skill_lv; + RE_LVL_DMOD(100); + break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + skillratio += 400 + 500 * skill_lv; + break; + case WL_SUMMON_ATK_FIRE: + case WL_SUMMON_ATK_WATER: + case WL_SUMMON_ATK_WIND: + case WL_SUMMON_ATK_GROUND: + skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech] + RE_LVL_DMOD(100); + break; + case LG_RAYOFGENESIS: + { + int16 lv = skill_lv; + int bandingBonus = 0; + if( sc && sc->data[SC_BANDING] ) + bandingBonus = 200 * (sd ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0) : 1); + skillratio = ((300 * skill_lv) + bandingBonus) * (sd ? sd->status.job_level : 1) / 25; } - if(!damage) damage = 1; break; - } - } - - if(battle_config.skill_min_damage && damage > 0 && damage < div_) - { - if ((flag&BF_WEAPON && battle_config.skill_min_damage&1) - || (flag&BF_MAGIC && battle_config.skill_min_damage&2) - || (flag&BF_MISC && battle_config.skill_min_damage&4) - ) - damage = div_; - } + case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield MDEF x 100) + (Casters INT x 2)] % + if( sd ) { + skillratio = status_get_lv(src) * 4 + sd->bonus.shieldmdef * 100 + status_get_int(src) * 2; + } else + skillratio += 1900; //2000% + break; + case WM_METALICSOUND: + skillratio += 120 * skill_lv + 60 * ( sd? pc->checkskill(sd, WM_LESSON) : 10 ) - 100; + break; + /*case WM_SEVERE_RAINSTORM: + skillratio += 50 * skill_lv; + break; - if( bl->type == BL_MOB && !status_isdead(bl) && src != bl) { - if (damage > 0 ) - mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),flag); - if (skill_id) - mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),MSC_SKILLUSED|(skill_id<<16)); - } - if( sd ) { - if( pc_ismadogear(sd) && rnd()%100 < 50 ) { - short element = skill->get_ele(skill_id, skill_lv); - if( !skill_id || element == -1 ) { //Take weapon's element - struct status_data *sstatus = NULL; - if( src->type == BL_PC && ((TBL_PC*)src)->bonus.arrow_ele ) - element = ((TBL_PC*)src)->bonus.arrow_ele; - else if( (sstatus = status_get_status_data(src)) ) { - element = sstatus->rhw.ele; - } + WM_SEVERE_RAINSTORM just set a unit place, + refer to WM_SEVERE_RAINSTORM_MELEE to set the formula. + */ + case WM_REVERBERATION_MAGIC: + // MATK [{(Skill Level x 100) + 100} x Casters Base Level / 100] % + skillratio += 100 * (sd ? pc->checkskill(sd, WM_REVERBERATION) : 1); + RE_LVL_DMOD(100); + break; + case SO_FIREWALK: + skillratio = 300; + RE_LVL_DMOD(100); + if( sc && sc->data[SC_HEATER_OPTION] ) + skillratio += sc->data[SC_HEATER_OPTION]->val3; + break; + case SO_ELECTRICWALK: + skillratio = 300; + RE_LVL_DMOD(100); + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += sd ? sd->status.job_level / 2 : 0; + break; + case SO_EARTHGRAVE: + skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_SEISMICWEAPON) : 10 ) + status_get_int(src) * skill_lv ); + RE_LVL_DMOD(100); + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; + break; + case SO_DIAMONDDUST: + skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_FROSTWEAPON) : 10 ) + status_get_int(src) * skill_lv ); + RE_LVL_DMOD(100); + if( sc && sc->data[SC_COOLER_OPTION] ) + skillratio += sc->data[SC_COOLER_OPTION]->val3; + break; + case SO_POISON_BUSTER: + skillratio += 1100 + 300 * skill_lv; + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; + break; + case SO_PSYCHIC_WAVE: + skillratio += -100 + skill_lv * 70 + (status_get_int(src) * 3); + RE_LVL_DMOD(100); + if( sc ){ + if( sc->data[SC_HEATER_OPTION] ) + skillratio += sc->data[SC_HEATER_OPTION]->val3; + else if(sc->data[SC_COOLER_OPTION] ) + skillratio += sc->data[SC_COOLER_OPTION]->val3; + else if(sc->data[SC_BLAST_OPTION] ) + skillratio += sc->data[SC_BLAST_OPTION]->val2; + else if(sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3; + } + break; + case SO_VARETYR_SPEAR: //MATK [{( Endow Tornado skill level x 50 ) + ( Caster INT x Varetyr Spear Skill level )} x Caster Base Level / 100 ] % + skillratio = status_get_int(src) * skill_lv + ( sd ? pc->checkskill(sd, SA_LIGHTNINGLOADER) * 50 : 0 ); + RE_LVL_DMOD(100); + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += sd ? sd->status.job_level * 5 : 0; + break; + case SO_CLOUD_KILL: + skillratio += -100 + skill_lv * 40; + RE_LVL_DMOD(100); + if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; + break; + case GN_DEMONIC_FIRE: + if( skill_lv > 20) + { // Fire expansion Lv.2 + skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine] + } + else if( skill_lv > 10 ) + { // Fire expansion Lv.1 + skillratio += 110 + 20 * (skill_lv - 10) / 2; + } + else + skillratio += 110 + 20 * skill_lv; + break; + // Magical Elemental Spirits Attack Skills + case EL_FIRE_MANTLE: + case EL_WATER_SCREW: + skillratio += 900; + break; + case EL_FIRE_ARROW: + case EL_ROCK_CRUSHER_ATK: + skillratio += 200; + break; + case EL_FIRE_BOMB: + case EL_ICE_NEEDLE: + case EL_HURRICANE_ATK: + skillratio += 400; + break; + case EL_FIRE_WAVE: + case EL_TYPOON_MIS_ATK: + skillratio += 1100; + break; + case MH_ERASER_CUTTER: + if(skill_lv%2) skillratio += 400; //600:800:1000 + else skillratio += 700; //1000:1200 + skillratio += 100 * skill_lv; + break; + case MH_XENO_SLASHER: + if(skill_lv%2) skillratio += 350 + 50 * skill_lv; //500:600:700 + else skillratio += 400 + 100 * skill_lv; //700:900 + break; + case MH_HEILIGE_STANGE: + skillratio += 400 + 250 * skill_lv; + break; + case MH_POISON_MIST: + skillratio += 100 * skill_lv; + break; + case KO_KAIHOU: + if( sd ){ + ARR_FIND(1, 6, i, sd->charm[i] > 0); + if( i < 5 ){ + skillratio += -100 + 200 * sd->charm[i]; + RE_LVL_DMOD(100); + pc->del_charm(sd, sd->charm[i], i); + } + } + break; } - else if( element == -2 ) //Use enchantment's element - element = status_get_attack_sc_element(src,status_get_sc(src)); - else if( element == -3 ) //Use random element - element = rnd()%ELE_MAX; - if( element == ELE_FIRE || element == ELE_WATER ) - pc->overheat(sd,element == ELE_FIRE ? 1 : -1); - } - } - - return damage; -} - -/*========================================== - * Calculates BG related damage adjustments. - *------------------------------------------*/ -int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) -{ - if( !damage ) - return 0; - - if( bl->type == BL_MOB ) { - struct mob_data* md = BL_CAST(BL_MOB, bl); - - if( flag&BF_SKILL && (md->class_ == MOBID_BLUE_CRYST || md->class_ == MOBID_PINK_CRYST) ) - return 0; // Crystal cannot receive skill damage on battlegrounds - } - - return damage; -} - -/*========================================== - * Calculates GVG related damage adjustments. - *------------------------------------------*/ -int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,uint16 skill_id,uint16 skill_lv,int flag) -{ - struct mob_data* md = BL_CAST(BL_MOB, bl); - int class_ = status_get_class(bl); - - if (!damage) //No reductions to make. - return 0; - - if(md && md->guardian_data) { - if(class_ == MOBID_EMPERIUM && flag&BF_SKILL) { - //Skill immunity. - switch (skill_id) { -#ifndef RENEWAL - case MO_TRIPLEATTACK: -#endif - case HW_GRAVITATION: - break; - default: - return 0; - } - } - if(src->type != BL_MOB) { - struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild->search(status_get_guild_id(src)); - - if (class_ == MOBID_EMPERIUM && (!g || guild->checkskill(g,GD_APPROVAL) <= 0 )) - return 0; - - if (g && battle_config.guild_max_castles && guild->checkcastles(g)>=battle_config.guild_max_castles) - return 0; // [MouseJstr] - } - } - - switch (skill_id) { - case PA_PRESSURE: - case HW_GRAVITATION: - case NJ_ZENYNAGE: - case KO_MUCHANAGE: - break; - default: - /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka] - if (md && md->guardian_data) { - damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100; - } - */ - break; - } - - return damage; -} - -/*========================================== - * HP/SP drain calculation - *------------------------------------------*/ -int battle_calc_drain(int damage, int rate, int per) { - int diff = 0; - - if (per && rnd()%1000 < rate) { - diff = (damage * per) / 100; - if (diff == 0) { - if (per > 0) - diff = 1; - else - diff = -1; - } - } - return diff; -} - -/*========================================== - * Passif skill dammages increases - *------------------------------------------*/ -int battle_addmastery(struct map_session_data *sd,struct block_list *target,int dmg,int type) { - int damage,skill; - struct status_data *status = status_get_status_data(target); - int weapon; - damage = dmg; - - nullpo_ret(sd); - - if((skill = pc->checkskill(sd,AL_DEMONBANE)) > 0 && - target->type == BL_MOB && //This bonus doesnt work against players. - (battle->check_undead(status->race,status->def_ele) || status->race==RC_DEMON) ) - damage += (skill*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn - //damage += (skill * 3); - if( (skill = pc->checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) ) - damage += (skill * 5); - if( (skill = pc->checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) ) - damage += (skill * 10); - if( pc_ismadogear(sd) ) - damage += 20 + 20 * pc->checkskill(sd, NC_MADOLICENCE); - - if((skill = pc->checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) { - damage += (skill * 4); - if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_HUNTER) - damage += sd->status.str; - } - - if(type == 0) - weapon = sd->weapontype1; - else - weapon = sd->weapontype2; - switch(weapon) - { - case W_1HSWORD: - #ifdef RENEWAL - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); - #endif - case W_DAGGER: - if((skill = pc->checkskill(sd,SM_SWORD)) > 0) - damage += (skill * 4); - if((skill = pc->checkskill(sd,GN_TRAINING_SWORD)) > 0) - damage += skill * 10; - break; - case W_2HSWORD: - #ifdef RENEWAL - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); - #endif - if((skill = pc->checkskill(sd,SM_TWOHAND)) > 0) - damage += (skill * 4); - break; - case W_1HSPEAR: - case W_2HSPEAR: - if((skill = pc->checkskill(sd,KN_SPEARMASTERY)) > 0) { - if(!pc_isriding(sd)) - damage += (skill * 4); - else - damage += (skill * 5); - } - break; - case W_1HAXE: - case W_2HAXE: - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); - if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) - damage += (skill * 5); - break; - case W_MACE: - case W_2HMACE: - if((skill = pc->checkskill(sd,PR_MACEMASTERY)) > 0) - damage += (skill * 3); - if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) - damage += (skill * 5); - break; - case W_FIST: - if((skill = pc->checkskill(sd,TK_RUN)) > 0) - damage += (skill * 10); - // No break, fallthrough to Knuckles - case W_KNUCKLE: - if((skill = pc->checkskill(sd,MO_IRONHAND)) > 0) - damage += (skill * 3); - break; - case W_MUSICAL: - if((skill = pc->checkskill(sd,BA_MUSICALLESSON)) > 0) - damage += (skill * 3); - break; - case W_WHIP: - if((skill = pc->checkskill(sd,DC_DANCINGLESSON)) > 0) - damage += (skill * 3); - break; - case W_BOOK: - if((skill = pc->checkskill(sd,SA_ADVANCEDBOOK)) > 0) - damage += (skill * 3); - break; - case W_KATAR: - if((skill = pc->checkskill(sd,AS_KATAR)) > 0) - damage += (skill * 3); - break; - } - - return damage; -} -/*========================================== - * Calculates the standard damage of a normal attack assuming it hits, - * it calculates nothing extra fancy, is needed for magnum break's WATK_ELEMENT bonus. [Skotlex] - *------------------------------------------ - * Pass damage2 as NULL to not calc it. - * Flag values: - * &1: Critical hit - * &2: Arrow attack - * &4: Skill is Magic Crasher - * &8: Skip target size adjustment (Extremity Fist?) - *&16: Arrow attack but BOW, REVOLVER, RIFLE, SHOTGUN, GATLING or GRENADE type weapon not equipped (i.e. shuriken, kunai and venom knives not affected by DEX) - */ -int battle_calc_base_damage(struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) { - unsigned int atkmin=0, atkmax=0; - short type = 0; - int damage = 0; - - if (!sd) - { //Mobs/Pets - if(flag&4) - { - atkmin = status->matk_min; - atkmax = status->matk_max; - } else { - atkmin = wa->atk; - atkmax = wa->atk2; - } - if (atkmin > atkmax) - atkmin = atkmax; - } else { //PCs - atkmax = wa->atk; - type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R; - - if (!(flag&1) || (flag&2)) - { //Normal attacks - atkmin = status->dex; - - if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]]) - atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[type]]->wlv*20)/100; - - if (atkmin > atkmax) - atkmin = atkmax; - - if(flag&2 && !(flag&16)) - { //Bows - atkmin = atkmin*atkmax/100; - if (atkmin > atkmax) - atkmax = atkmin; - } - } - } - - if (sc && sc->data[SC_MAXIMIZEPOWER]) - atkmin = atkmax; - - //Weapon Damage calculation - if (!(flag&1)) - damage = (atkmax>atkmin? rnd()%(atkmax-atkmin):0)+atkmin; - else - damage = atkmax; - - if (sd) - { - //rodatazone says the range is 0~arrow_atk-1 for non crit - if (flag&2 && sd->bonus.arrow_atk) - damage += ( (flag&1) ? sd->bonus.arrow_atk : rnd()%sd->bonus.arrow_atk ); - - //SizeFix only for players - if (!(sd->special_state.no_sizefix || (flag&8))) - damage = damage * ( type == EQI_HAND_L ? sd->left_weapon.atkmods[t_size] : sd->right_weapon.atkmods[t_size] ) / 100; - } - - //Finally, add baseatk - if(flag&4) - damage += status->matk_min; - else - damage += status->batk; - - //rodatazone says that Overrefine bonuses are part of baseatk - //Here we also apply the weapon_atk_rate bonus so it is correctly applied on left/right hands. - if(sd) { - if (type == EQI_HAND_L) { - if(sd->left_weapon.overrefine) - damage += rnd()%sd->left_weapon.overrefine+1; - if (sd->weapon_atk_rate[sd->weapontype2]) - damage += damage * sd->weapon_atk_rate[sd->weapontype2] / 100; - } else { //Right hand - if(sd->right_weapon.overrefine) - damage += rnd()%sd->right_weapon.overrefine+1; - if (sd->weapon_atk_rate[sd->weapontype1]) - damage += damage * sd->weapon_atk_rate[sd->weapontype1] / 100; - } - } - return damage; -} - -/*========================================== - * Consumes ammo for the given skill. - *------------------------------------------*/ -void battle_consume_ammo(TBL_PC*sd, int skill_id, int lv) { - int qty=1; - if (!battle_config.arrow_decrement) - return; - - if (skill) { - qty = skill->get_ammo_qty(skill_id, lv); - if (!qty) qty = 1; - } - - if(sd->equip_index[EQI_AMMO]>=0) //Qty check should have been done in skill_check_condition - pc->delitem(sd,sd->equip_index[EQI_AMMO],qty,0,1,LOG_TYPE_CONSUME); - - sd->state.arrow_atk = 0; -} -//Skill Range Criteria -int battle_range_type(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv) { - if (battle_config.skillrange_by_distance && - (src->type&battle_config.skillrange_by_distance) - ) { //based on distance between src/target [Skotlex] - if (check_distance_bl(src, target, 5)) - return BF_SHORT; - return BF_LONG; - } - //based on used skill's range - if (skill->get_range2(src, skill_id, skill_lv) < 5) - return BF_SHORT; - return BF_LONG; -} -int battle_adjust_skill_damage(int m, unsigned short skill_id) { - - if( map[m].skill_count ) { - int i; - ARR_FIND(0, map[m].skill_count, i, map[m].skills[i]->skill_id == skill_id ); - - if( i < map[m].skill_count ) { - return map[m].skills[i]->modifier; - } - - } - - return 0; -} -int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { - int i; - if (!sd->skillblown[0].id) - return 0; - //Apply the bonus blewcount. [Skotlex] - for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id; i++) { - if (sd->skillblown[i].id == skill_id) - return sd->skillblown[i].val; - } - return 0; -} - -//For quick div adjustment. -#define damage_div_fix(dmg, div) { if (div > 1) (dmg)*=div; else if (div < 0) (div)*=-1; } -/*========================================== - * battle_calc_weapon_attack (by Skotlex) - *------------------------------------------*/ -struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int wflag) -{ - unsigned int skillratio = 100; //Skill dmg modifiers. - short temp=0; - short s_ele, s_ele_, t_class; - int i, nk; - bool n_ele = false; // non-elemental - - struct map_session_data *sd, *tsd; - struct Damage wd; - struct status_change *sc = status_get_sc(src); - struct status_change *tsc = status_get_sc(target); - struct status_data *sstatus = status_get_status_data(src); - struct status_data *tstatus = status_get_status_data(target); - struct { - unsigned hit : 1; //the attack Hit? (not a miss) - unsigned cri : 1; //Critical hit - unsigned idef : 1; //Ignore defense - unsigned idef2 : 1; //Ignore defense (left weapon) - unsigned pdef : 2; //Pierces defense (Investigate/Ice Pick) - unsigned pdef2 : 2; //1: Use def+def2/100, 2: Use def+def2/50 - unsigned infdef : 1; //Infinite defense (plants) - unsigned arrow : 1; //Attack is arrow-based - unsigned rh : 1; //Attack considers right hand (wd.damage) - unsigned lh : 1; //Attack considers left hand (wd.damage2) - unsigned weapon : 1; //It's a weapon attack (consider VVS, and all that) - } flag; - - memset(&wd,0,sizeof(wd)); - memset(&flag,0,sizeof(flag)); - - if(src==NULL || target==NULL) - { - nullpo_info(NLP_MARK); - return wd; - } - //Initial flag - flag.rh=1; - flag.weapon=1; - flag.infdef=(tstatus->mode&MD_PLANT && skill_id != RA_CLUSTERBOMB -#ifdef RENEWAL - && skill_id != HT_FREEZINGTRAP -#endif - ?1:0); - if( target->type == BL_SKILL){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - flag.infdef = 1; - } - - //Initial Values - wd.type=0; //Normal attack - wd.div_=skill_id?skill->get_num(skill_id,skill_lv):1; - wd.amotion=(skill_id && skill->get_inf(skill_id)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills. - if(skill_id == KN_AUTOCOUNTER) - wd.amotion >>= 1; - wd.dmotion=tstatus->dmotion; - wd.blewcount=skill->get_blewcount(skill_id,skill_lv); - wd.flag = BF_WEAPON; //Initial Flag - wd.flag |= (skill_id||wflag)?BF_SKILL:BF_NORMAL; // Baphomet card's splash damage is counted as a skill. [Inkfish] - wd.dmg_lv=ATK_DEF; //This assumption simplifies the assignation later - nk = skill->get_nk(skill_id); - if( !skill_id && wflag ) //If flag, this is splash damage from Baphomet Card and it always hits. - nk |= NK_NO_CARDFIX_ATK|NK_IGNORE_FLEE; - flag.hit = nk&NK_IGNORE_FLEE?1:0; - flag.idef = flag.idef2 = nk&NK_IGNORE_DEF?1:0; - - if (sc && !sc->count) - sc = NULL; //Skip checking as there are no status changes active. - if (tsc && !tsc->count) - tsc = NULL; //Skip checking as there are no status changes active. - - sd = BL_CAST(BL_PC, src); - tsd = BL_CAST(BL_PC, target); - - if(sd) - wd.blewcount += battle->blewcount_bonus(sd, skill_id); - - //Set miscellaneous data that needs be filled regardless of hit/miss - if( - (sd && sd->state.arrow_atk) || - (!sd && ((skill_id && skill->get_ammotype(skill_id)) || sstatus->rhw.range>3)) - ) - flag.arrow = 1; - - if(skill_id) { - wd.flag |= battle->range_type(src, target, skill_id, skill_lv); - switch(skill_id) { - case MO_FINGEROFFENSIVE: - if(sd) { - if (battle_config.finger_offensive_type) - wd.div_ = 1; - else - wd.div_ = sd->spiritball_old; - } - break; - case HT_PHANTASMIC: - //Since these do not consume ammo, they need to be explicitly set as arrow attacks. - flag.arrow = 1; - break; -#ifndef RENEWAL - case PA_SHIELDCHAIN: - case CR_SHIELDBOOMERANG: -#endif - case LG_SHIELDPRESS: - case LG_EARTHDRIVE: - flag.weapon = 0; - break; - - case KN_PIERCE: - case ML_PIERCE: - wd.div_= (wd.div_>0?tstatus->size+1:-(tstatus->size+1)); - break; - - case TF_DOUBLE: //For NPC used skill. - case GS_CHAINACTION: - wd.type = 0x08; - break; - - case GS_GROUNDDRIFT: - case KN_SPEARSTAB: - case KN_BOWLINGBASH: - case MS_BOWLINGBASH: - case MO_BALKYOUNG: - case TK_TURNKICK: - wd.blewcount=0; - break; - - case KN_AUTOCOUNTER: - wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL; - break; - - case NPC_CRITICALSLASH: - case LG_PINPOINTATTACK: - flag.cri = 1; //Always critical skill. - break; - - case LK_SPIRALPIERCE: - if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC; - break; - } - } else //Range for normal attacks. - wd.flag |= flag.arrow?BF_LONG:BF_SHORT; - - if ( (!skill_id || skill_id == PA_SACRIFICE) && tstatus->flee2 && rnd()%1000 < tstatus->flee2 ) - { //Check for Lucky Dodge - wd.type=0x0b; - wd.dmg_lv=ATK_LUCKY; - if (wd.div_ < 0) wd.div_*=-1; - return wd; - } - - t_class = status_get_class(target); - s_ele = s_ele_ = skill->get_ele(skill_id, skill_lv); - if( !skill_id || s_ele == -1 ) - { //Take weapon's element - s_ele = sstatus->rhw.ele; - s_ele_ = sstatus->lhw.ele; - if( sd ){ //Summoning 10 talisman will endow your weapon. - ARR_FIND(1, 6, i, sd->talisman[i] >= 10); - if( i < 5 ) s_ele = s_ele_ = i; - } - if( flag.arrow && sd && sd->bonus.arrow_ele ) - s_ele = sd->bonus.arrow_ele; - if( battle_config.attack_attr_none&src->type ) - n_ele = true; //Weapon's element is "not elemental" - } - else if( s_ele == -2 ) //Use enchantment's element - s_ele = s_ele_ = status_get_attack_sc_element(src,sc); - else if( s_ele == -3 ) //Use random element - s_ele = s_ele_ = rnd()%ELE_MAX; - switch( skill_id ) - { - case GS_GROUNDDRIFT: - s_ele = s_ele_ = wflag; //element comes in flag. - break; - case LK_SPIRALPIERCE: - if (!sd) n_ele = false; //forced neutral for monsters - break; - } - - if (!(nk & NK_NO_ELEFIX) && !n_ele) - if (src->type == BL_HOM) - n_ele = true; //skill is "not elemental" - if (sc && sc->data[SC_GOLDENE_FERSE] && ((!skill_id && (rnd() % 100 < sc->data[SC_GOLDENE_FERSE]->val4)) || skill_id == MH_STAHL_HORN)) { - s_ele = s_ele_ = ELE_HOLY; - n_ele = false; - } - - if(!skill_id) - { //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2) - if (sd && sd->weapontype1 == 0 && sd->weapontype2 > 0) - { - flag.rh=0; - flag.lh=1; - } - if (sstatus->lhw.atk) - flag.lh=1; - } - - if( sd && !skill_id ) { //Check for double attack. - if( ( ( skill_lv = pc->checkskill(sd,TF_DOUBLE) ) > 0 && sd->weapontype1 == W_DAGGER ) - || ( sd->bonus.double_rate > 0 && sd->weapontype1 != W_FIST ) //Will fail bare-handed - || ( sc && sc->data[SC_KAGEMUSYA] && sd->weapontype1 != W_FIST )) // Need confirmation - { //Success chance is not added, the higher one is used [Skotlex] - if( rnd()%100 < ( 5*skill_lv > sd->bonus.double_rate ? 5*skill_lv : sc && sc->data[SC_KAGEMUSYA]?sc->data[SC_KAGEMUSYA]->val1*3:sd->bonus.double_rate ) ) - { - wd.div_ = skill->get_num(TF_DOUBLE,skill_lv?skill_lv:1); - wd.type = 0x08; - } - } - else if( sd->weapontype1 == W_REVOLVER && (skill_lv = pc->checkskill(sd,GS_CHAINACTION)) > 0 && rnd()%100 < 5*skill_lv ) - { - wd.div_ = skill->get_num(GS_CHAINACTION,skill_lv); - wd.type = 0x08; - } - else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW - && (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1){ - int chance = rand()%100; - wd.type = 0x08; - switch(sc->data[SC_FEARBREEZE]->val1){ - case 5: - if( chance < 3){// 3 % chance to attack 5 times. - wd.div_ = 5; - break; - } - case 4: - if( chance < 7){// 6 % chance to attack 4 times. - wd.div_ = 4; - break; - } - case 3: - if( chance < 10){// 9 % chance to attack 3 times. - wd.div_ = 3; - break; - } - case 2: - case 1: - if( chance < 13){// 12 % chance to attack 2 times. - wd.div_ = 2; - break; - } - } - wd.div_ = min(wd.div_,sd->status.inventory[i].amount); - sc->data[SC_FEARBREEZE]->val4 = wd.div_-1; - } - } - - //Check for critical - if( !flag.cri && !(wd.type&0x08) && sstatus->cri && - (!skill_id || - skill_id == KN_AUTOCOUNTER || - skill_id == SN_SHARPSHOOTING || skill_id == MA_SHARPSHOOTING || - skill_id == NJ_KIRIKAGE)) - { - short cri = sstatus->cri; - if (sd) - { - cri+= sd->critaddrace[tstatus->race]; - if(flag.arrow) - cri += sd->bonus.arrow_cri; - } - if( sc && sc->data[SC_CAMOUFLAGE] ) - cri += 10 * (10-sc->data[SC_CAMOUFLAGE]->val4); - //The official equation is *2, but that only applies when sd's do critical. - //Therefore, we use the old value 3 on cases when an sd gets attacked by a mob - cri -= tstatus->luk*(!sd&&tsd?3:2); - - if( tsc && tsc->data[SC_SLEEP] ) { - cri <<= 1; - } - switch (skill_id) { - case KN_AUTOCOUNTER: - if(battle_config.auto_counter_type && - (battle_config.auto_counter_type&src->type)) - flag.cri = 1; - else - cri <<= 1; - break; - case SN_SHARPSHOOTING: - case MA_SHARPSHOOTING: - cri += 200; - break; - case NJ_KIRIKAGE: - cri += 250 + 50*skill_lv; - break; - } - if(tsd && tsd->bonus.critical_def) - cri = cri * ( 100 - tsd->bonus.critical_def ) / 100; - if (rnd()%1000 < cri) - flag.cri = 1; - } - if (flag.cri) { - wd.type = 0x0a; -#ifdef RENEWAL - flag.hit = 1; -#else - flag.idef = flag.idef2 = flag.hit = 1; -#endif - } else { //Check for Perfect Hit - if(sd && sd->bonus.perfect_hit > 0 && rnd()%100 < sd->bonus.perfect_hit) - flag.hit = 1; - if (sc && sc->data[SC_FUSION]) { - flag.hit = 1; //SG_FUSION always hit [Komurka] - flag.idef = flag.idef2 = 1; //def ignore [Komurka] - } - if( !flag.hit ) - switch(skill_id) - { - case AS_SPLASHER: - if( !wflag ) // Always hits the one exploding. - flag.hit = 1; - break; - case CR_SHIELDBOOMERANG: - if( sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_CRUSADER ) - flag.hit = 1; - break; - } - if (tsc && !flag.hit && tsc->opt1 && tsc->opt1 != OPT1_STONEWAIT && tsc->opt1 != OPT1_BURNING) - flag.hit = 1; - } - - if (!flag.hit) - { //Hit/Flee calculation - short - flee = tstatus->flee, -#ifdef RENEWAL - hitrate = 0; //Default hitrate -#else - hitrate = 80; //Default hitrate -#endif - - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) { - if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; - else //asume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; - } - } - - hitrate+= sstatus->hit - flee; - - if(wd.flag&BF_LONG && !skill_id && //Fogwall's hit penalty is only for normal ranged attacks. - tsc && tsc->data[SC_FOGWALL]) - hitrate -= 50; - - if(sd && flag.arrow) - hitrate += sd->bonus.arrow_hit; -#ifdef RENEWAL - if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window - hitrate += pc->checkskill(sd,AC_VULTURE); -#endif - if(skill_id) - switch(skill_id) - { //Hit skill modifiers - //It is proven that bonus is applied on final hitrate, not hit. - case SM_BASH: - case MS_BASH: - hitrate += hitrate * 5 * skill_lv / 100; - break; - case MS_MAGNUM: - case SM_MAGNUM: - hitrate += hitrate * 10 * skill_lv / 100; - break; - case KN_AUTOCOUNTER: - case PA_SHIELDCHAIN: - case NPC_WATERATTACK: - case NPC_GROUNDATTACK: - case NPC_FIREATTACK: - case NPC_WINDATTACK: - case NPC_POISONATTACK: - case NPC_HOLYATTACK: - case NPC_DARKNESSATTACK: - case NPC_UNDEADATTACK: - case NPC_TELEKINESISATTACK: - case NPC_BLEEDING: - hitrate += hitrate * 20 / 100; - break; - case KN_PIERCE: - case ML_PIERCE: - hitrate += hitrate * 5 * skill_lv / 100; - break; - case AS_SONICBLOW: - if(sd && pc->checkskill(sd,AS_SONICACCEL)>0) - hitrate += hitrate * 50 / 100; - break; - case MC_CARTREVOLUTION: - case GN_CART_TORNADO: - case GN_CARTCANNON: - if( sd && pc->checkskill(sd, GN_REMODELING_CART) ) - hitrate += pc->checkskill(sd, GN_REMODELING_CART) * 4; - break; - case GC_VENOMPRESSURE: - hitrate += 10 + 4 * skill_lv; - break; - } - - if( sd ) { - // Weaponry Research hidden bonus - if ((temp = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0) - hitrate += hitrate * ( 2 * temp ) / 100; - - if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) && - (temp = pc->checkskill(sd, GN_TRAINING_SWORD))>0 ) - hitrate += 3 * temp; - } - - hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); - - if(rnd()%100 >= hitrate) - wd.dmg_lv = ATK_FLEE; - else - flag.hit = 1; - } //End hit/miss calculation - - if (flag.hit && !flag.infdef) //No need to do the math for plants - { //Hitting attack - -//Assuming that 99% of the cases we will not need to check for the flag.rh... we don't. -//ATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc -#define ATK_RATE( a ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(a)/100; } -#define ATK_RATE2( a , b ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(b)/100; } -#define ATK_RATER(a){ wd.damage = wd.damage*(a)/100;} -#define ATK_RATEL(a){ wd.damage2 = wd.damage2*(a)/100;} -//Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage -#define ATK_ADDRATE( a ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(a)/100; } -#define ATK_ADDRATE2( a , b ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(b)/100; } -//Adds an absolute value to damage. 100 = +100 damage -#define ATK_ADD( a ) { wd.damage+= a; if (flag.lh) wd.damage2+= a; } -#define ATK_ADD2( a , b ) { wd.damage+= a; if (flag.lh) wd.damage2+= b; } - - switch (skill_id) - { //Calc base damage according to skill - case PA_SACRIFICE: - wd.damage = sstatus->max_hp* 9/100; - wd.damage2 = 0; - break; -#ifndef RENEWAL - case NJ_ISSEN: - wd.damage = 40*sstatus->str +skill_lv*(sstatus->hp/10 + 35); - wd.damage2 = 0; - break; - case LK_SPIRALPIERCE: - case ML_SPIRALPIERCE: - if (sd) { - short index = sd->equip_index[EQI_HAND_R]; - - if (index >= 0 && - sd->inventory_data[index] && - sd->inventory_data[index]->type == IT_WEAPON) - wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight - } else - wd.damage = sstatus->rhw.atk2*8/10; //Else use Atk2 - - ATK_ADDRATE(50*skill_lv); //Skill modifier applies to weight only. - i = sstatus->str/10; - i*=i; - ATK_ADD(i); //Add str bonus. - switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection? - case SZ_SMALL: //Small: 125% - ATK_RATE(125); - break; - //case SZ_MEDIUM: //Medium: 100% - case SZ_BIG: //Large: 75% - ATK_RATE(75); - break; - } - break; -#endif - case CR_SHIELDBOOMERANG: - case PA_SHIELDCHAIN: - case LG_SHIELDPRESS: - case LG_EARTHDRIVE: - wd.damage = sstatus->batk; - if (sd) { - short index = sd->equip_index[EQI_HAND_L]; - - if (index >= 0 && - sd->inventory_data[index] && - sd->inventory_data[index]->type == IT_ARMOR) - ATK_ADD(sd->inventory_data[index]->weight/10); - } else - ATK_ADD(sstatus->rhw.atk2); //Else use Atk2 - break; - case HFLI_SBR44: //[orn] - if(src->type == BL_HOM) { - wd.damage = ((TBL_HOM*)src)->homunculus.intimacy ; - break; - } - default: - { - i = (flag.cri?1:0)| - (flag.arrow?2:0)| - (skill_id == HW_MAGICCRASHER?4:0)| - (!skill_id && sc && sc->data[SC_CHANGE]?4:0)| - (skill_id == MO_EXTREMITYFIST?8:0)| - (sc && sc->data[SC_WEAPONPERFECTION]?8:0); - if (flag.arrow && sd) - switch(sd->status.weapon) { - case W_BOW: - case W_REVOLVER: - case W_GATLING: - case W_SHOTGUN: - case W_GRENADE: - break; - default: - i |= 16; // for ex. shuriken must not be influenced by DEX - } - wd.damage = battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i); - if (flag.lh) - wd.damage2 = battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i); - - if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets - if(wflag>0) - wd.damage/= wflag; - else - ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); - } - - //Add any bonuses that modify the base baseatk+watk (pre-skills) - if(sd) { - if (sd->bonus.atk_rate) - ATK_ADDRATE(sd->bonus.atk_rate); - - if(flag.cri && sd->bonus.crit_atk_rate) - ATK_ADDRATE(sd->bonus.crit_atk_rate); - - if(sd->status.party_id && (temp=pc->checkskill(sd,TK_POWER)) > 0){ - if( (i = party_foreachsamemap(party->sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish] - ATK_ADDRATE(2*temp*i); - } - } - break; - } //End default case - } //End switch(skill_id) - - //Skill damage modifiers that stack linearly - if(sc && skill_id != PA_SACRIFICE) - { - if(sc->data[SC_OVERTHRUST]) - skillratio += sc->data[SC_OVERTHRUST]->val3; - if(sc->data[SC_MAXOVERTHRUST]) - skillratio += sc->data[SC_MAXOVERTHRUST]->val2; - if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC__BLOODYLUST]) - skillratio += 100; - if(sc->data[SC_ZENKAI] && sstatus->rhw.ele == sc->data[SC_ZENKAI]->val2 ) - skillratio += sc->data[SC_ZENKAI]->val1 * 2; - } - if( !skill_id ) - { - ATK_RATE(skillratio); - } - else - { + break; + case BF_WEAPON: switch( skill_id ) { case SM_BASH: case MS_BASH: - skillratio += 30*skill_lv; + skillratio += 30 * skill_lv; break; case SM_MAGNUM: case MS_MAGNUM: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case MC_MAMMONITE: - skillratio += 50*skill_lv; + skillratio += 50 * skill_lv; break; case HT_POWER: - skillratio += -50+8*sstatus->str; + skillratio += -50 + 8 * status_get_str(src); break; case AC_DOUBLE: case MA_DOUBLE: - skillratio += 10*(skill_lv-1); + skillratio += 10 * (skill_lv-1); break; case AC_SHOWER: case MA_SHOWER: #ifdef RENEWAL - skillratio += 50+10*skill_lv; + skillratio += 50 + 10 * skill_lv; #else - skillratio += -25+5*skill_lv; + skillratio += -25 + 5 * skill_lv; #endif break; case AC_CHARGEARROW: case MA_CHARGEARROW: skillratio += 50; break; -#ifndef RENEWAL + #ifndef RENEWAL case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: - skillratio += -50+10*skill_lv; + skillratio += -50 + 10 * skill_lv; break; -#endif + #endif case KN_PIERCE: case ML_PIERCE: - skillratio += 10*skill_lv; + skillratio += 10 * skill_lv; break; case MER_CRASH: - skillratio += 10*skill_lv; + skillratio += 10 * skill_lv; break; case KN_SPEARSTAB: - skillratio += 15*skill_lv; + skillratio += 15 * skill_lv; break; case KN_SPEARBOOMERANG: skillratio += 50*skill_lv; @@ -2228,41 +1760,41 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case KN_BRANDISHSPEAR: case ML_BRANDISH: { - int ratio = 100+20*skill_lv; - skillratio += ratio-100; - if(skill_lv>3 && wflag==1) skillratio += ratio/2; - if(skill_lv>6 && wflag==1) skillratio += ratio/4; - if(skill_lv>9 && wflag==1) skillratio += ratio/8; - if(skill_lv>6 && wflag==2) skillratio += ratio/2; - if(skill_lv>9 && wflag==2) skillratio += ratio/4; - if(skill_lv>9 && wflag==3) skillratio += ratio/2; + int ratio = 100 + 20 * skill_lv; + skillratio += ratio - 100; + if(skill_lv>3 && flag==1) skillratio += ratio / 2; + if(skill_lv>6 && flag==1) skillratio += ratio / 4; + if(skill_lv>9 && flag==1) skillratio += ratio / 8; + if(skill_lv>6 && flag==2) skillratio += ratio / 2; + if(skill_lv>9 && flag==2) skillratio += ratio / 4; + if(skill_lv>9 && flag==3) skillratio += ratio / 2; break; } case KN_BOWLINGBASH: case MS_BOWLINGBASH: - skillratio+= 40*skill_lv; + skillratio+= 40 * skill_lv; break; case AS_GRIMTOOTH: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case AS_POISONREACT: - skillratio += 30*skill_lv; + skillratio += 30 * skill_lv; break; case AS_SONICBLOW: - skillratio += -50+5*skill_lv; + skillratio += -50 + 5 * skill_lv; break; case TF_SPRINKLESAND: skillratio += 30; break; case MC_CARTREVOLUTION: skillratio += 50; - if(sd && sd->cart_weight) - skillratio += 100*sd->cart_weight/sd->cart_weight_max; // +1% every 1% weight + if( sd && sd->cart_weight ) + skillratio += 100 * sd->cart_weight / sd->cart_weight_max; // +1% every 1% weight else if (!sd) skillratio += 100; //Max damage for non players. break; case NPC_RANDOMATTACK: - skillratio += 100*skill_lv; + skillratio += 100 * skill_lv; break; case NPC_WATERATTACK: case NPC_GROUNDATTACK: @@ -2281,30 +1813,30 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case NPC_THUNDERBREATH: case NPC_HELLJUDGEMENT: case NPC_PULSESTRIKE: - skillratio += 100*(skill_lv-1); + skillratio += 100 * (skill_lv-1); break; case RG_BACKSTAP: - if(sd && sd->status.weapon == W_BOW && battle_config.backstab_bow_penalty) - skillratio += (200+40*skill_lv)/2; + if( sd && sd->status.weapon == W_BOW && battle_config.backstab_bow_penalty ) + skillratio += (200 + 40 * skill_lv) / 2; else - skillratio += 200+40*skill_lv; + skillratio += 200 + 40 * skill_lv; break; case RG_RAID: - skillratio += 40*skill_lv; + skillratio += 40 * skill_lv; break; case RG_INTIMIDATE: - skillratio += 30*skill_lv; + skillratio += 30 * skill_lv; break; case CR_SHIELDCHARGE: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case CR_SHIELDBOOMERANG: - skillratio += 30*skill_lv; + skillratio += 30 * skill_lv; break; case NPC_DARKCROSS: case CR_HOLYCROSS: { - int ratio = 35*skill_lv; + int ratio = 35 * skill_lv; #ifdef RENEWAL if(sd && sd->status.weapon == W_2HSPEAR) ratio *= 2; @@ -2313,18 +1845,18 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list break; } case AM_DEMONSTRATION: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case AM_ACIDTERROR: - skillratio += 40*skill_lv; + skillratio += 40 * skill_lv; break; case MO_FINGEROFFENSIVE: skillratio+= 50 * skill_lv; break; case MO_INVESTIGATE: - skillratio += 75*skill_lv; - flag.pdef = flag.pdef2 = 2; + skillratio += 75 * skill_lv; break; + #ifndef RENEWAL case MO_EXTREMITYFIST: { //Overflow check. [Skotlex] unsigned int ratio = skillratio + 100*(8 + sstatus->sp/10); @@ -2333,76 +1865,63 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio = (unsigned short)ratio; } break; + #endif case MO_TRIPLEATTACK: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case MO_CHAINCOMBO: - skillratio += 50+50*skill_lv; + skillratio += 50 + 50 * skill_lv; break; case MO_COMBOFINISH: - skillratio += 140+60*skill_lv; + skillratio += 140 + 60 * skill_lv; break; case BA_MUSICALSTRIKE: case DC_THROWARROW: - skillratio += 25+25*skill_lv; + skillratio += 25 + 25 * skill_lv; break; case CH_TIGERFIST: - skillratio += 100*skill_lv-60; + skillratio += 100 * skill_lv - 60; break; case CH_CHAINCRUSH: - skillratio += 300+100*skill_lv; + skillratio += 300 + 100 * skill_lv; break; case CH_PALMSTRIKE: - skillratio += 100+100*skill_lv; + skillratio += 100 + 100 * skill_lv; break; case LK_HEADCRUSH: - skillratio += 40*skill_lv; + skillratio += 40 * skill_lv; break; case LK_JOINTBEAT: - i = 10*skill_lv-50; + i = 10 * skill_lv - 50; // Although not clear, it's being assumed that the 2x damage is only for the break neck ailment. - if (wflag&BREAK_NECK) i*=2; + if (flag&BREAK_NECK) i*=2; skillratio += i; break; -#ifdef RENEWAL - case LK_SPIRALPIERCE: - case ML_SPIRALPIERCE: - {// Formula: Floor[Floor(Weapon Weight/2)*skill level + ATK ]*(100%+50%*s.lvl) * 5 multi-hits - short index = sd?sd->equip_index[EQI_HAND_R]:0; - int weight = 0; - - if (sd && index >= 0 && - sd->inventory_data[index] && - sd->inventory_data[index]->type == IT_WEAPON) - weight = sd->inventory_data[index]->weight/20; - ATK_ADD(weight * skill_lv) - skillratio += 50*skill_lv; - } - break; -#endif case ASC_METEORASSAULT: - skillratio += 40*skill_lv-60; + skillratio += 40 * skill_lv - 60; break; case SN_SHARPSHOOTING: case MA_SHARPSHOOTING: - skillratio += 100+50*skill_lv; + skillratio += 100 + 50 * skill_lv; break; case CG_ARROWVULCAN: - skillratio += 100+100*skill_lv; + skillratio += 100 + 100 * skill_lv; break; case AS_SPLASHER: - skillratio += 400+50*skill_lv; + skillratio += 400 + 50 * skill_lv; if(sd) skillratio += 20 * pc->checkskill(sd,AS_POISONREACT); break; + #ifndef RENEWAL case ASC_BREAKER: skillratio += 100*skill_lv-100; break; + #endif case PA_SACRIFICE: - skillratio += 10*skill_lv-10; + skillratio += 10 * skill_lv - 10; break; case PA_SHIELDCHAIN: - skillratio += 30*skill_lv; + skillratio += 30 * skill_lv; break; case WS_CARTTERMINATION: i = 10 * (16 - skill_lv); @@ -2414,30 +1933,30 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 80000 / i - 100; break; case TK_DOWNKICK: - skillratio += 60 + 20*skill_lv; + skillratio += 60 + 20 * skill_lv; break; case TK_STORMKICK: - skillratio += 60 + 20*skill_lv; + skillratio += 60 + 20 * skill_lv; break; case TK_TURNKICK: - skillratio += 90 + 30*skill_lv; + skillratio += 90 + 30 * skill_lv; break; case TK_COUNTER: - skillratio += 90 + 30*skill_lv; + skillratio += 90 + 30 * skill_lv; break; case TK_JUMPKICK: skillratio += -70 + 10*skill_lv; - if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id) - skillratio += 10*status_get_lv(src)/3; //Tumble bonus - if (wflag) + if (sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == skill_id) + skillratio += 10 * status_get_lv(src) / 3; //Tumble bonus + if (flag) { - skillratio += 10*status_get_lv(src)/3; //Running bonus (TODO: What is the real bonus?) - if( sc && sc->data[SC_SPURT] ) // Spurt bonus + skillratio += 10 * status_get_lv(src) / 3; //Running bonus (TODO: What is the real bonus?) + if( sc && sc->data[SC_STRUP] ) // Spurt bonus skillratio *= 2; } break; case GS_TRIPLEACTION: - skillratio += 50*skill_lv; + skillratio += 50 * skill_lv; break; case GS_BULLSEYE: //Only works well against brute/demihumans non bosses. @@ -2446,55 +1965,47 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 400; break; case GS_TRACKING: - skillratio += 100 *(skill_lv+1); + skillratio += 100 * (skill_lv+1); break; case GS_PIERCINGSHOT: - skillratio += 20*skill_lv; + skillratio += 20 * skill_lv; break; case GS_RAPIDSHOWER: - skillratio += 10*skill_lv; + skillratio += 10 * skill_lv; break; case GS_DESPERADO: - skillratio += 50*(skill_lv-1); + skillratio += 50 * (skill_lv-1); break; case GS_DUST: - skillratio += 50*skill_lv; + skillratio += 50 * skill_lv; break; case GS_FULLBUSTER: - skillratio += 100*(skill_lv+2); + skillratio += 100 * (skill_lv+2); break; case GS_SPREADATTACK: #ifdef RENEWAL - skillratio += 20*(skill_lv); + skillratio += 20 * (skill_lv); #else - skillratio += 20*(skill_lv-1); + skillratio += 20 * (skill_lv-1); #endif break; -#ifdef RENEWAL - case NJ_ISSEN: - skillratio += 100 * (skill_lv-1); - break; -#endif case NJ_HUUMA: - skillratio += 50 + 150*skill_lv; + skillratio += 50 + 150 * skill_lv; break; case NJ_TATAMIGAESHI: -#ifdef RENEWAL - ATK_RATE(200); -#endif - skillratio += 10*skill_lv; + skillratio += 10 * skill_lv; break; case NJ_KASUMIKIRI: - skillratio += 10*skill_lv; + skillratio += 10 * skill_lv; break; case NJ_KIRIKAGE: - skillratio += 100*(skill_lv-1); + skillratio += 100 * (skill_lv-1); break; case KN_CHARGEATK: { - int k = (wflag-1)/3; //+100% every 3 cells of distance - if( k > 2 ) k = 2; // ...but hard-limited to 300%. - skillratio += 100 * k; + int k = (flag-1)/3; //+100% every 3 cells of distance + if( k > 2 ) k = 2; // ...but hard-limited to 300%. + skillratio += 100 * k; } break; case HT_PHANTASMIC: @@ -2504,66 +2015,63 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 200; break; case HFLI_MOON: //[orn] - skillratio += 10+110*skill_lv; + skillratio += 10 + 110 * skill_lv; break; case HFLI_SBR44: //[orn] - skillratio += 100 *(skill_lv-1); + skillratio += 100 * (skill_lv-1); break; case NPC_VAMPIRE_GIFT: - skillratio += ((skill_lv-1)%5+1)*100; + skillratio += ((skill_lv-1)%5+1) * 100; break; case RK_SONICWAVE: - skillratio += 400 + 100 * skill_lv; - RE_LVL_DMOD(100); + skillratio += -100 + 100 * (skill_lv + 5); + skillratio = skillratio * (100 + (status_get_lv(src)-100) / 2) / 100; break; case RK_HUNDREDSPEAR: skillratio += 500 + (80 * skill_lv); - if( sd ) - { + if( sd ){ short index = sd->equip_index[EQI_HAND_R]; if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) - skillratio += max(10000 - sd->inventory_data[index]->weight, 0) / 10; - skillratio += 50 * pc->checkskill(sd,LK_SPIRALPIERCE); - } // (1 + [(Casters Base Level - 100) / 200]) - skillratio = skillratio * (100 + (status_get_lv(src)-100) / 2) / 100; + skillratio += (10000 - min(10000, sd->inventory_data[index]->weight)) / 10; + skillratio = skillratio * (100 + (status_get_lv(src)-100) / 2) / 100 + 50 * pc->checkskill(sd,LK_SPIRALPIERCE); + } break; case RK_WINDCUTTER: - skillratio += 50 * skill_lv; + skillratio += -100 + 50 * (skill_lv + 2); RE_LVL_DMOD(100); break; case RK_IGNITIONBREAK: i = distance_bl(src,target); if( i < 2 ) - skillratio = 200 + 200 * skill_lv; + skillratio += 300 * skill_lv; else if( i < 4 ) - skillratio = 100 + 200 * skill_lv; + skillratio += 250 * skill_lv; else - skillratio = 100 + 100 * skill_lv; - RE_LVL_DMOD(100); - if( sstatus->rhw.ele == ELE_FIRE ) - skillratio += skillratio / 2; + skillratio += 200 * skill_lv; + skillratio = (skillratio - 100) * (100 + (status_get_lv(src)-100)) / 100; + if( status->rhw.ele == ELE_FIRE ) + skillratio += 100 * skill_lv; break; case RK_CRUSHSTRIKE: if( sd ) {//ATK [{Weapon Level * (Weapon Upgrade Level + 6) * 100} + (Weapon ATK) + (Weapon Weight)]% short index = sd->equip_index[EQI_HAND_R]; if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) - skillratio = sd->inventory_data[index]->weight/10 + sstatus->rhw.atk + + skillratio += -100 + sd->inventory_data[index]->weight/10 + status->rhw.atk + 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6); } break; case RK_STORMBLAST: - skillratio = 100 * (sd ? pc->checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (sstatus->int_ / 4); + skillratio += -100 + 100 * (sd ? pc->checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (status_get_int(src) / 4); break; case RK_PHANTOMTHRUST: - skillratio = 50 * skill_lv + 10 * ( sd ? pc->checkskill(sd,KN_SPEARMASTERY) : 10); - //if( s_level > 100 ) skillratio += skillratio * s_level / 150; // Base level bonus. This is official, but is disabled until I can confirm something with was changed or not. [Rytech] - //if( s_level > 100 ) skillratio += skillratio * (s_level - 100) / 200; // Base level bonus. + skillratio += -100 + 50 * skill_lv + 10 * ( sd ? pc->checkskill(sd,KN_SPEARMASTERY) : 10); + RE_LVL_DMOD(150); break; /** - * GC Guilotine Cross - **/ + * GC Guilotine Cross + **/ case GC_CROSSIMPACT: skillratio += 900 + 100 * skill_lv; RE_LVL_DMOD(120); @@ -2575,7 +2083,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list //ATK [{(Skill Level x 100) + 300} x Caster's Base Level / 120]% + ATK [(AGI x 2) + (Caster's Job Level x 4)]% skillratio += 200 + (100 * skill_lv); RE_LVL_DMOD(120); - skillratio += sstatus->agi + (sd?sd->status.job_level:0) * 4; + skillratio += status_get_agi(src) * 2 + (sd?sd->status.job_level:0) * 4; break; case GC_ROLLINGCUTTER: skillratio += -50 + 50 * skill_lv; @@ -2585,17 +2093,20 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 300 + 80 * skill_lv; RE_LVL_DMOD(100); if( sc && sc->data[SC_ROLLINGCUTTER] ) - skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * sstatus->agi; + skillratio += sc->data[SC_ROLLINGCUTTER]->val1 * status_get_agi(src); + break; + case GC_DARKCROW: + skillratio += 100 * (skill_lv - 1); break; /** - * Arch Bishop - **/ + * Arch Bishop + **/ case AB_DUPLELIGHT_MELEE: skillratio += 10 * skill_lv; break; /** - * Ranger - **/ + * Ranger + **/ case RA_ARROWSTORM: skillratio += 900 + 80 * skill_lv; RE_LVL_DMOD(100); @@ -2603,8 +2114,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case RA_AIMEDBOLT: skillratio += 400 + 50 * skill_lv; RE_LVL_DMOD(100); - if( tsc && (tsc->data[SC_BITE] || tsc->data[SC_ANKLE] || tsc->data[SC_ELECTRICSHOCKER]) ) - wd.div_ = tstatus->size + 2 + ( (rnd()%100 < 50-tstatus->size*10) ? 1 : 0 ); break; case RA_CLUSTERBOMB: skillratio += 100 + 100 * skill_lv; @@ -2613,7 +2122,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 200; break; case RA_WUGSTRIKE: - skillratio = 200 * skill_lv; + skillratio += -100 + 200 * skill_lv; break; case RA_WUGBITE: skillratio += 300 + 200 * skill_lv; @@ -2623,18 +2132,18 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 50 * skill_lv; break; /** - * Mechanic - **/ + * Mechanic + **/ case NC_BOOSTKNUCKLE: - skillratio += 100 + 100 * skill_lv + sstatus->dex; + skillratio += 100 + 100 * skill_lv + status_get_dex(src); RE_LVL_DMOD(100); break; case NC_PILEBUNKER: - skillratio += 200 + 100 * skill_lv + sstatus->str; + skillratio += 200 + 100 * skill_lv + status_get_str(src); RE_LVL_DMOD(100); break; case NC_VULCANARM: - skillratio = 70 * skill_lv + sstatus->dex; + skillratio += -100 + 70 * skill_lv + status_get_dex(src); RE_LVL_DMOD(100); break; case NC_FLAMELAUNCHER: @@ -2661,11 +2170,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list RE_LVL_DMOD(100); break; case NC_POWERSWING: - skillratio += 80 + 20 * skill_lv + sstatus->str + sstatus->dex; + skillratio += 80 + 20 * skill_lv + status_get_str(src) + status_get_dex(src); RE_LVL_DMOD(100); break; case NC_AXETORNADO: - skillratio += 100 + 100 * skill_lv + sstatus->vit; + skillratio += 100 + 100 * skill_lv + status_get_vit(src); RE_LVL_DMOD(100); break; case SC_FATALMENACE: @@ -2678,7 +2187,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list skillratio += 100 + 100 * skill_lv; break; case LG_CANNONSPEAR:// Stimated formula. Still need confirm it. - skillratio += -100 + (50 + sstatus->str) * skill_lv; + skillratio += -100 + (50 + status_get_str(src)) * skill_lv; RE_LVL_DMOD(100); break; case LG_BANISHINGPOINT: @@ -2690,7 +2199,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list RE_LVL_DMOD(100); break; case LG_PINPOINTATTACK: - skillratio = ((100 * skill_lv) + (10 * status_get_agi(src)) ); + skillratio += -100 + ((100 * skill_lv) + (10 * status_get_agi(src)) ); RE_LVL_DMOD(100); break; case LG_RAGEBURST: @@ -2703,7 +2212,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield DEF x 10) + (Casters VIT x 2)] % if( sd ) { struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; - skillratio = status_get_lv(src) * 4 + status_get_vit(src) * 2; + skillratio += -100 + status_get_lv(src) * 4 + status_get_vit(src) * 2; if( shield_data ) skillratio += shield_data->def * 10; } else @@ -2714,668 +2223,1563 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list RE_LVL_DMOD(100); break; case LG_OVERBRAND: - skillratio = 400 * skill_lv + (pc->checkskill(sd,CR_SPEARQUICKEN) * 30); + skillratio += -100 + 400 * skill_lv + (pc->checkskill(sd,CR_SPEARQUICKEN) * 30); RE_LVL_DMOD(100); break; case LG_OVERBRAND_BRANDISH: - skillratio = 300 * skill_lv + (2 * (sstatus->str + sstatus->dex) / 3); + skillratio += -100 + 300 * skill_lv + (2 * (status_get_str(src) + status_get_dex(src)) / 3); RE_LVL_DMOD(100); break; case LG_OVERBRAND_PLUSATK: - skillratio = 150 * skill_lv; + skillratio += -100 + 150 * skill_lv; + RE_LVL_DMOD(100); + break; + case LG_RAYOFGENESIS: + skillratio += 200 + 300 * skill_lv; + RE_LVL_DMOD(100); + break; + case LG_EARTHDRIVE: + skillratio = (skillratio + 100) * skill_lv; + RE_LVL_DMOD(100); + break; + case LG_HESPERUSLIT: + skillratio += 120 * skill_lv - 100; + break; + case SR_DRAGONCOMBO: + skillratio += 40 * skill_lv; + RE_LVL_DMOD(100); + break; + case SR_SKYNETBLOW: + if( sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_DRAGONCOMBO )//ATK [{(Skill Level x 100) + (Caster AGI) + 150} x Caster Base Level / 100] % + skillratio += 100 * skill_lv + status_get_agi(src) + 50; + else //ATK [{(Skill Level x 80) + (Caster AGI)} x Caster Base Level / 100] % + skillratio += -100 + 80 * skill_lv + status_get_agi(src); + RE_LVL_DMOD(100); + break; + case SR_EARTHSHAKER: + if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || // [(Skill Level x 150) x (Caster Base Level / 100) + (Caster INT x 3)] % + tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC__INVISIBILITY]) ){ + skillratio += -100 + 150 * skill_lv; + RE_LVL_DMOD(100); + skillratio += status_get_int(src) * 3; + }else{ //[(Skill Level x 50) x (Caster Base Level / 100) + (Caster INT x 2)] % + skillratio += 50 * (skill_lv-2); + RE_LVL_DMOD(100); + skillratio += status_get_int(src) * 2; + } + break; + case SR_FALLENEMPIRE:// ATK [(Skill Level x 150 + 100) x Caster Base Level / 150] % + skillratio += 150 *skill_lv; + RE_LVL_DMOD(150); + break; + case SR_TIGERCANNON:// ATK [((Caster consumed HP + SP) / 4) x Caster Base Level / 100] % + { + int hp = status_get_max_hp(src) * (10 + 2 * skill_lv) / 100, + sp = status_get_max_sp(src) * (6 + skill_lv) / 100; + if( sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) // ATK [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] % + skillratio += -100 + hp+sp / 2; + else + skillratio += -100 + (hp+sp) / 4; + RE_LVL_DMOD(100); + } + break; + case SR_RAMPAGEBLASTER: + skillratio += 20 * skill_lv * (sd?sd->spiritball_old:5) - 100; + if( sc && sc->data[SC_EXPLOSIONSPIRITS] ){ + skillratio += sc->data[SC_EXPLOSIONSPIRITS]->val1 * 20; + RE_LVL_DMOD(120); + }else + RE_LVL_DMOD(150); + break; + case SR_KNUCKLEARROW: + if( flag&4 ){ // ATK [(Skill Level x 150) + (1000 x Target current weight / Maximum weight) + (Target Base Level x 5) x (Caster Base Level / 150)] % + skillratio += -100 + 150 * skill_lv + status_get_lv(target) * 5 * (status_get_lv(src) / 100) ; + if( tsd && tsd->weight ) + skillratio += 100 * (tsd->weight / tsd->max_weight); + }else // ATK [(Skill Level x 100 + 500) x Caster Base Level / 100] % + skillratio += 400 + (100 * skill_lv); + RE_LVL_DMOD(100); + break; + case SR_WINDMILL: // ATK [(Caster Base Level + Caster DEX) x Caster Base Level / 100] % + skillratio += -100 + status_get_lv(src) + status_get_dex(src); + RE_LVL_DMOD(100); + break; + case SR_GATEOFHELL: + if( sc && sc->data[SC_COMBOATTACK] + && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) + skillratio += 800 * skill_lv -100; + else + skillratio += 500 * skill_lv -100; + RE_LVL_DMOD(100); + break; + case SR_GENTLETOUCH_QUIET: + skillratio += 100 * skill_lv - 100 + status_get_dex(src); + RE_LVL_DMOD(100); + break; + case SR_HOWLINGOFLION: + skillratio += 300 * skill_lv - 100; + RE_LVL_DMOD(150); + break; + case SR_RIDEINLIGHTNING: // ATK [{(Skill Level x 200) + Additional Damage} x Caster Base Level / 100] % + if( (status->rhw.ele) == ELE_WIND || (status->lhw.ele) == ELE_WIND ) + skillratio += skill_lv * 50; + skillratio += -100 + 200 * skill_lv; + RE_LVL_DMOD(100); + break; + case WM_REVERBERATION_MELEE: + // ATK [{(Skill Level x 100) + 300} x Caster Base Level / 100] + skillratio += 200 + 100 * pc->checkskill(sd, WM_REVERBERATION); RE_LVL_DMOD(100); break; - case LG_RAYOFGENESIS: - skillratio = 300 + 300 * skill_lv; + case WM_SEVERE_RAINSTORM_MELEE: + //ATK [{(Caster DEX + AGI) x (Skill Level / 5)} x Caster Base Level / 100] % + skillratio += -100 + (status_get_dex(src) + status_get_agi(src)) * (skill_lv * 2); + RE_LVL_DMOD(100); + skillratio /= 10; + break; + case WM_GREAT_ECHO: + skillratio += 800 + 100 * skill_lv; + if( sd ) { // Still need official value [pakpil] + short lv = (short)skill_lv; + skillratio += 100 * skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0); + } + break; + case WM_SOUND_OF_DESTRUCTION: + skillratio += 400; + break; + case GN_CART_TORNADO: + // ATK [( Skill Level x 50 ) + ( Cart Weight / ( 150 - Caster Base STR ))] + ( Cart Remodeling Skill Level x 50 )] % + skillratio += -100 + 50 * skill_lv; + if( sd && sd->cart_weight) + skillratio += sd->cart_weight/10 / max(150-status_get_str(src),1) + pc->checkskill(sd, GN_REMODELING_CART) * 50; + break; + case GN_CARTCANNON: + // ATK [{( Cart Remodeling Skill Level x 50 ) x ( INT / 40 )} + ( Cart Cannon Skill Level x 60 )] % + skillratio += -100 + 60 * skill_lv; + if( sd ) skillratio += pc->checkskill(sd, GN_REMODELING_CART) * 50 * (status_get_int(src) / 40); + break; + case GN_SPORE_EXPLOSION: + skillratio += 200 + 100 * skill_lv; + break; + case GN_CRAZYWEED_ATK: + skillratio += 400 + 100 * skill_lv; + break; + case GN_SLINGITEM_RANGEMELEEATK: + if( sd ) { + switch( sd->itemid ) { + case 13260: // Apple Bomob + case 13261: // Coconut Bomb + case 13262: // Melon Bomb + case 13263: // Pinapple Bomb + skillratio += 400; // Unconfirded + break; + case 13264: // Banana Bomb 2000% + skillratio += 1900; + break; + case 13265: skillratio -= 75; break; // Black Lump 25% + case 13266: skillratio -= 25; break; // Hard Black Lump 75% + case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200% + } + } else + skillratio += 300; // Bombs + break; + case SO_VARETYR_SPEAR://ATK [{( Striking Level x 50 ) + ( Varetyr Spear Skill Level x 50 )} x Caster Base Level / 100 ] % + skillratio += -100 + 50 * skill_lv + ( sd ? pc->checkskill(sd, SO_STRIKING) * 50 : 0 ); + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += sd ? sd->status.job_level * 5 : 0; + break; + // Physical Elemantal Spirits Attack Skills + case EL_CIRCLE_OF_FIRE: + case EL_FIRE_BOMB_ATK: + case EL_STONE_RAIN: + skillratio += 200; + break; + case EL_FIRE_WAVE_ATK: + skillratio += 500; + break; + case EL_TIDAL_WEAPON: + skillratio += 1400; + break; + case EL_WIND_SLASH: + skillratio += 100; + break; + case EL_HURRICANE: + skillratio += 600; + break; + case EL_TYPOON_MIS: + case EL_WATER_SCREW_ATK: + skillratio += 900; + break; + case EL_STONE_HAMMER: + skillratio += 400; + break; + case EL_ROCK_CRUSHER: + skillratio += 700; + break; + case KO_JYUMONJIKIRI: + skillratio += -100 + 150 * skill_lv; + RE_LVL_DMOD(120); + if( tsc && tsc->data[SC_KO_JYUMONJIKIRI] ) + skillratio += status_get_lv(src) * skill_lv; + case KO_HUUMARANKA: + skillratio += -100 + 150 * skill_lv + status_get_agi(src) + status_get_dex(src) + 100 * (sd ? pc->checkskill(sd, NJ_HUUMA) : 0); + break; + case KO_SETSUDAN: + skillratio += -100 + 100 * skill_lv; RE_LVL_DMOD(100); break; - case LG_EARTHDRIVE: - skillratio = (skillratio + 100) * skill_lv; - RE_LVL_DMOD(100); + case KO_BAKURETSU: + skillratio += -100 + (50 + status_get_dex(src) / 4) * skill_lv * (sd?pc->checkskill(sd,NJ_TOBIDOUGU):10) * 4 / 100; + RE_LVL_DMOD(120); + skillratio += 10 * (sd ? sd->status.job_level : 0); break; - case LG_HESPERUSLIT: - skillratio += 120 * skill_lv - 100; + case MH_NEEDLE_OF_PARALYZE: + skillratio += 600 + 100 * skill_lv; break; - case SR_DRAGONCOMBO: - skillratio += 40 * skill_lv; - RE_LVL_DMOD(100); + case MH_STAHL_HORN: + skillratio += 400 + 100 * skill_lv; break; - case SR_SKYNETBLOW: - //ATK [{(Skill Level x 80) + (Caster AGI)} x Caster Base Level / 100] % - skillratio = 80 * skill_lv + sstatus->agi; - if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO )//ATK [{(Skill Level x 100) + (Caster AGI) + 150} x Caster Base Level / 100] % - skillratio = 100 * skill_lv + sstatus->agi + 150; - RE_LVL_DMOD(100); + case MH_LAVA_SLIDE: + skillratio += -100 + 70 * skill_lv; break; - case SR_EARTHSHAKER: - if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || // [(Skill Level x 150) x (Caster Base Level / 100) + (Caster INT x 3)] % - tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC__INVISIBILITY]) ){ - skillratio = 150 * skill_lv; - RE_LVL_DMOD(100); - skillratio += sstatus->int_ * 3; - }else{ //[(Skill Level x 50) x (Caster Base Level / 100) + (Caster INT x 2)] % - skillratio += 50 * (skill_lv-2); - RE_LVL_DMOD(100); - skillratio += sstatus->int_ * 2; - } + case MH_TINDER_BREAKER: + case MH_MAGMA_FLOW: + skillratio += -100 + 100 * skill_lv; break; - case SR_FALLENEMPIRE:// ATK [(Skill Level x 150 + 100) x Caster Base Level / 150] % - skillratio += 150 *skill_lv; - RE_LVL_DMOD(150); - break; - case SR_TIGERCANNON:// ATK [((Caster consumed HP + SP) / 4) x Caster Base Level / 100] % - { - int hp = sstatus->max_hp * (10 + 2 * skill_lv) / 100, - sp = sstatus->max_sp * (6 + skill_lv) / 100; - skillratio = (hp+sp) / 4; - if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) // ATK [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] % - skillratio = hp+sp / 2; - RE_LVL_DMOD(100); + } + if( sc && sc->data[SC_EDP] ){ + skillratio -= addedratio; + if( skill_id == AS_SONICBLOW || + skill_id == GC_COUNTERSLASH || + skill_id == GC_CROSSIMPACT ) + skillratio >>= 1; + skillratio += addedratio; + } + } + if( skillratio < 1 ) + return 0; + return skillratio; +} +/*========================================== + * Check dammage trough status. + * ATK may be MISS, BLOCKED FAIL, reduc, increase, end status... + * After this we apply bg/gvg reduction + *------------------------------------------*/ +int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int damage,uint16 skill_id,uint16 skill_lv) +{ + struct map_session_data *sd = NULL; + struct status_change *sc; + struct status_change_entry *sce; + int div_ = d->div_, flag = d->flag; + + nullpo_ret(bl); + + if( !damage ) + return 0; + if( battle_config.ksprotection && mob_ksprotected(src, bl) ) + return 0; + + if (bl->type == BL_PC) { + sd=(struct map_session_data *)bl; + //Special no damage states + if(flag&BF_WEAPON && sd->special_state.no_weapon_damage) + damage -= damage * sd->special_state.no_weapon_damage / 100; + + if(flag&BF_MAGIC && sd->special_state.no_magic_damage) + damage -= damage * sd->special_state.no_magic_damage / 100; + + if(flag&BF_MISC && sd->special_state.no_misc_damage) + damage -= damage * sd->special_state.no_misc_damage / 100; + + if(!damage) return 0; + } + + sc = status_get_sc(bl); + + if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + return 1; + + if (skill_id == PA_PRESSURE) + return damage; //This skill bypass everything else. + + if( sc && sc->count ) + { + //First, sc_*'s that reduce damage to 0. + if( sc->data[SC_BASILICA] && !(status_get_mode(src)&MD_BOSS) ) + { + d->dmg_lv = ATK_BLOCK; + return 0; + } + if( sc->data[SC_WHITEIMPRISON] && skill_id != HW_GRAVITATION ) { // Gravitation and Pressure do damage without removing the effect + if( skill_id == MG_NAPALMBEAT || + skill_id == MG_SOULSTRIKE || + skill_id == WL_SOULEXPANSION || + (skill_id && skill->get_ele(skill_id, skill_lv) == ELE_GHOST) || + (!skill_id && (status_get_status_data(src))->rhw.ele == ELE_GHOST) + ){ + if( skill_id == WL_SOULEXPANSION ) + damage <<= 1; // If used against a player in White Imprison, the skill deals double damage. + status_change_end(bl,SC_WHITEIMPRISON,INVALID_TIMER); // Those skills do damage and removes effect + }else{ + d->dmg_lv = ATK_BLOCK; + return 0; + } + } + + if(sc->data[SC_ZEPHYR] && + flag&(BF_LONG|BF_SHORT)){ + d->dmg_lv = ATK_BLOCK; + return 0; + } + + if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT ) + { + struct skill_unit_group* group = skill->id2group(sc->data[SC_SAFETYWALL]->val3); + uint16 skill_id = sc->data[SC_SAFETYWALL]->val2; + if (group) { + if(skill_id == MH_STEINWAND){ + if (--group->val2<=0) + skill->del_unitgroup(group,ALC_MARK); + d->dmg_lv = ATK_BLOCK; + return 0; + } + /** + * in RE, SW possesses a lifetime equal to 3 times the caster's health + **/ + #ifdef RENEWAL + d->dmg_lv = ATK_BLOCK; + if ( ( group->val2 - damage) > 0 ) { + group->val2 -= damage; + } else + skill->del_unitgroup(group,ALC_MARK); + return 0; + #else + if (--group->val2<=0) + skill->del_unitgroup(group,ALC_MARK); + d->dmg_lv = ATK_BLOCK; + return 0; + #endif + } + status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER); + } + + if( ( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) || sc->data[SC__MANHOLE] ) { + d->dmg_lv = ATK_BLOCK; + return 0; + } + if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rnd()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) + { + clif->skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1); + d->dmg_lv = ATK_BLOCK; + sc_start2(bl,SC_COMBOATTACK,100,GC_WEAPONBLOCKING,src->id,2000); + return 0; + } + if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) + { + int delay; + clif->skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1); + // different delay depending on skill level [celest] + if (sce->val1 <= 5) + delay = 300; + else if (sce->val1 > 5 && sce->val1 <= 9) + delay = 200; + else + delay = 100; + unit_set_walkdelay(bl, iTimer->gettick(), delay, 1); + + if(sc->data[SC_CR_SHRINK] && rnd()%100<5*sce->val1) + skill->blown(bl,src,skill->get_blewcount(CR_SHRINK,1),-1,0); + return 0; + } + + if( (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 ) { + clif->skill_nodamage(bl, bl, RK_MILLENNIUMSHIELD, 1, 1); + sce->val3 -= damage; // absorb damage + d->dmg_lv = ATK_BLOCK; + sc_start(bl,SC_STUN,15,0,skill->get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stuned when one shield is broken. + if( sce->val3 <= 0 ) { // Shield Down + sce->val2--; + if( sce->val2 > 0 ) { + if( sd ) + clif->millenniumshield(sd,sce->val2); + sce->val3 = 1000; // Next Shield + } else + status_change_end(bl,SC_MILLENNIUMSHIELD,INVALID_TIMER); // All shields down + } + return 0; + } + + + if( (sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON && skill_id != WS_CARTTERMINATION && rnd()%100 < sce->val2 ) + { // attack blocked by Parrying + clif->skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1); + return 0; + } + + if(sc->data[SC_DODGE_READY] && ( !sc->opt1 || sc->opt1 == OPT1_BURNING ) && + (flag&BF_LONG || sc->data[SC_STRUP]) + && rnd()%100 < 20) { + if (sd && pc_issit(sd)) pc->setstand(sd); //Stand it to dodge. + clif->skill_nodamage(bl,bl,TK_DODGE,1,1); + if (!sc->data[SC_COMBOATTACK]) + sc_start4(bl, SC_COMBOATTACK, 100, TK_JUMPKICK, src->id, 1, 0, 2000); + return 0; + } + + if(sc->data[SC_HERMODE] && flag&BF_MAGIC) + return 0; + + if(sc->data[SC_NJ_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG) + return 0; + + if( sc->data[SC_NEUTRALBARRIER] && (flag&(BF_MAGIC|BF_LONG)) == (BF_MAGIC|BF_LONG) ) { + d->dmg_lv = ATK_MISS; + return 0; + } + + if((sce=sc->data[SC_KAUPE]) && rnd()%100 < sce->val2) + { //Kaupe blocks damage (skill or otherwise) from players, mobs, homuns, mercenaries. + clif->specialeffect(bl, 462, AREA); + //Shouldn't end until Breaker's non-weapon part connects. + if (skill_id != ASC_BREAKER || !(flag&BF_WEAPON)) + if (--(sce->val3) <= 0) //We make it work like Safety Wall, even though it only blocks 1 time. + status_change_end(bl, SC_KAUPE, INVALID_TIMER); + return 0; + } + + if( flag&BF_MAGIC && (sce=sc->data[SC_PRESTIGE]) && rnd()%100 < sce->val2) { + clif->specialeffect(bl, 462, AREA); // Still need confirm it. + return 0; + } + + if (((sce=sc->data[SC_NJ_UTSUSEMI]) || sc->data[SC_NJ_BUNSINJYUTSU]) + && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK)) { + + skill->additional_effect (src, bl, skill_id, skill_lv, flag, ATK_BLOCK, iTimer->gettick() ); + if( !status_isdead(src) ) + skill->counter_additional_effect( src, bl, skill_id, skill_lv, flag, iTimer->gettick() ); + if (sce) { + clif->specialeffect(bl, 462, AREA); + skill->blown(src,bl,sce->val3,-1,0); + } + //Both need to be consumed if they are active. + if (sce && --(sce->val2) <= 0) + status_change_end(bl, SC_NJ_UTSUSEMI, INVALID_TIMER); + if ((sce=sc->data[SC_NJ_BUNSINJYUTSU]) && --(sce->val2) <= 0) + status_change_end(bl, SC_NJ_BUNSINJYUTSU, INVALID_TIMER); + + return 0; + } + + //Now damage increasing effects + if( sc->data[SC_LEXAETERNA] && skill_id != PF_SOULBURN ) + { + if( src->type != BL_MER || skill_id == 0 ) + damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries + + if( skill_id != ASC_BREAKER || !(flag&BF_WEAPON) ) + status_change_end(bl, SC_LEXAETERNA, INVALID_TIMER); //Shouldn't end until Breaker's non-weapon part connects. + } + +#ifdef RENEWAL + if( sc->data[SC_RAID] ) { + damage += damage * 20 / 100; + + if (--sc->data[SC_RAID]->val1 == 0) + status_change_end(bl, SC_RAID, INVALID_TIMER); + } +#endif + + if( damage ) { + struct map_session_data *tsd = BL_CAST(BL_PC, src); + if( sc->data[SC_DEEP_SLEEP] ) { + damage += damage / 2; // 1.5 times more damage while in Deep Sleep. + status_change_end(bl,SC_DEEP_SLEEP,INVALID_TIMER); + } + if( tsd && sd && sc->data[SC_CRYSTALIZE] && flag&BF_WEAPON ){ + switch(tsd->status.weapon){ + case W_MACE: + case W_2HMACE: + case W_1HAXE: + case W_2HAXE: + damage = damage * 150/100; + break; + case W_MUSICAL: + case W_WHIP: + if(!sd->state.arrow_atk) + break; + case W_BOW: + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + case W_GRENADE: + case W_DAGGER: + case W_1HSWORD: + case W_2HSWORD: + damage = damage * 50/100; + break; + } + } + if( sc->data[SC_SIREN] ) + status_change_end(bl,SC_SIREN,INVALID_TIMER); + } + + //Finally damage reductions.... + // Assumptio doubles the def & mdef on RE mode, otherwise gives a reduction on the final damage. [Igniz] +#ifndef RENEWAL + if( sc->data[SC_ASSUMPTIO] ) { + if( map_flag_vs(bl->m) ) + damage = damage*2/3; //Receive 66% damage + else + damage >>= 1; //Receive 50% damage + } +#endif + + if(sc->data[SC_DEFENDER] && + (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + damage = damage * ( 100 - sc->data[SC_DEFENDER]->val2 ) / 100; + + if(sc->data[SC_GS_ADJUSTMENT] && + (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + damage -= damage * 20 / 100; + + if(sc->data[SC_FOGWALL] && skill_id != RK_DRAGONBREATH && skill_id != RK_DRAGONBREATH_WATER) { + if(flag&BF_SKILL) //25% reduction + damage -= damage * 25 / 100; + else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + damage >>= 2; //75% reduction + } + + // Compressed code, fixed by map.h [Epoque] + if (src->type == BL_MOB) { + int i; + if (sc->data[SC_MANU_DEF]) + for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) + if (mob_manuk[i]==((TBL_MOB*)src)->class_) { + damage -= damage * sc->data[SC_MANU_DEF]->val1 / 100; + break; } + if (sc->data[SC_SPL_DEF]) + for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) + if (mob_splendide[i]==((TBL_MOB*)src)->class_) { + damage -= damage * sc->data[SC_SPL_DEF]->val1 / 100; + break; + } + } + + if((sce=sc->data[SC_ARMOR]) && //NPC_DEFENDER + sce->val3&flag && sce->val4&flag) + damage -= damage * sc->data[SC_ARMOR]->val2 / 100; + +#ifdef RENEWAL + if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON || flag&BF_MAGIC) && skill_id != WS_CARTTERMINATION) +#else + if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON && skill_id != WS_CARTTERMINATION)) +#endif + { + struct status_data *status = status_get_status_data(bl); + int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval + per /=20; //Uses 20% SP intervals. + //SP Cost: 1% + 0.5% per every 20% SP + if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000)) + status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER); + //Reduction: 6% + 6% every 20% + damage -= damage * (6 * (1+per)) / 100; + } + if(sc->data[SC_GRANITIC_ARMOR]){ + damage -= damage * sc->data[SC_GRANITIC_ARMOR]->val2 / 100; + } + if(sc->data[SC_PAIN_KILLER]){ + damage -= damage * sc->data[SC_PAIN_KILLER]->val3 / 100; + } + if((sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) ){ + skill->castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,iTimer->gettick(),0); + } + + if( (sce = sc->data[SC_STONEHARDSKIN]) && flag&(BF_SHORT|BF_WEAPON) && damage > 0 ) { + sce->val2 -= damage; + if( src->type == BL_PC ) { + TBL_PC *ssd = BL_CAST(BL_PC, src); + if (ssd && ssd->status.weapon != W_BOW) + skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); + } else + skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); + // 30% chance to reduce monster's ATK by 25% for 10 seconds. + if( src->type == BL_MOB ) + sc_start(src, SC_NOEQUIPWEAPON, 30, 0, skill->get_time2(RK_STONEHARDSKIN, sce->val1)); + if( sce->val2 <= 0 ) + status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER); + } + +/** + * In renewal steel body reduces all incoming damage by 1/10 + **/ +#ifdef RENEWAL + if( sc->data[SC_STEELBODY] ) { + damage = damage > 10 ? damage / 10 : 1; + } +#endif + + //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie] + if( skill_id == RA_AIMEDBOLT && (sc->data[SC_WUGBITE] || sc->data[SC_ANKLESNARE] || sc->data[SC_ELECTRICSHOCKER]) ) + { + status_change_end(bl, SC_WUGBITE, INVALID_TIMER); + status_change_end(bl, SC_ANKLESNARE, INVALID_TIMER); + status_change_end(bl, SC_ELECTRICSHOCKER, INVALID_TIMER); + } + + //Finally Kyrie because it may, or not, reduce damage to 0. + if((sce = sc->data[SC_KYRIE]) && damage > 0){ + sce->val2-=damage; + if(flag&BF_WEAPON || skill_id == TF_THROWSTONE){ + if(sce->val2>=0) + damage=0; + else + damage=-sce->val2; + } + if((--sce->val3)<=0 || (sce->val2<=0) || skill_id == AL_HOLYLIGHT) + status_change_end(bl, SC_KYRIE, INVALID_TIMER); + } + + if( sc->data[SC_MEIKYOUSISUI] && rand()%100 < 40 ) // custom value + damage = 0; + + + if (!damage) return 0; + + if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) { + int dx[8]={0,-1,-1,-1,0,1,1,1}; + int dy[8]={1,1,0,-1,-1,-1,0,1}; + uint8 dir = iMap->calc_dir(bl, src->x, src->y); + if( unit_movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) { + clif->slide(bl,src->x-dx[dir],src->y-dy[dir]); + unit_setdir(bl, dir); + } + d->dmg_lv = ATK_DEF; + status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER); + return 0; + } + + //Probably not the most correct place, but it'll do here + //(since battle_drain is strictly for players currently) + if ((sce=sc->data[SC_HAMI_BLOODLUST]) && flag&BF_WEAPON && damage > 0 && + rnd()%100 < sce->val3) + status_heal(src, damage*sce->val4/100, 0, 3); + + if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) + pc->addspiritball(sd,skill->get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); + if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { + TBL_HOM *hd = BL_CAST(BL_HOM,bl); + if (hd) homun->addspiritball(hd, 10); //add a sphere + } + + if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) + status_change_spread(bl, src); // Deadly infect attacked side + + if( sc && sc->data[SC__SHADOWFORM] ) { + struct block_list *s_bl = iMap->id2bl(sc->data[SC__SHADOWFORM]->val2); + if( !s_bl || s_bl->m != bl->m ) { // If the shadow form target is not present remove the sc. + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + } else if( status_isdead(s_bl) || !battle->check_target(src,s_bl,BCT_ENEMY)) { // If the shadow form target is dead or not your enemy remove the sc in both. + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + if( s_bl->type == BL_PC ) + ((TBL_PC*)s_bl)->shadowform_id = 0; + } else { + if( (--sc->data[SC__SHADOWFORM]->val3) < 0 ) { // If you have exceded max hits supported, remove the sc in both. + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + if( s_bl->type == BL_PC ) + ((TBL_PC*)s_bl)->shadowform_id = 0; + } else { + status_damage(bl, s_bl, damage, 0, clif->damage(s_bl, s_bl, iTimer->gettick(), 500, 500, damage, -1, 0, 0), 0); + return ATK_NONE; + } + } + } + + } + + //SC effects from caster side. + sc = status_get_sc(src); + + if (sc && sc->count) { + if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + damage += damage * 75 / 100; + // [Epoque] + if (bl->type == BL_MOB) { + int i; + + if ( ((sce=sc->data[SC_MANU_ATK]) && (flag&BF_WEAPON)) || + ((sce=sc->data[SC_MANU_MATK]) && (flag&BF_MAGIC)) + ) + for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) + if (((TBL_MOB*)bl)->class_==mob_manuk[i]) { + damage += damage * sce->val1 / 100; break; - case SR_RAMPAGEBLASTER: - skillratio += 20 * skill_lv * (sd?sd->spiritball_old:5) - 100; - if( sc && sc->data[SC_EXPLOSIONSPIRITS] ){ - skillratio += sc->data[SC_EXPLOSIONSPIRITS]->val1 * 20; - RE_LVL_DMOD(120); - }else - RE_LVL_DMOD(150); - break; - case SR_KNUCKLEARROW: - if( wflag&4 ){ // ATK [(Skill Level x 150) + (1000 x Target current weight / Maximum weight) + (Target Base Level x 5) x (Caster Base Level / 150)] % - skillratio = 150 * skill_lv + status_get_lv(target) * 5 * (status_get_lv(src) / 100) ; - if( tsd && tsd->weight ) - skillratio += 100 * (tsd->weight / tsd->max_weight); - }else // ATK [(Skill Level x 100 + 500) x Caster Base Level / 100] % - skillratio += 400 + (100 * skill_lv); - RE_LVL_DMOD(100); - break; - case SR_WINDMILL: // ATK [(Caster Base Level + Caster DEX) x Caster Base Level / 100] % - skillratio = status_get_lv(src) + sstatus->dex; - RE_LVL_DMOD(100); - break; - case SR_GATEOFHELL: - if( sc && sc->data[SC_COMBO] - && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) - skillratio += 800 * skill_lv -100; - else - skillratio += 500 * skill_lv -100; - RE_LVL_DMOD(100); - break; - case SR_GENTLETOUCH_QUIET: - skillratio += 100 * skill_lv - 100 + sstatus->dex; - RE_LVL_DMOD(100); - break; - case SR_HOWLINGOFLION: - skillratio += 300 * skill_lv - 100; - RE_LVL_DMOD(150); - break; - case SR_RIDEINLIGHTNING: // ATK [{(Skill Level x 200) + Additional Damage} x Caster Base Level / 100] % - if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) - skillratio += skill_lv * 50; - skillratio += -100 + 200 * skill_lv; - RE_LVL_DMOD(100); - break; - case WM_REVERBERATION_MELEE: - // ATK [{(Skill Level x 100) + 300} x Caster Base Level / 100] - skillratio += 200 + 100 * pc->checkskill(sd, WM_REVERBERATION); - RE_LVL_DMOD(100); - break; - case WM_SEVERE_RAINSTORM_MELEE: - //ATK [{(Caster DEX + AGI) x (Skill Level / 5)} x Caster Base Level / 100] % - skillratio = (sstatus->dex + sstatus->agi) * (skill_lv * 2); - RE_LVL_DMOD(100); - skillratio /= 10; - break; - case WM_GREAT_ECHO: - skillratio += 800 + 100 * skill_lv; - if( sd ) { // Still need official value [pakpil] - short lv = (short)skill_lv; - skillratio += 100 * skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0); } - break; - case WM_SOUND_OF_DESTRUCTION: - skillratio += 400; - break; - case GN_CART_TORNADO: - // ATK [( Skill Level x 50 ) + ( Cart Weight / ( 150 - Caster Base STR ))] + ( Cart Remodeling Skill Level x 50 )] % - skillratio = 50 * skill_lv; - if( sd && sd->cart_weight) - skillratio += sd->cart_weight/10 / max(150-sstatus->str,1) + pc->checkskill(sd, GN_REMODELING_CART) * 50; - break; - case GN_CARTCANNON: - // ATK [{( Cart Remodeling Skill Level x 50 ) x ( INT / 40 )} + ( Cart Cannon Skill Level x 60 )] % - skillratio = 60 * skill_lv; - if( sd ) skillratio += pc->checkskill(sd, GN_REMODELING_CART) * 50 * (sstatus->int_ / 40); - break; - case GN_SPORE_EXPLOSION: - skillratio += 200 + 100 * skill_lv; - break; - case GN_CRAZYWEED_ATK: - skillratio += 400 + 100 * skill_lv; - break; - case GN_SLINGITEM_RANGEMELEEATK: - if( sd ) { - switch( sd->itemid ) { - case 13260: // Apple Bomob - case 13261: // Coconut Bomb - case 13262: // Melon Bomb - case 13263: // Pinapple Bomb - skillratio += 400; // Unconfirded - break; - case 13264: // Banana Bomb 2000% - skillratio += 1900; - break; - case 13265: skillratio -= 75; break; // Black Lump 25% - case 13266: skillratio -= 25; break; // Hard Black Lump 75% - case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200% - } - } else - skillratio += 300; // Bombs - break; - case SO_VARETYR_SPEAR://ATK [{( Striking Level x 50 ) + ( Varetyr Spear Skill Level x 50 )} x Caster Base Level / 100 ] % - skillratio = 50 * skill_lv + ( sd ? pc->checkskill(sd, SO_STRIKING) * 50 : 0 ); - if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level * 5 : 0; - break; - // Physical Elemantal Spirits Attack Skills - case EL_CIRCLE_OF_FIRE: - case EL_FIRE_BOMB_ATK: - case EL_STONE_RAIN: - skillratio += 200; - break; - case EL_FIRE_WAVE_ATK: - skillratio += 500; - break; - case EL_TIDAL_WEAPON: - skillratio += 1400; - break; - case EL_WIND_SLASH: - skillratio += 100; - break; - case EL_HURRICANE: - skillratio += 600; - break; - case EL_TYPOON_MIS: - case EL_WATER_SCREW_ATK: - skillratio += 900; - break; - case EL_STONE_HAMMER: - skillratio += 400; - break; - case EL_ROCK_CRUSHER: - skillratio += 700; - break; - case KO_JYUMONJIKIRI: - if( tsc && tsc->data[SC_JYUMONJIKIRI] ) - wd.div_ = wd.div_ * -1;// needs more info - skillratio += -100 + 150 * skill_lv; - case KO_HUUMARANKA: - skillratio += -100 + 150 * skill_lv + sstatus->dex/2 + sstatus->agi/2; // needs more info - break; - case KO_SETSUDAN: - skillratio += 100 * (skill_lv-1); - break; - case KO_BAKURETSU: - skillratio = 50 * skill_lv * (sd?pc->checkskill(sd,NJ_TOBIDOUGU):10); - break; - case MH_NEEDLE_OF_PARALYZE: - skillratio += 600 + 100 * skill_lv; - break; - case MH_STAHL_HORN: - skillratio += 400 + 100 * skill_lv; - break; - case MH_LAVA_SLIDE: - skillratio = 70 * skill_lv; - break; - case MH_TINDER_BREAKER: - case MH_MAGMA_FLOW: - skillratio += -100 + 100 * skill_lv; - break; + if ( ((sce=sc->data[SC_SPL_ATK]) && (flag&BF_WEAPON)) || + ((sce=sc->data[SC_SPL_MATK]) && (flag&BF_MAGIC)) + ) + for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) + if (((TBL_MOB*)bl)->class_==mob_splendide[i]) { + damage += damage * sce->val1 / 100; + break; + } + } + if( sc->data[SC_POISONINGWEAPON] && skill_id != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 ) + sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON, 1)); + if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) + status_change_spread(src, bl); + if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { + TBL_HOM *hd = BL_CAST(BL_HOM,bl); + if (hd) homun->addspiritball(hd, 10); + } + } + /* no data claims these settings affect anything other than players */ + if( damage && sd && bl->type == BL_PC ) { + switch( skill_id ) { + //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so dont worry about it */ + case HW_GRAVITATION: + case NJ_ZENYNAGE: + case KO_MUCHANAGE: + break; + default: + if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] + if (flag&BF_WEAPON) + damage = damage * map[bl->m].weapon_damage_rate / 100; + if (flag&BF_MAGIC) + damage = damage * map[bl->m].magic_damage_rate / 100; + if (flag&BF_MISC) + damage = damage * map[bl->m].misc_damage_rate / 100; + } else { //Normal attacks get reductions based on range. + if (flag & BF_SHORT) + damage = damage * map[bl->m].short_damage_rate / 100; + if (flag & BF_LONG) + damage = damage * map[bl->m].long_damage_rate / 100; + } + if(!damage) damage = 1; + break; + } + } + + if(battle_config.skill_min_damage && damage > 0 && damage < div_) + { + if ((flag&BF_WEAPON && battle_config.skill_min_damage&1) + || (flag&BF_MAGIC && battle_config.skill_min_damage&2) + || (flag&BF_MISC && battle_config.skill_min_damage&4) + ) + damage = div_; + } + + if( bl->type == BL_MOB && !status_isdead(bl) && src != bl) { + if (damage > 0 ) + mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),flag); + if (skill_id) + mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),MSC_SKILLUSED|(skill_id<<16)); + } + if( sd ) { + if( pc_ismadogear(sd) && rnd()%100 < 50 ) { + short element = skill->get_ele(skill_id, skill_lv); + if( !skill_id || element == -1 ) { //Take weapon's element + struct status_data *sstatus = NULL; + if( src->type == BL_PC && ((TBL_PC*)src)->bonus.arrow_ele ) + element = ((TBL_PC*)src)->bonus.arrow_ele; + else if( (sstatus = status_get_status_data(src)) ) { + element = sstatus->rhw.ele; + } + } + else if( element == -2 ) //Use enchantment's element + element = status_get_attack_sc_element(src,status_get_sc(src)); + else if( element == -3 ) //Use random element + element = rnd()%ELE_MAX; + if( element == ELE_FIRE || element == ELE_WATER ) + pc->overheat(sd,element == ELE_FIRE ? 1 : -1); + } + } + + return damage; +} + +/*========================================== + * Calculates BG related damage adjustments. + *------------------------------------------*/ +int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) +{ + if( !damage ) + return 0; + + if( bl->type == BL_MOB ) { + struct mob_data* md = BL_CAST(BL_MOB, bl); + + if( flag&BF_SKILL && (md->class_ == MOBID_BLUE_CRYST || md->class_ == MOBID_PINK_CRYST) ) + return 0; // Crystal cannot receive skill damage on battlegrounds + } + + return damage; +} + +/*========================================== + * Calculates GVG related damage adjustments. + *------------------------------------------*/ +int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,uint16 skill_id,uint16 skill_lv,int flag) +{ + struct mob_data* md = BL_CAST(BL_MOB, bl); + int class_ = status_get_class(bl); + + if (!damage) //No reductions to make. + return 0; + + if(md && md->guardian_data) { + if(class_ == MOBID_EMPERIUM && flag&BF_SKILL) { + //Skill immunity. + switch (skill_id) { +#ifndef RENEWAL + case MO_TRIPLEATTACK: +#endif + case HW_GRAVITATION: + break; + default: + return 0; + } + } + if(src->type != BL_MOB) { + struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild->search(status_get_guild_id(src)); + + if (class_ == MOBID_EMPERIUM && (!g || guild->checkskill(g,GD_APPROVAL) <= 0 )) + return 0; + + if (g && battle_config.guild_max_castles && guild->checkcastles(g)>=battle_config.guild_max_castles) + return 0; // [MouseJstr] + } + } + + switch (skill_id) { + case PA_PRESSURE: + case HW_GRAVITATION: + case NJ_ZENYNAGE: + case KO_MUCHANAGE: + break; + default: + /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka] + if (md && md->guardian_data) { + damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100; + } + */ + break; + } + + return damage; +} + +/*========================================== + * HP/SP drain calculation + *------------------------------------------*/ +int battle_calc_drain(int damage, int rate, int per) { + int diff = 0; + + if (per && rnd()%1000 < rate) { + diff = (damage * per) / 100; + if (diff == 0) { + if (per > 0) + diff = 1; + else + diff = -1; + } + } + return diff; +} + +/*========================================== + * Consumes ammo for the given skill. + *------------------------------------------*/ +void battle_consume_ammo(TBL_PC*sd, int skill_id, int lv) { + int qty=1; + if (!battle_config.arrow_decrement) + return; + + if (skill) { + qty = skill->get_ammo_qty(skill_id, lv); + if (!qty) qty = 1; + } + + if(sd->equip_index[EQI_AMMO]>=0) //Qty check should have been done in skill_check_condition + pc->delitem(sd,sd->equip_index[EQI_AMMO],qty,0,1,LOG_TYPE_CONSUME); + + sd->state.arrow_atk = 0; +} +//Skill Range Criteria +int battle_range_type(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv) { + if (battle_config.skillrange_by_distance && + (src->type&battle_config.skillrange_by_distance) + ) { //based on distance between src/target [Skotlex] + if (check_distance_bl(src, target, 5)) + return BF_SHORT; + return BF_LONG; + } + //based on used skill's range + if (skill->get_range2(src, skill_id, skill_lv) < 5) + return BF_SHORT; + return BF_LONG; +} +int battle_adjust_skill_damage(int m, unsigned short skill_id) { + + if( map[m].skill_count ) { + int i; + ARR_FIND(0, map[m].skill_count, i, map[m].skills[i]->skill_id == skill_id ); + + if( i < map[m].skill_count ) { + return map[m].skills[i]->modifier; + } + + } + + return 0; +} +int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { + int i; + if (!sd->skillblown[0].id) + return 0; + //Apply the bonus blewcount. [Skotlex] + for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id; i++) { + if (sd->skillblown[i].id == skill_id) + return sd->skillblown[i].val; + } + return 0; +} +//For quick div adjustment. +#define damage_div_fix(dmg, div) { if (div > 1) (dmg)*=div; else if (div < 0) (div)*=-1; } +/*========================================== + * battle_calc_magic_attack [DracoRPG] + *------------------------------------------*/ +struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { + int i, nk; + short s_ele = 0; + unsigned int skillratio = 100; //Skill dmg modifiers. + + TBL_PC *sd; +// TBL_PC *tsd; + struct status_change *sc, *tsc; + struct Damage ad; + struct status_data *sstatus = status_get_status_data(src); + struct status_data *tstatus = status_get_status_data(target); + struct { + unsigned imdef : 1; + unsigned infdef : 1; + } flag; + + memset(&ad,0,sizeof(ad)); + memset(&flag,0,sizeof(flag)); + + if(src==NULL || target==NULL) + { + nullpo_info(NLP_MARK); + return ad; + } + //Initial Values + ad.damage = 1; + ad.div_=skill->get_num(skill_id,skill_lv); + ad.amotion=skill->get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; //Amotion should be 0 for ground skills. + ad.dmotion=tstatus->dmotion; + ad.blewcount = skill->get_blewcount(skill_id,skill_lv); + ad.flag=BF_MAGIC|BF_SKILL; + ad.dmg_lv=ATK_DEF; + nk = skill->get_nk(skill_id); + flag.imdef = nk&NK_IGNORE_DEF?1:0; + + sd = BL_CAST(BL_PC, src); +// tsd = BL_CAST(BL_PC, target); + sc = status_get_sc(src); + tsc = status_get_sc(target); + + //Initialize variables that will be used afterwards + s_ele = skill->get_ele(skill_id, skill_lv); + + if (s_ele == -1){ // pl=-1 : the skill takes the weapon's element + s_ele = sstatus->rhw.ele; + if( sd ){ //Summoning 10 charm will endow your weapon + ARR_FIND(1, 6, i, sd->charm[i] >= 10); + if( i < 5 ) s_ele = i; + } + }else if (s_ele == -2) //Use status element + s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + else if( s_ele == -3 ) //Use random element + s_ele = rnd()%ELE_MAX; + + if( skill_id == SO_PSYCHIC_WAVE ) { + if( sc && sc->count ) { + if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4; + else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4; + else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3; + else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4; + } + } + + //Set miscellaneous data that needs be filled + if(sd) { + sd->state.arrow_atk = 0; + ad.blewcount += battle->blewcount_bonus(sd, skill_id); + } + + //Skill Range Criteria + ad.flag |= battle->range_type(src, target, skill_id, skill_lv); + flag.infdef=(tstatus->mode&MD_PLANT?1:0); + if( target->type == BL_SKILL){ + TBL_SKILL *su = (TBL_SKILL*)target; + if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) + flag.infdef = 1; + } + + switch(skill_id) { + case MG_FIREWALL: + case NJ_KAENSIN: + ad.dmotion = 0; //No flinch animation. + if ( tstatus->def_ele == ELE_FIRE || battle->check_undead(tstatus->race, tstatus->def_ele) ) + ad.blewcount = 0; //No knockback + break; + case PR_SANCTUARY: + ad.dmotion = 0; //No flinch animation. + break; + case WL_HELLINFERNO: + if( mflag&ELE_DARK ) + s_ele = ELE_DARK; + break; + case KO_KAIHOU: + if( sd ){ + ARR_FIND(1, 6, i, sd->charm[i] > 0); + if( i < 5 ) + s_ele = i; } + break; #ifdef RENEWAL - if( sc && sc->data[SC_TRUESIGHT] ) - skillratio += 2*sc->data[SC_TRUESIGHT]->val1; + case CR_ACIDDEMONSTRATION: + case ASC_BREAKER: + case HW_MAGICCRASHER: + flag.imdef = 1; + break; #endif - ATK_RATE(skillratio); + } - //Constant/misc additions from skills - switch (skill_id) { - case MO_EXTREMITYFIST: - ATK_ADD(250 + 150*skill_lv); - break; - case TK_DOWNKICK: - case TK_STORMKICK: - case TK_TURNKICK: - case TK_COUNTER: - case TK_JUMPKICK: - //TK_RUN kick damage bonus. - if(sd && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST) - ATK_ADD(10*pc->checkskill(sd, TK_RUN)); - break; - case GS_MAGICALBULLET: - if(sstatus->matk_max>sstatus->matk_min) { - ATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min)); - } else { - ATK_ADD(sstatus->matk_min); - } - break; - case NJ_SYURIKEN: - ATK_ADD(4*skill_lv); - break; + if (!flag.infdef) //No need to do the math for plants + { #ifdef RENEWAL - case NJ_ISSEN: - // Damage = (current HP + atk * skill_lv) - (sdef+edef) - ATK_ADD(sstatus->hp); - wd.damage2 = 0;// needs more info if this really 0 for dual weilding KG/OB. [malufett] - if( sc && sc->data[SC_BUNSINJYUTSU] && (i=sc->data[SC_BUNSINJYUTSU]->val2) > 0){ - wd.div_ = -( i + 2 ); // mirror image number of hits + 2 - ATK_ADDRATE(20 + i*20); // (20 + 20 * mirror image) % - } - break; + ad.damage = 0; //reinitialize.. #endif - case HT_FREEZINGTRAP: - if(sd) - ATK_ADD( 40 * pc->checkskill(sd, RA_RESEARCHTRAP) ); - break; - case RA_WUGDASH ://(Caster Current Weight x 10 / 8) - if( sd && sd->weight ) - ATK_ADD( sd->weight / 8 ); - case RA_WUGSTRIKE: - case RA_WUGBITE: - if(sd) - ATK_ADD(30*pc->checkskill(sd, RA_TOOTHOFWUG)); - break; - case SR_GATEOFHELL: - ATK_ADD (sstatus->max_hp - status_get_hp(src)); - if(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE){ - ATK_ADD ( (sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status_get_lv(src) ); - }else{ - ATK_ADD ( (sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status_get_lv(src) ); - } - break; - case SR_TIGERCANNON: // (Tiger Cannon skill level x 240) + (Target Base Level x 40) - ATK_ADD( skill_lv * 240 + status_get_lv(target) * 40 ); - if( sc && sc->data[SC_COMBO] - && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) // (Tiger Cannon skill level x 500) + (Target Base Level x 40) - ATK_ADD( skill_lv * 500 + status_get_lv(target) * 40 ); - break; - case SR_FALLENEMPIRE:// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)] - ATK_ADD( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str); - if( tsd && tsd->weight ){ - ATK_ADD( (tsd->weight/10) * sstatus->dex / 120 ); - }else{ - ATK_ADD( status_get_lv(target) * 50 ); //mobs - } - break; - case KO_SETSUDAN: - if( tsc && tsc->data[SC_SPIRIT] ){ - ATK_ADDRATE(10*tsc->data[SC_SPIRIT]->val1);// +10% custom value. - status_change_end(target,SC_SPIRIT,INVALID_TIMER); - } - break; - case KO_KAIHOU: - if( sd ){ - ARR_FIND(1, 6, i, sd->talisman[i] > 0); - if( i < 5 ){ - s_ele = i; - ATK_ADDRATE(100 * sd->talisman[i]);// +100% custom value. - pc->del_talisman(sd, sd->talisman[i], i); +//MATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc +#define MATK_RATE( a ) { ad.damage= ad.damage*(a)/100; } +//Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage +#define MATK_ADDRATE( a ) { ad.damage+= ad.damage*(a)/100; } +//Adds an absolute value to damage. 100 = +100 damage +#define MATK_ADD( a ) { ad.damage+= a; } + + switch (skill_id) + { //Calc base damage according to skill + case AL_HEAL: + case PR_BENEDICTIO: + case PR_SANCTUARY: + /** + * Arch Bishop + **/ + case AB_HIGHNESSHEAL: + ad.damage = skill->calc_heal(src, target, skill_id, skill_lv, false); + break; + case PR_ASPERSIO: + ad.damage = 40; + break; + case ALL_RESURRECTION: + case PR_TURNUNDEAD: + //Undead check is on skill_castend_damageid code. + i = 20*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src) + + 200 - 200*tstatus->hp/tstatus->max_hp; // there is no changed in success chance in renewal. [malufett] + if(i > 700) i = 700; + if(rnd()%1000 < i && !(tstatus->mode&MD_BOSS)) + ad.damage = tstatus->hp; + else { + #ifdef RENEWAL + MATK_ADD(status_get_matk(src, 2)); + #else + ad.damage = status_get_lv(src) + sstatus->int_ + skill_lv * 10; + #endif + } + break; + case PF_SOULBURN: + ad.damage = tstatus->sp * 2; + break; + /** + * Arch Bishop + **/ + case AB_RENOVATIO: + //Damage calculation from iRO wiki. [Jobbie] + ad.damage = (int)((15 * status_get_lv(src)) + (1.5 * sstatus->int_)); + break; + default: { + MATK_ADD( status_get_matk(src, 2) ); + + if (nk&NK_SPLASHSPLIT) { // Divide MATK in case of multiple targets skill + if(mflag>0) + ad.damage/= mflag; + else + ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); + } + + if (sc){ + if( sc->data[SC_TELEKINESIS_INTENSE] && s_ele == ELE_GHOST ) + skillratio += sc->data[SC_TELEKINESIS_INTENSE]->val3; + } + switch(skill_id){ + case MG_FIREBOLT: + case MG_COLDBOLT: + case MG_LIGHTNINGBOLT: + if ( sc && sc->data[SC_SPELLFIST] && mflag&BF_SHORT ) { + skillratio += (sc->data[SC_SPELLFIST]->val4 * 100) + (sc->data[SC_SPELLFIST]->val2 * 100) - 100;// val4 = used bolt level, val2 = used spellfist level. [Rytech] + ad.div_ = 1;// ad mods, to make it work similar to regular hits [Xazax] + ad.flag = BF_WEAPON|BF_SHORT; + ad.type = 0; } + break; + default: + MATK_RATE(battle->calc_skillratio(BF_MAGIC, src, target, skill_id, skill_lv, skillratio, mflag)); + } + //Constant/misc additions from skills + if (skill_id == WZ_FIREPILLAR) + MATK_ADD(50); + if( sd && (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && + (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) + MATK_ADDRATE(i); + } + } +#ifndef HMAP_ZONE_DAMAGE_CAP_TYPE + if( target && skill_id ) { + for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { + if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { + if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { + if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + continue; + if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) + continue; } + if( ad.damage > map[target->m].zone->capped_skills[i]->cap ) + ad.damage = map[target->m].zone->capped_skills[i]->cap; + if( ad.damage2 > map[target->m].zone->capped_skills[i]->cap ) + ad.damage2 = map[target->m].zone->capped_skills[i]->cap; break; + } } } - //Div fix. - damage_div_fix(wd.damage, wd.div_); - - //The following are applied on top of current damage and are stackable. - if ( sc ) { -#ifndef RENEWAL - if( sc->data[SC_TRUESIGHT] ) - ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1); #endif - if( sc->data[SC_GLOOMYDAY_SK] && - ( skill_id == LK_SPIRALPIERCE || skill_id == KN_BRANDISHSPEAR || - skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN || - skill_id == LG_SHIELDPRESS ) ) - ATK_ADDRATE(sc->data[SC_GLOOMYDAY_SK]->val2); - if( sc->data[SC_EDP] ){ - switch(skill_id){ - case AS_SPLASHER: case AS_VENOMKNIFE: -#ifndef RENEWAL_EDP - case AS_GRIMTOOTH: +#ifdef RENEWAL + ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); #endif + if(sd) { + //Damage bonuses + if ((i = pc->skillatk_bonus(sd, skill_id))) + ad.damage += ad.damage*i/100; + + if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) + MATK_RATE(i); + + //Ignore Defense? + if (!flag.imdef && ( + sd->bonus.ignore_mdef_ele & ( 1 << tstatus->def_ele ) || + sd->bonus.ignore_mdef_race & ( 1 << tstatus->race ) || + sd->bonus.ignore_mdef_race & ( is_boss(target) ? 1 << RC_BOSS : 1 << RC_NONBOSS ) + )) + flag.imdef = 1; + } + + ad.damage = battle->calc_defense(BF_MAGIC, src, target, skill_id, skill_lv, ad.damage, (flag.imdef?1:0), 0); + + if (skill_id == NPC_EARTHQUAKE) + { //Adds atk2 to the damage, should be influenced by number of hits and skill-ratio, but not mdef reductions. [Skotlex] + //Also divide the extra bonuses from atk2 based on the number in range [Kevin] + if(mflag>0) + ad.damage+= (sstatus->rhw.atk2*skillratio/100)/mflag; + else + ShowError("Zero range by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); + } + + if(ad.damage<1) + ad.damage=1; + else if(sc){//only applies when hit + // TODO: there is another factor that contribute with the damage and need to be formulated. [malufett] + switch(skill_id){ + case MG_LIGHTNINGBOLT: + case MG_THUNDERSTORM: + case MG_FIREBOLT: + case MG_FIREWALL: + case MG_COLDBOLT: + case MG_FROSTDIVER: + case WZ_EARTHSPIKE: + case WZ_HEAVENDRIVE: + if(sc->data[SC_GUST_OPTION] || sc->data[SC_PETROLOGY_OPTION] + || sc->data[SC_PYROTECHNIC_OPTION] || sc->data[SC_AQUAPLAY_OPTION]) + ad.damage += (6 + sstatus->int_/4) + max(sstatus->dex-10,0)/30; break; -#ifndef RENEWAL_EDP - case ASC_BREAKER: case ASC_METEORASSAULT: break; -#else - case AS_SONICBLOW: - case ASC_BREAKER: - case GC_COUNTERSLASH: - case GC_CROSSIMPACT: - ATK_RATE(50); // only modifier is halved but still benefit with the damage bonus -#endif - default: - ATK_ADDRATE(sc->data[SC_EDP]->val3); - } } - if(sc->data[SC_STYLE_CHANGE]){ - TBL_HOM *hd = BL_CAST(BL_HOM,src); - if (hd) ATK_ADD(hd->homunculus.spiritball * 3); - } } - switch (skill_id) { - case AS_SONICBLOW: - if (sc && sc->data[SC_SPIRIT] && - sc->data[SC_SPIRIT]->val2 == SL_ASSASIN) - ATK_ADDRATE(map_flag_gvg(src->m)?25:100); //+25% dmg on woe/+100% dmg on nonwoe + if (!(nk&NK_NO_ELEFIX)) + ad.damage=battle->attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); - if(sd && pc->checkskill(sd,AS_SONICACCEL)>0) - ATK_ADDRATE(10); - break; - case CR_SHIELDBOOMERANG: - if(sc && sc->data[SC_SPIRIT] && - sc->data[SC_SPIRIT]->val2 == SL_CRUSADER) - ATK_ADDRATE(100); - break; - case NC_AXETORNADO: - if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) - ATK_ADDRATE(50); - break; + if( skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS ) + { //Apply the physical part of the skill's damage. [Skotlex] + struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); + ad.damage = battle->attr_fix(src, target, wd.damage + ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv) * (100 + 40*skill_lv)/100; + if( src == target ) + { + if( src->type == BL_PC ) + ad.damage = ad.damage/2; + else + ad.damage = 0; + } } - if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) - ATK_RATE(i); - - if( sd ) { - if (skill_id && (i = pc->skillatk_bonus(sd, skill_id))) - ATK_ADDRATE(i); - - if( skill_id != PA_SACRIFICE && skill_id != MO_INVESTIGATE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && !flag.cri ) - { //Elemental/Racial adjustments - if( sd->right_weapon.def_ratio_atk_ele & (1<def_ele) || - sd->right_weapon.def_ratio_atk_race & (1<race) || - sd->right_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS)) - ) - flag.pdef = 1; +#ifndef RENEWAL + ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); +#endif + } - if( sd->left_weapon.def_ratio_atk_ele & (1<def_ele) || - sd->left_weapon.def_ratio_atk_race & (1<race) || - sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS)) - ) - { //Pass effect onto right hand if configured so. [Skotlex] - if (battle_config.left_cardfix_to_right && flag.rh) - flag.pdef = 1; - else - flag.pdef2 = 1; - } - } + damage_div_fix(ad.damage, ad.div_); - if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS) - { //Ignore Defense? - if (!flag.idef && ( - sd->right_weapon.ignore_def_ele & (1<def_ele) || - sd->right_weapon.ignore_def_race & (1<race) || - sd->right_weapon.ignore_def_race & (is_boss(target)?1<0?1:-1; - if (!flag.idef2 && ( - sd->left_weapon.ignore_def_ele & (1<def_ele) || - sd->left_weapon.ignore_def_race & (1<race) || - sd->left_weapon.ignore_def_race & (is_boss(target)?1<calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv); + if( map_flag_gvg2(target->m) ) + ad.damage=battle->calc_gvg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); + else if( map[target->m].flag.battleground ) + ad.damage=battle->calc_bg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); + + switch( skill_id ) { /* post-calc modifiers */ + case SO_VARETYR_SPEAR: { // Physical damage. + struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); + if(!flag.infdef && ad.damage > 1) + ad.damage += wd.damage; + break; } + //case HM_ERASER_CUTTER: + } + + return ad; +} + +/*========================================== + * Calculate Misc dammage for skill_id + *------------------------------------------*/ +struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { + int temp; + short i, nk; + short s_ele; + + struct map_session_data *sd, *tsd; + struct Damage md; //DO NOT CONFUSE with md of mob_data! + struct status_data *sstatus = status_get_status_data(src); + struct status_data *tstatus = status_get_status_data(target); + struct status_change *tsc = status_get_sc(target); + struct status_change *sc = status_get_sc(src); + + memset(&md,0,sizeof(md)); + + if( src == NULL || target == NULL ){ + nullpo_info(NLP_MARK); + return md; + } + + //Some initial values + md.amotion=skill->get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; + md.dmotion=tstatus->dmotion; + md.div_=skill->get_num( skill_id,skill_lv ); + md.blewcount=skill->get_blewcount(skill_id,skill_lv); + md.dmg_lv=ATK_DEF; + md.flag=BF_MISC|BF_SKILL; + + nk = skill->get_nk(skill_id); - if (!flag.idef || !flag.idef2) - { //Defense reduction - short vit_def; - defType def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions. - short def2 = tstatus->def2; -#ifdef RENEWAL - if( tsc && tsc->data[SC_ASSUMPTIO] ) - def1 <<= 1; // only eDEF is doubled -#endif - if( sd ) - { - i = sd->ignore_def[is_boss(target)?RC_BOSS:RC_NONBOSS]; - i += sd->ignore_def[tstatus->race]; - if( i ) - { - if( i > 100 ) i = 100; - def1 -= def1 * i / 100; - def2 -= def2 * i / 100; - } - } + sd = BL_CAST(BL_PC, src); + tsd = BL_CAST(BL_PC, target); - if( sc && sc->data[SC_EXPIATIO] ){ - i = 5 * sc->data[SC_EXPIATIO]->val1; // 5% per level - def1 -= def1 * i / 100; - def2 -= def2 * i / 100; - } + if(sd) { + sd->state.arrow_atk = 0; + md.blewcount += battle->blewcount_bonus(sd, skill_id); + } - if( tsc && tsc->data[SC_GT_REVITALIZE] && tsc->data[SC_GT_REVITALIZE]->val4 ) - def2 += 2 * tsc->data[SC_GT_REVITALIZE]->val4; + s_ele = skill->get_ele(skill_id, skill_lv); + if (s_ele < 0 && s_ele != -3) //Attack that takes weapon's element for misc attacks? Make it neutral [Skotlex] + s_ele = ELE_NEUTRAL; + else if (s_ele == -3) //Use random element + s_ele = rnd()%ELE_MAX; - if( tsc && tsc->data[SC_CAMOUFLAGE] ){ - i = 5 * (10-tsc->data[SC_CAMOUFLAGE]->val4); - def1 -= def1 * i / 100; - def2 -= def2 * i / 100; - } + //Skill Range Criteria + md.flag |= battle->range_type(src, target, skill_id, skill_lv); - if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { - unsigned char target_count; //256 max targets should be a sane max - target_count = unit_counttargeted(target); - if(target_count >= battle_config.vit_penalty_count) { - if(battle_config.vit_penalty_type == 1) { - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - def2 = (def2 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - } else { //Assume type 2 - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; - def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; - } - } - if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex] - if(def2 < 1) def2 = 1; - } - //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def - if (tsd) //Sd vit-eq - { -#ifndef RENEWAL - //[VIT*0.5] + rnd([VIT*0.3], max([VIT*0.3],[VIT^2/150]-1)) - vit_def = def2*(def2-15)/150; - vit_def = def2/2 + (vit_def>0?rnd()%vit_def:0); -#else - vit_def = def2; -#endif - if((battle->check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players - src->type == BL_MOB && (temp=pc->checkskill(tsd,AL_DP)) > 0) - vit_def += temp*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn - if( src->type == BL_MOB && (temp=pc->checkskill(tsd,RA_RANGERMAIN))>0 && - (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) ) - vit_def += temp*5; + switch( skill_id ) + { #ifdef RENEWAL - if( temp == NJ_ISSEN ){//TODO: do better implementation if other skills(same func) are found [malufett] - vit_def += def1; - def1 = 0; - } -#endif - } - else { //Mob-Pet vit-eq -#ifndef RENEWAL - //VIT + rnd(0,[VIT/20]^2-1) - vit_def = (def2/20)*(def2/20); - vit_def = def2 + (vit_def>0?rnd()%vit_def:0); + case HT_LANDMINE: + case MA_LANDMINE: + case HT_BLASTMINE: + case HT_CLAYMORETRAP: + md.damage = skill_lv * sstatus->dex * (3+status_get_lv(src)/100) * (1+sstatus->int_/35); + md.damage += md.damage * (rnd()%20-10) / 100; + md.damage += 40 * (sd?pc->checkskill(sd,RA_RESEARCHTRAP):0); + break; #else - vit_def = def2; + case HT_LANDMINE: + case MA_LANDMINE: + md.damage=skill_lv*(sstatus->dex+75)*(100+sstatus->int_)/100; + break; + case HT_BLASTMINE: + md.damage=skill_lv*(sstatus->dex/2+50)*(100+sstatus->int_)/100; + break; + case HT_CLAYMORETRAP: + md.damage=skill_lv*(sstatus->dex/2+75)*(100+sstatus->int_)/100; + break; #endif - } + case HT_BLITZBEAT: + case SN_FALCONASSAULT: + //Blitz-beat Damage. + if(!sd || (temp = pc->checkskill(sd,HT_STEELCROW)) <= 0) + temp=0; + md.damage=(sstatus->dex/10+sstatus->int_/2+temp*3+40)*2; + if(mflag > 1) //Autocasted Blitz. + nk|=NK_SPLASHSPLIT; + if (skill_id == SN_FALCONASSAULT) { + //Div fix of Blitzbeat + temp = skill->get_num(HT_BLITZBEAT, 5); + damage_div_fix(md.damage, temp); - if (battle_config.weapon_defense_type) { - vit_def += def1*battle_config.weapon_defense_type; - def1 = 0; + //Falcon Assault Modifier + md.damage=md.damage*(150+70*skill_lv)/100; + } + break; + case TF_THROWSTONE: + md.damage=50; + break; + case BA_DISSONANCE: + md.damage=30+skill_lv*10; + if (sd) + md.damage+= 3*pc->checkskill(sd,BA_MUSICALLESSON); + break; + case NPC_SELFDESTRUCTION: + md.damage = sstatus->hp; + break; + case NPC_SMOKING: + md.damage=3; + break; + case NPC_DARKBREATH: + md.damage = 500 + (skill_lv-1)*1000 + rnd()%1000; + if(md.damage > 9999) md.damage = 9999; + break; + case PA_PRESSURE: + md.damage=500+300*skill_lv; + break; + case PA_GOSPEL: + md.damage = 1+rnd()%9999; + break; + case CR_ACIDDEMONSTRATION: +#ifdef RENEWAL + {// [malufett] + int matk=0, atk; + short tdef = status_get_total_def(target); + short tmdef = status_get_total_mdef(target); + int targetVit = min(120, status_get_vit(target)); + short totaldef = (tmdef + tdef - ((unsigned _int64)(tmdef + tdef) >> 32)) >> 1; + + matk = battle->calc_magic_attack(src, target, skill_id, skill_lv, mflag).damage; + atk = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, false, s_ele, ELE_NEUTRAL, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), md.flag); + md.damage = matk + atk; + if( src->type == BL_MOB ){ + totaldef = (tdef + tmdef) >> 1; + md.damage = 7 * targetVit * skill_lv * (atk + matk) / 100; + /* + // Pending [malufett] + if( unknown condition ) + md.damage >>= 1; + if( unknown condition ){ + md.damage = 7 * md.damage % 20; + md.damage = 7 * md.damage / 20; + }*/ + }else{ + float vitfactor = 0.0f, temp; + + if( (vitfactor=(status_get_vit(target)-120.0f)) > 0) + vitfactor = (vitfactor * (matk + atk) / 10) / status_get_vit(target); + temp = max(0, vitfactor) + (targetVit * (matk + atk)) / 10; + md.damage = (int)(temp * 70 * skill_lv / 100); } - #ifdef RENEWAL - /** - * RE DEF Reduction - * Damage = Attack * (4000+eDEF)/(4000+eDEF) - sDEF - * Pierce defence gains 1 atk per def/2 - **/ - - if( def1 == -400 ) /* being hit by a gazillion units, you hit the jackpot and got -400 which creates a division by 0 and subsequently crashes */ - def1 = -399; - - ATK_ADD2( - flag.pdef ?(def1/2):0, - flag.pdef2?(def1/2):0 - ); - if( !flag.idef && !flag.pdef ) - wd.damage = wd.damage * (4000+def1) / (4000+10*def1) - vit_def; - if( flag.lh && !flag.idef2 && !flag.pdef2 ) - wd.damage2 = wd.damage2 * (4000+def1) / (4000+10*def1) - vit_def; - - #else - if (def1 > 100) def1 = 100; - ATK_RATE2( - flag.idef ?100:(flag.pdef ? flag.pdef*(def1+vit_def) : (100-def1)), - flag.idef2?100:(flag.pdef2? flag.pdef2*(def1+vit_def) : (100-def1)) - ); - ATK_ADD2( - flag.idef ||flag.pdef ?0:-vit_def, - flag.idef2||flag.pdef2?0:-vit_def - ); - #endif + md.damage -= totaldef; } +#else + // updated the formula based on a Japanese formula found to be exact [Reddozen] + if(tstatus->vit+sstatus->int_) //crash fix + md.damage = (int)(7*tstatus->vit*sstatus->int_*sstatus->int_ / (10*(tstatus->vit+sstatus->int_))); + else + md.damage = 0; + if (tsd) md.damage>>=1; +#endif + if (md.damage < 0 || md.damage > INT_MAX>>1) + //Overflow prevention, will anyone whine if I cap it to a few billion? + //Not capped to INT_MAX to give some room for further damage increase. + md.damage = INT_MAX>>1; + break; - //Post skill/vit reduction damage increases - if( sc ) - { //SC skill damages - if(sc->data[SC_AURABLADE] + case KO_MUCHANAGE: + md.damage = skill->get_zeny(skill_id ,skill_lv); + md.damage = md.damage * (50 + rand()%50) / 100; + if ( is_boss(target) || (sd && !pc->checkskill(sd,NJ_TOBIDOUGU)) ) + md.damage >>= 1; + break; + case NJ_ZENYNAGE: + md.damage = skill->get_zeny(skill_id ,skill_lv); + if (!md.damage) md.damage = 2; + md.damage = rand()%md.damage + md.damage; + if (is_boss(target)) + md.damage=md.damage / 3; + else if (tsd) + md.damage=md.damage / 2; + break; + case GS_FLING: + md.damage = sd?sd->status.job_level:status_get_lv(src); + break; + case HVAN_EXPLOSION: //[orn] + md.damage = sstatus->max_hp * (50 + 50 * skill_lv) / 100; + break ; + case ASC_BREAKER: + { #ifndef RENEWAL - && skill_id != LK_SPIRALPIERCE && skill_id != ML_SPIRALPIERCE -#endif - ){ - int lv = sc->data[SC_AURABLADE]->val1; -#ifdef RENEWAL - lv *= ((skill_id == LK_SPIRALPIERCE || skill_id == ML_SPIRALPIERCE)?wd.div_:1); // +100 per hit in lv 5 + md.damage = 500+rnd()%500 + 5*skill_lv * sstatus->int_; + nk|=NK_IGNORE_FLEE|NK_NO_ELEFIX; //These two are not properties of the weapon based part. +#else + int ratio = 300 + 50 * skill_lv; + int matk = battle->calc_magic_attack(src, target, skill_id, skill_lv, mflag).damage; + short totaldef = status_get_total_def(target) + status_get_total_mdef(target); + int atk = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, false, s_ele, ELE_NEUTRAL, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), md.flag); + + if( sc && sc->data[SC_EDP] ) + ratio >>= 1; + md.damage = (matk + atk) * ratio / 100; + md.damage -= totaldef; #endif - ATK_ADD(20*lv); - } - - if(sc->data[SC_GN_CARTBOOST]) - ATK_ADD(10*sc->data[SC_GN_CARTBOOST]->val1); - - if(sc->data[SC_GT_CHANGE] && sc->data[SC_GT_CHANGE]->val2){ - struct block_list *bl; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] - if( (bl = iMap->id2bl(sc->data[SC_GT_CHANGE]->val2)) ) - ATK_ADD( ( status_get_dex(bl)/4 + status_get_str(bl)/2 ) * sc->data[SC_GT_CHANGE]->val1 / 5 ); - } - - if(sc->data[SC_CAMOUFLAGE]) - ATK_ADD(30 * (10-sc->data[SC_CAMOUFLAGE]->val4) ); } + break; + case HW_GRAVITATION: + md.damage = 200+200*skill_lv; + md.dmotion = 0; //No flinch animation. + break; + case NPC_EVILLAND: + md.damage = skill->calc_heal(src,target,skill_id,skill_lv,false); + break; + case RK_DRAGONBREATH: + case RK_DRAGONBREATH_WATER: + md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv; + RE_LVL_MDMOD(150); + if (sd) md.damage = md.damage * (100 + 5 * (pc->checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100; + md.flag |= BF_LONG|BF_WEAPON; + break; + /** + * Ranger + **/ + case RA_CLUSTERBOMB: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + md.damage = skill_lv * sstatus->dex + sstatus->int_ * 5 ; + RE_LVL_TMDMOD(); + if(sd) + { + int researchskill_lv = pc->checkskill(sd,RA_RESEARCHTRAP); + if(researchskill_lv) + md.damage = md.damage * 20 * researchskill_lv / (skill_id == RA_CLUSTERBOMB?50:100); + else + md.damage = 0; + }else + md.damage = md.damage * 200 / (skill_id == RA_CLUSTERBOMB?50:100); - //Refine bonus - if( sd && flag.weapon && skill_id != MO_INVESTIGATE && skill_id != MO_EXTREMITYFIST ) - { // Counts refine bonus multiple times - if( skill_id == MO_FINGEROFFENSIVE ) - { - ATK_ADD2(wd.div_*sstatus->rhw.atk2, wd.div_*sstatus->lhw.atk2); - } else { - ATK_ADD2(sstatus->rhw.atk2, sstatus->lhw.atk2); - } + break; + /** + * Mechanic + **/ + case NC_SELFDESTRUCTION: + { + short totaldef = status_get_total_def(target); + md.damage = ( (sd?pc->checkskill(sd,NC_MAINFRAME):10) + 8 ) * ( skill_lv + 1 ) * ( status_get_sp(src) + sstatus->vit ); + RE_LVL_MDMOD(100); + md.damage += status_get_hp(src) - totaldef; + } + break; + case NC_MAGMA_ERUPTION: + md.damage = 1200 + 400 * skill_lv; + break; + case GN_THORNS_TRAP: + md.damage = 100 + 200 * skill_lv + sstatus->int_; + break; + case GN_HELLS_PLANT_ATK: + //[{( Hell Plant Skill Level x Casters Base Level ) x 10 } + {( Casters INT x 7 ) / 2 } x { 18 + ( Casters Job Level / 4 )] x ( 5 / ( 10 - Summon Flora Skill Level )) + md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( sstatus->int_ * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - (sd?pc->checkskill(sd,AM_CANNIBALIZE):0)) ); + break; + case KO_HAPPOKUNAI: + { + struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); + short totaldef = status_get_total_def(target); + md.damage = 3 * wd.damage * (5 + skill_lv) / 5; + md.damage -= totaldef; } + break; + } - //Set to min of 1 - if (flag.rh && wd.damage < 1) wd.damage = 1; - if (flag.lh && wd.damage2 < 1) wd.damage2 = 1; + if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets + if(mflag>0) + md.damage/= mflag; + else + ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); + } - if (sd && flag.weapon && - skill_id != MO_INVESTIGATE && - skill_id != MO_EXTREMITYFIST && - skill_id != CR_GRANDCROSS) - { //Add mastery damage - if(skill_id != ASC_BREAKER && sd->status.weapon == W_KATAR && - (temp=pc->checkskill(sd,ASC_KATAR)) > 0) - { //Adv Katar Mastery is does not applies to ASC_BREAKER, - // but other masteries DO apply >_> - ATK_ADDRATE(10+ 2*temp); - } + damage_div_fix(md.damage, md.div_); - wd.damage = battle->add_mastery(sd,target,wd.damage,0); - if (flag.lh) - wd.damage2 = battle->add_mastery(sd,target,wd.damage2,1); + if (!(nk&NK_IGNORE_FLEE)) + { + i = 0; //Temp for "hit or no hit" + if(tsc && tsc->opt1 && tsc->opt1 != OPT1_STONEWAIT && tsc->opt1 != OPT1_BURNING) + i = 1; + else { + short + flee = tstatus->flee, +#ifdef RENEWAL + hitrate = 0; //Default hitrate +#else + hitrate = 80; //Default hitrate +#endif - if (sc && sc->data[SC_MIRACLE]) i = 2; //Star anger - else - ARR_FIND(0, MAX_PC_FEELHATE, i, t_class == sd->hate_mob[i]); - if (i < MAX_PC_FEELHATE && (temp=pc->checkskill(sd,sg_info[i].anger_id))) { - skillratio = sd->status.base_level + sstatus->dex + sstatus->luk; - if (i == 2) skillratio += sstatus->str; //Star Anger - if (temp<4) - skillratio /= 12-3*temp; - ATK_ADDRATE(skillratio); + if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { + unsigned char attacker_count; //256 max targets should be a sane max + attacker_count = unit_counttargeted(target); + if(attacker_count >= battle_config.agi_penalty_count) + { + if (battle_config.agi_penalty_type == 1) + flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; + else //asume type 2: absolute reduction + flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; + if(flee < 1) flee = 1; + } } - if (skill_id == NJ_SYURIKEN && (temp = pc->checkskill(sd,NJ_TOBIDOUGU)) > 0) { - ATK_ADD(3*temp); - } else if (skill_id == NJ_KUNAI) - ATK_ADD(60); - } - } //Here ends flag.hit section, the rest of the function applies to both hitting and missing attacks - else if(wd.div_ < 0) //Since the attack missed... - wd.div_ *= -1; - - if(sd && (temp=pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0) - ATK_ADD(temp*2); - if(skill_id==TF_POISON) - ATK_ADD(15*skill_lv); + hitrate+= sstatus->hit - flee; +#ifdef RENEWAL + if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window + hitrate += pc->checkskill(sd,AC_VULTURE); +#endif + if( skill_id == KO_MUCHANAGE ) + hitrate = (int)((10 - ((float)1 / (status_get_dex(src) + status_get_luk(src))) * 500) * ((float)skill_lv / 2 + 5)); + + hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); - if( !(nk&NK_NO_ELEFIX) && !n_ele ) - { //Elemental attribute fix - if( wd.damage > 0 ) - { - wd.damage=battle->attr_fix(src,target,wd.damage,s_ele,tstatus->def_ele, tstatus->ele_lv); - if( skill_id == MC_CARTREVOLUTION ) //Cart Revolution applies the element fix once more with neutral element - wd.damage = battle->attr_fix(src,target,wd.damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); - if( skill_id== GS_GROUNDDRIFT ) //Additional 50*lv Neutral damage. - wd.damage += battle->attr_fix(src,target,50*skill_lv,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); - } - if( flag.lh && wd.damage2 > 0 ) - wd.damage2 = battle->attr_fix(src,target,wd.damage2,s_ele_,tstatus->def_ele, tstatus->ele_lv); - if( sc && sc->data[SC_WATK_ELEMENT] ) - { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex] - int damage = battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, (flag.arrow?2:0)) * sc->data[SC_WATK_ELEMENT]->val2 / 100; - wd.damage += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); - - if( flag.lh ) { - damage = battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, (flag.arrow?2:0)) * sc->data[SC_WATK_ELEMENT]->val2 / 100; - wd.damage2 += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); - } + if(rnd()%100 < hitrate) + i = 1; + } + if (!i) { + md.damage = 0; + md.dmg_lv=ATK_FLEE; } - #ifdef RENEWAL - /** - * In RE Shield Bommerang takes weapon element only for damage calculation, - * - resist calculation is always against neutral - **/ - if ( skill_id == CR_SHIELDBOOMERANG ) - s_ele = s_ele_ = ELE_NEUTRAL; - #endif } - - if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) - return wd; //Enough, rest is not needed. #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { @@ -3386,1107 +3790,970 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( wd.damage > map[target->m].zone->capped_skills[i]->cap ) - wd.damage = map[target->m].zone->capped_skills[i]->cap; - if( wd.damage2 > map[target->m].zone->capped_skills[i]->cap ) - wd.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( md.damage > map[target->m].zone->capped_skills[i]->cap ) + md.damage = map[target->m].zone->capped_skills[i]->cap; + if( md.damage2 > map[target->m].zone->capped_skills[i]->cap ) + md.damage2 = map[target->m].zone->capped_skills[i]->cap; break; } } } #endif - if (sd) { - if (skill_id != CR_SHIELDBOOMERANG) //Only Shield boomerang doesn't takes the Star Crumbs bonus. - ATK_ADD2(wd.div_*sd->right_weapon.star, wd.div_*sd->left_weapon.star); - if (skill_id==MO_FINGEROFFENSIVE) { //The finger offensive spheres on moment of attack do count. [Skotlex] - ATK_ADD(wd.div_*sd->spiritball_old*3); - } else { - ATK_ADD(wd.div_*sd->spiritball*3); - } + md.damage = battle->calc_cardfix(BF_MISC, src, target, nk, s_ele, 0, md.damage, 0, md.flag); - //Card Fix, sd side - wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, 2, wd.flag); - if( flag.lh ) - wd.damage2 = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage2, 3, wd.flag); + if (sd && (i = pc->skillatk_bonus(sd, skill_id))) + md.damage += md.damage*i/100; + + if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) + md.damage = md.damage * i / 100; + + if(md.damage < 0) + md.damage = 0; + else if(md.damage && tstatus->mode&MD_PLANT){ + switch(skill_id){ + case HT_LANDMINE: + case MA_LANDMINE: + case HT_BLASTMINE: + case HT_CLAYMORETRAP: + case RA_CLUSTERBOMB: #ifdef RENEWAL - if( flag.cri ) - ATK_ADDRATE(sd->bonus.crit_atk_rate>=100?sd->bonus.crit_atk_rate-60:40); + break; #endif - if( skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN ) - { //Refine bonus applies after cards and elements. - short index= sd->equip_index[EQI_HAND_L]; - if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) - ATK_ADD(10*sd->status.inventory[index].refine); + default: + md.damage = 1; } + }else if( target->type == BL_SKILL ){ + TBL_SKILL *su = (TBL_SKILL*)target; + if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) + md.damage = 1; } - //Card Fix, tsd side - if(tsd) //if player on player then it was already measured above - wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, flag.lh, wd.flag); + if(!(nk&NK_NO_ELEFIX)) + md.damage=battle->attr_fix(src, target, md.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); - if( flag.infdef ) { //Plants receive 1 damage when hit - short class_ = status_get_class(target); - if( flag.hit || wd.damage > 0 ) - wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage - if( flag.lh && (flag.hit || wd.damage2 > 0) ) - wd.damage2 = wd.div_; - if( flag.hit && class_ == MOBID_EMPERIUM ) { - if(wd.damage2 > 0) { - wd.damage2 = battle->attr_fix(src,target,wd.damage2,s_ele_,tstatus->def_ele, tstatus->ele_lv); - wd.damage2 = battle->calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); - } - else if(wd.damage > 0) { - wd.damage = battle->attr_fix(src,target,wd.damage,s_ele_,tstatus->def_ele, tstatus->ele_lv); - wd.damage = battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - } - return wd; - } - if( !(battle_config.skill_min_damage&1) ) - //Do not return if you are supposed to deal greater damage to plants than 1. [Skotlex] - return wd; - } + md.damage=battle->calc_damage(src,target,&md,md.damage,skill_id,skill_lv); + if( map_flag_gvg2(target->m) ) + md.damage=battle->calc_gvg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); + else if( map[target->m].flag.battleground ) + md.damage=battle->calc_bg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); - if (sd) { - if (!flag.rh && flag.lh) { //Move lh damage to the rh - wd.damage = wd.damage2; - wd.damage2 = 0; - flag.rh=1; - flag.lh=0; - } else if(flag.rh && flag.lh) { //Dual-wield - if (wd.damage) { - if( (temp = pc->checkskill(sd,AS_RIGHT)) ) - ATK_RATER(50 + (temp * 10)) - else if( (temp = pc->checkskill(sd,KO_RIGHT)) ) - ATK_RATER(70 + (temp * 10)) - if(wd.damage < 1) wd.damage = 1; - } - if (wd.damage2) { - if( (temp = pc->checkskill(sd,AS_LEFT)) ) - ATK_RATEL(30 + (temp * 10)) - else if( (temp = pc->checkskill(sd,KO_LEFT)) ) - ATK_RATEL(50 + (temp * 10)) - if(wd.damage2 < 1) wd.damage2 = 1; + switch( skill_id ) { + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + if( md.damage == 1 ) break; + case RA_CLUSTERBOMB: + { + struct Damage wd; + wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); + md.damage += wd.damage; } - } else if(sd->status.weapon == W_KATAR && !skill_id) { //Katars (offhand damage only applies to normal attacks, tested on Aegis 10.2) - temp = pc->checkskill(sd,TF_DOUBLE); - wd.damage2 = wd.damage * (1 + (temp * 2))/100; - - if(wd.damage && !wd.damage2) wd.damage2 = 1; - flag.lh = 1; - } - } - - if(!flag.rh && wd.damage) - wd.damage=0; - - if(!flag.lh && wd.damage2) - wd.damage2=0; - - if( wd.damage + wd.damage2 ) - { //There is a total damage value - if(!wd.damage2) - { - wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); - if( map_flag_gvg2(target->m) ) - wd.damage=battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) - wd.damage=battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - } - else if(!wd.damage) - { - wd.damage2 = battle->calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv); - if( map_flag_gvg2(target->m) ) - wd.damage2 = battle->calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) - wd.damage = battle->calc_bg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); - } - else - { - int d1 = wd.damage + wd.damage2,d2 = wd.damage2; - wd.damage = battle->calc_damage(src,target,&wd,d1,skill_id,skill_lv); - if( map_flag_gvg2(target->m) ) - wd.damage = battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) - wd.damage = battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - wd.damage2 = d2*100/d1 * wd.damage/100; - if(wd.damage > 1 && wd.damage2 < 1) wd.damage2 = 1; - wd.damage-=wd.damage2; - } - } - //Reject Sword bugreport:4493 by Daegaladh - if(wd.damage && tsc && tsc->data[SC_REJECTSWORD] && - (src->type!=BL_PC || ( - ((TBL_PC *)src)->weapontype1 == W_DAGGER || - ((TBL_PC *)src)->weapontype1 == W_1HSWORD || - ((TBL_PC *)src)->status.weapon == W_2HSWORD - )) && - rnd()%100 < tsc->data[SC_REJECTSWORD]->val2 - ) { - ATK_RATER(50) - status_fix_damage(target,src,wd.damage,clif->damage(target,src,iTimer->gettick(),0,0,wd.damage,0,0,0)); - clif->skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_REJECTSWORD]->val1,1); - if( --(tsc->data[SC_REJECTSWORD]->val3) <= 0 ) - status_change_end(target, SC_REJECTSWORD, INVALID_TIMER); - } - if(skill_id == ASC_BREAKER) { //Breaker's int-based damage (a misc attack?) - struct Damage md = battle->calc_misc_attack(src, target, skill_id, skill_lv, wflag); - wd.damage += md.damage; - } - if( sc ) { - //SG_FUSION hp penalty [Komurka] - if (sc->data[SC_FUSION]) { - int hp= sstatus->max_hp; - if (sd && tsd) { - hp = 8*hp/100; - if ((sstatus->hp * 100) <= (sstatus->max_hp * 20)) - hp = sstatus->hp; - } else - hp = 2*hp/100; //2% hp loss per hit - status_zap(src, hp, 0); - } - /** - * affecting non-skills - **/ - if( !skill_id ) { - /** - * RK Enchant Blade - **/ - if( sc->data[SC_ENCHANTBLADE] && sd && ( (flag.rh && sd->weapontype1) || (flag.lh && sd->weapontype2) ) ) { - //[( ( Skill Lv x 20 ) + 100 ) x ( casterBaseLevel / 150 )] + casterInt - ATK_ADD( ( sc->data[SC_ENCHANTBLADE]->val1*20+100 ) * status_get_lv(src) / 150 + status_get_int(src) ); + break; + case NJ_ZENYNAGE: + if( sd ) { + if ( md.damage > sd->status.zeny ) + md.damage = sd->status.zeny; + pc->payzeny(sd, md.damage,LOG_TYPE_STEAL,NULL); } - } - status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); - } - if( skill_id == LG_RAYOFGENESIS ) { - struct Damage md = battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag); - wd.damage += md.damage; + break; } - return wd; + return md; } /*========================================== - * battle_calc_magic_attack [DracoRPG] + * battle_calc_weapon_attack (by Skotlex) *------------------------------------------*/ -struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { - int i, nk; - short s_ele = 0; +struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int wflag) +{ unsigned int skillratio = 100; //Skill dmg modifiers. + short temp=0; + short s_ele, s_ele_, t_class; + int i, nk; + bool n_ele = false; // non-elemental - TBL_PC *sd; -// TBL_PC *tsd; - struct status_change *sc, *tsc; - struct Damage ad; + struct map_session_data *sd, *tsd; + struct Damage wd; + struct status_change *sc = status_get_sc(src); + struct status_change *tsc = status_get_sc(target); struct status_data *sstatus = status_get_status_data(src); struct status_data *tstatus = status_get_status_data(target); struct { - unsigned imdef : 1; - unsigned infdef : 1; + unsigned hit : 1; //the attack Hit? (not a miss) + unsigned cri : 1; //Critical hit + unsigned idef : 1; //Ignore defense + unsigned idef2 : 1; //Ignore defense (left weapon) + unsigned pdef : 2; //Pierces defense (Investigate/Ice Pick) + unsigned pdef2 : 2; //1: Use def+def2/100, 2: Use def+def2/50 + unsigned infdef : 1; //Infinite defense (plants) + unsigned arrow : 1; //Attack is arrow-based + unsigned rh : 1; //Attack considers right hand (wd.damage) + unsigned lh : 1; //Attack considers left hand (wd.damage2) + unsigned weapon : 1; //It's a weapon attack (consider VVS, and all that) +#ifdef RENEWAL + unsigned tdef : 1; //Total defence reduction +#endif } flag; - memset(&ad,0,sizeof(ad)); + memset(&wd,0,sizeof(wd)); memset(&flag,0,sizeof(flag)); if(src==NULL || target==NULL) { nullpo_info(NLP_MARK); - return ad; - } - //Initial Values - ad.damage = 1; - ad.div_=skill->get_num(skill_id,skill_lv); - ad.amotion=skill->get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; //Amotion should be 0 for ground skills. - ad.dmotion=tstatus->dmotion; - ad.blewcount = skill->get_blewcount(skill_id,skill_lv); - ad.flag=BF_MAGIC|BF_SKILL; - ad.dmg_lv=ATK_DEF; - nk = skill->get_nk(skill_id); - flag.imdef = nk&NK_IGNORE_DEF?1:0; - - sd = BL_CAST(BL_PC, src); -// tsd = BL_CAST(BL_PC, target); - sc = status_get_sc(src); - tsc = status_get_sc(target); - - //Initialize variables that will be used afterwards - s_ele = skill->get_ele(skill_id, skill_lv); - - if (s_ele == -1){ // pl=-1 : the skill takes the weapon's element - s_ele = sstatus->rhw.ele; - if( sd ){ //Summoning 10 talisman will endow your weapon - ARR_FIND(1, 6, i, sd->talisman[i] >= 10); - if( i < 5 ) s_ele = i; - } - }else if (s_ele == -2) //Use status element - s_ele = status_get_attack_sc_element(src,status_get_sc(src)); - else if( s_ele == -3 ) //Use random element - s_ele = rnd()%ELE_MAX; - - if( skill_id == SO_PSYCHIC_WAVE ) { - if( sc && sc->count ) { - if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4; - else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4; - else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3; - else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4; - } - } - - //Set miscellaneous data that needs be filled - if(sd) { - sd->state.arrow_atk = 0; - ad.blewcount += battle->blewcount_bonus(sd, skill_id); - } - - //Skill Range Criteria - ad.flag |= battle->range_type(src, target, skill_id, skill_lv); - flag.infdef=(tstatus->mode&MD_PLANT?1:0); - if( target->type == BL_SKILL){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - flag.infdef = 1; - } - - switch(skill_id) { - case MG_FIREWALL: - case NJ_KAENSIN: - ad.dmotion = 0; //No flinch animation. - if ( tstatus->def_ele == ELE_FIRE || battle->check_undead(tstatus->race, tstatus->def_ele) ) - ad.blewcount = 0; //No knockback - break; - case PR_SANCTUARY: - ad.dmotion = 0; //No flinch animation. - break; + return wd; + } + //Initial flag + flag.rh=1; + flag.weapon=1; + flag.infdef=(tstatus->mode&MD_PLANT && skill_id != RA_CLUSTERBOMB +#ifdef RENEWAL + && skill_id != HT_FREEZINGTRAP +#endif + ?1:0); + if( target->type == BL_SKILL){ + TBL_SKILL *su = (TBL_SKILL*)target; + if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) + flag.infdef = 1; } - if (!flag.infdef) //No need to do the math for plants - { -#ifdef RENEWAL - ad.damage = 0; //reinitialize.. -#endif -//MATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc -#define MATK_RATE( a ) { ad.damage= ad.damage*(a)/100; } -//Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage -#define MATK_ADDRATE( a ) { ad.damage+= ad.damage*(a)/100; } -//Adds an absolute value to damage. 100 = +100 damage -#define MATK_ADD( a ) { ad.damage+= a; } - - switch (skill_id) - { //Calc base damage according to skill - case AL_HEAL: - case PR_BENEDICTIO: - case PR_SANCTUARY: - /** - * Arch Bishop - **/ - case AB_HIGHNESSHEAL: - ad.damage = skill->calc_heal(src, target, skill_id, skill_lv, false); - break; - case PR_ASPERSIO: - ad.damage = 40; - break; - case ALL_RESURRECTION: - case PR_TURNUNDEAD: - //Undead check is on skill_castend_damageid code. - #ifdef RENEWAL - i = 10*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src) - + 300 - 300*tstatus->hp/tstatus->max_hp; - #else - i = 20*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src) - + 200 - 200*tstatus->hp/tstatus->max_hp; - #endif - if(i > 700) i = 700; - if(rnd()%1000 < i && !(tstatus->mode&MD_BOSS)) - ad.damage = tstatus->hp; - else { - #ifdef RENEWAL - if (sstatus->matk_max > sstatus->matk_min) { - MATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min)); - } else { - MATK_ADD(sstatus->matk_min); - } - MATK_RATE(skill_lv); - #else - ad.damage = status_get_lv(src) + sstatus->int_ + skill_lv * 10; - #endif - } - break; - case PF_SOULBURN: - ad.damage = tstatus->sp * 2; - break; - /** - * Arch Bishop - **/ - case AB_RENOVATIO: - //Damage calculation from iRO wiki. [Jobbie] - ad.damage = (int)((15 * status_get_lv(src)) + (1.5 * sstatus->int_)); - break; - default: { - if (sstatus->matk_max > sstatus->matk_min) { - MATK_ADD(sstatus->matk_min+rnd()%(sstatus->matk_max-sstatus->matk_min)); - } else { - MATK_ADD(sstatus->matk_min); - } - - if (nk&NK_SPLASHSPLIT) { // Divide MATK in case of multiple targets skill - if(mflag>0) - ad.damage/= mflag; - else - ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); - } - - switch(skill_id){ - case MG_NAPALMBEAT: - skillratio += skill_lv*10-30; - break; - case MG_FIREBALL: - #ifdef RENEWAL - skillratio += 20*skill_lv; - #else - skillratio += skill_lv*10-30; - #endif - break; - case MG_SOULSTRIKE: - if (battle->check_undead(tstatus->race,tstatus->def_ele)) - skillratio += 5*skill_lv; - break; - case MG_FIREWALL: - skillratio -= 50; - break; - case MG_FIREBOLT: - case MG_COLDBOLT: - case MG_LIGHTNINGBOLT: - if ( sc && sc->data[SC_SPELLFIST] && mflag&BF_SHORT ) { - skillratio += (sc->data[SC_SPELLFIST]->val4 * 100) + (sc->data[SC_SPELLFIST]->val2 * 100) - 100;// val4 = used bolt level, val2 = used spellfist level. [Rytech] - ad.div_ = 1;// ad mods, to make it work similar to regular hits [Xazax] - ad.flag = BF_WEAPON|BF_SHORT; - ad.type = 0; - } - break; - case MG_THUNDERSTORM: - /** - * in Renewal Thunder Storm boost is 100% (in pre-re, 80%) - **/ - #ifndef RENEWAL - skillratio -= 20; - #endif - break; - case MG_FROSTDIVER: - skillratio += 10*skill_lv; - break; - case AL_HOLYLIGHT: - skillratio += 25; - if (sd && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_PRIEST) - skillratio *= 5; //Does 5x damage include bonuses from other skills? - break; - case AL_RUWACH: - skillratio += 45; - break; - case WZ_FROSTNOVA: - skillratio += (100+skill_lv*10)*2/3-100; - break; - case WZ_FIREPILLAR: - if (skill_lv > 10) - skillratio += 100; - else - skillratio -= 80; - break; - case WZ_SIGHTRASHER: - skillratio += 20*skill_lv; - break; - case WZ_WATERBALL: - skillratio += 30*skill_lv; - break; - case WZ_STORMGUST: - skillratio += 40*skill_lv; - break; - case HW_NAPALMVULCAN: - skillratio += 10*skill_lv-30; - break; - case SL_STIN: - skillratio += (tstatus->size!=SZ_SMALL?-99:10*skill_lv); //target size must be small (0) for full damage. - break; - case SL_STUN: - skillratio += (tstatus->size!=SZ_BIG?5*skill_lv:-99); //Full damage is dealt on small/medium targets - break; - case SL_SMA: - skillratio += -60 + status_get_lv(src); //Base damage is 40% + lv% - break; - case NJ_KOUENKA: - skillratio -= 10; - break; - case NJ_KAENSIN: - skillratio -= 50; - break; - case NJ_BAKUENRYU: - skillratio += 50*(skill_lv-1); - break; - case NJ_HYOUSYOURAKU: - skillratio += 50*skill_lv; - break; - case NJ_RAIGEKISAI: - skillratio += 60 + 40*skill_lv; - break; - case NJ_KAMAITACHI: - case NPC_ENERGYDRAIN: - skillratio += 100*skill_lv; - break; - case NPC_EARTHQUAKE: - skillratio += 100 +100*skill_lv +100*(skill_lv/2); - break; - #ifdef RENEWAL - case WZ_HEAVENDRIVE: - case WZ_METEOR: - skillratio += 25; - break; - case WZ_VERMILION: - { - int interval = 0, per = interval, ratio = per; - while( (per++) < skill_lv ){ - ratio += interval; - if(per%3==0) interval += 20; - } - if( skill_lv > 9 ) - ratio -= 10; - skillratio += ratio; - } - break; - case NJ_HUUJIN: - skillratio += 50; - break; - #else - case WZ_VERMILION: - skillratio += 20*skill_lv-20; - break; - #endif - /** - * Arch Bishop - **/ - case AB_JUDEX: - skillratio += 180 + 20 * skill_lv; - if (skill_lv > 4) skillratio += 20; - RE_LVL_DMOD(100); - break; - case AB_ADORAMUS: - skillratio += 400 + 100 * skill_lv; - RE_LVL_DMOD(100); - break; - case AB_DUPLELIGHT_MAGIC: - skillratio += 100 + 20 * skill_lv; - break; - /** - * Warlock - **/ - case WL_SOULEXPANSION: - skillratio += 300 + 100 * skill_lv + sstatus->int_; - RE_LVL_DMOD(100); - break; - case WL_FROSTMISTY: - skillratio += 100 + 100 * skill_lv; - RE_LVL_DMOD(100); - break; - case WL_JACKFROST: - if( tsc && tsc->data[SC_FREEZING] ){ - skillratio += 900 + 300 * skill_lv; - RE_LVL_DMOD(100); - }else{ - skillratio += 400 + 100 * skill_lv; - RE_LVL_DMOD(150); - } - break; - case WL_DRAINLIFE: - skillratio = 200 * skill_lv + sstatus->int_; - RE_LVL_DMOD(100); - break; - case WL_CRIMSONROCK: - skillratio += 1200 + 300 * skill_lv; - RE_LVL_DMOD(100); - break; - case WL_HELLINFERNO: - skillratio = 300 * skill_lv; - RE_LVL_DMOD(100); - // Shadow: MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) x 4/5 }] % - // Fire : MATK [{( Skill Level x 300 ) x ( Caster Base Level / 100 ) /5 }] % - if( mflag&ELE_DARK ){ skillratio *= 4; s_ele = ELE_DARK; } - skillratio /= 5; - break; - case WL_COMET: { - struct status_change * sc = status_get_sc(src); - if( sc ) - i = distance_xy(target->x, target->y, sc->comet_x, sc->comet_y); - else - i = 8; - if( i < 2 ) skillratio = 2500 + 500 * skill_lv; - else - if( i < 4 ) skillratio = 1600 + 400 * skill_lv; - else - if( i < 6 ) skillratio = 1200 + 300 * skill_lv; - else - skillratio = 800 + 200 * skill_lv; - } - break; - case WL_CHAINLIGHTNING_ATK: - skillratio += 100 + 300 * skill_lv; - RE_LVL_DMOD(100); - break; - case WL_EARTHSTRAIN: - skillratio += 1900 + 100 * skill_lv; - RE_LVL_DMOD(100); - break; - case WL_TETRAVORTEX_FIRE: - case WL_TETRAVORTEX_WATER: - case WL_TETRAVORTEX_WIND: - case WL_TETRAVORTEX_GROUND: - skillratio += 400 + 500 * skill_lv; - break; - case WL_SUMMON_ATK_FIRE: - case WL_SUMMON_ATK_WATER: - case WL_SUMMON_ATK_WIND: - case WL_SUMMON_ATK_GROUND: - skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech] - RE_LVL_DMOD(100); - break; - case LG_RAYOFGENESIS: - { - int16 lv = skill_lv; - int bandingBonus = 0; - if( sc && sc->data[SC_BANDING] ) - bandingBonus = 200 * (sd ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0) : 1); - skillratio = ((300 * skill_lv) + bandingBonus) * (sd ? sd->status.job_level : 1) / 25; - } - break; - case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield MDEF x 100) + (Casters INT x 2)] % - if( sd ) { - skillratio = status_get_lv(src) * 4 + sd->bonus.shieldmdef * 100 + status_get_int(src) * 2; - } else - skillratio += 1900; //2000% - break; - case WM_METALICSOUND: - skillratio += 120 * skill_lv + 60 * ( sd? pc->checkskill(sd, WM_LESSON) : 10 ) - 100; - break; - /*case WM_SEVERE_RAINSTORM: - skillratio += 50 * skill_lv; - break; - - WM_SEVERE_RAINSTORM just set a unit place, - refer to WM_SEVERE_RAINSTORM_MELEE to set the formula. - */ - case WM_REVERBERATION_MAGIC: - // MATK [{(Skill Level x 100) + 100} x Casters Base Level / 100] % - skillratio += 100 * (sd ? pc->checkskill(sd, WM_REVERBERATION) : 1); - RE_LVL_DMOD(100); - break; - case SO_FIREWALK: - skillratio = 300; - RE_LVL_DMOD(100); - if( sc && sc->data[SC_HEATER_OPTION] ) - skillratio += sc->data[SC_HEATER_OPTION]->val3; - break; - case SO_ELECTRICWALK: - skillratio = 300; - RE_LVL_DMOD(100); - if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level / 2 : 0; - break; - case SO_EARTHGRAVE: - skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_SEISMICWEAPON) : 10 ) + sstatus->int_ * skill_lv ); - RE_LVL_DMOD(100); - if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; - break; - case SO_DIAMONDDUST: - skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_FROSTWEAPON) : 10 ) + sstatus->int_ * skill_lv ); - RE_LVL_DMOD(100); - if( sc && sc->data[SC_COOLER_OPTION] ) - skillratio += sc->data[SC_COOLER_OPTION]->val3; - break; - case SO_POISON_BUSTER: - skillratio += 1100 + 300 * skill_lv; - if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; - break; - case SO_PSYCHIC_WAVE: - skillratio += -100 + skill_lv * 70 + (sstatus->int_ * 3); - RE_LVL_DMOD(100); - if( sc ){ - if( sc->data[SC_HEATER_OPTION] ) - skillratio += sc->data[SC_HEATER_OPTION]->val3; - else if(sc->data[SC_COOLER_OPTION] ) - skillratio += sc->data[SC_COOLER_OPTION]->val3; - else if(sc->data[SC_BLAST_OPTION] ) - skillratio += sc->data[SC_BLAST_OPTION]->val2; - else if(sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3; - } - break; - case SO_VARETYR_SPEAR: //MATK [{( Endow Tornado skill level x 50 ) + ( Caster INT x Varetyr Spear Skill level )} x Caster Base Level / 100 ] % - skillratio = status_get_int(src) * skill_lv + ( sd ? pc->checkskill(sd, SA_LIGHTNINGLOADER) * 50 : 0 ); - RE_LVL_DMOD(100); - if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level * 5 : 0; - break; - case SO_CLOUD_KILL: - skillratio += -100 + skill_lv * 40; - RE_LVL_DMOD(100); - if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; - break; - case GN_DEMONIC_FIRE: - if( skill_lv > 20) - { // Fire expansion Lv.2 - skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine] - } - else if( skill_lv > 10 ) - { // Fire expansion Lv.1 - skillratio += 110 + 20 * (skill_lv - 10) / 2; - } - else - skillratio += 110 + 20 * skill_lv; - break; - // Magical Elemental Spirits Attack Skills - case EL_FIRE_MANTLE: - case EL_WATER_SCREW: - skillratio += 900; - break; - case EL_FIRE_ARROW: - case EL_ROCK_CRUSHER_ATK: - skillratio += 200; - break; - case EL_FIRE_BOMB: - case EL_ICE_NEEDLE: - case EL_HURRICANE_ATK: - skillratio += 400; - break; - case EL_FIRE_WAVE: - case EL_TYPOON_MIS_ATK: - skillratio += 1100; - break; - case MH_ERASER_CUTTER: - if(skill_lv%2) skillratio += 400; //600:800:1000 - else skillratio += 700; //1000:1200 - skillratio += 100 * skill_lv; - break; - case MH_XENO_SLASHER: - if(skill_lv%2) skillratio += 350 + 50 * skill_lv; //500:600:700 - else skillratio += 400 + 100 * skill_lv; //700:900 - break; - case MH_HEILIGE_STANGE: - skillratio += 400 + 250 * skill_lv; - break; - case MH_POISON_MIST: - skillratio += 100 * skill_lv; - break; - } + //Initial Values + wd.type=0; //Normal attack + wd.div_=skill_id?skill->get_num(skill_id,skill_lv):1; + wd.amotion=(skill_id && skill->get_inf(skill_id)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills. + if(skill_id == KN_AUTOCOUNTER) + wd.amotion >>= 1; + wd.dmotion=tstatus->dmotion; + wd.blewcount=skill->get_blewcount(skill_id,skill_lv); + wd.flag = BF_WEAPON; //Initial Flag + wd.flag |= (skill_id||wflag)?BF_SKILL:BF_NORMAL; // Baphomet card's splash damage is counted as a skill. [Inkfish] + wd.dmg_lv=ATK_DEF; //This assumption simplifies the assignation later + nk = skill->get_nk(skill_id); + if( !skill_id && wflag ) //If flag, this is splash damage from Baphomet Card and it always hits. + nk |= NK_NO_CARDFIX_ATK|NK_IGNORE_FLEE; + flag.hit = nk&NK_IGNORE_FLEE?1:0; + flag.idef = flag.idef2 = nk&NK_IGNORE_DEF?1:0; + flag.tdef = 0; - MATK_RATE(skillratio); + if (sc && !sc->count) + sc = NULL; //Skip checking as there are no status changes active. + if (tsc && !tsc->count) + tsc = NULL; //Skip checking as there are no status changes active. - //Constant/misc additions from skills - if (skill_id == WZ_FIREPILLAR) - MATK_ADD(50); - } - } -#ifndef HMAP_ZONE_DAMAGE_CAP_TYPE - if( target && skill_id ) { - for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { - if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { - if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { - if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) - continue; - if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) - continue; - } - if( ad.damage > map[target->m].zone->capped_skills[i]->cap ) - ad.damage = map[target->m].zone->capped_skills[i]->cap; - if( ad.damage2 > map[target->m].zone->capped_skills[i]->cap ) - ad.damage2 = map[target->m].zone->capped_skills[i]->cap; - break; + sd = BL_CAST(BL_PC, src); + tsd = BL_CAST(BL_PC, target); + + if(sd) + wd.blewcount += battle->blewcount_bonus(sd, skill_id); + + //Set miscellaneous data that needs be filled regardless of hit/miss + if( + (sd && sd->state.arrow_atk) || + (!sd && ((skill_id && skill->get_ammotype(skill_id)) || sstatus->rhw.range>3)) + ) + flag.arrow = 1; + + if(skill_id) { + wd.flag |= battle->range_type(src, target, skill_id, skill_lv); + switch(skill_id) { + case MO_FINGEROFFENSIVE: + if(sd) { + if (battle_config.finger_offensive_type) + wd.div_ = 1; + else + wd.div_ = sd->spiritball_old; } - } - } + break; + case HT_PHANTASMIC: + //Since these do not consume ammo, they need to be explicitly set as arrow attacks. + flag.arrow = 1; + break; +#ifndef RENEWAL + case PA_SHIELDCHAIN: + case CR_SHIELDBOOMERANG: #endif + case LG_SHIELDPRESS: + case LG_EARTHDRIVE: + flag.weapon = 0; + break; + + case KN_PIERCE: + case ML_PIERCE: + wd.div_= (wd.div_>0?tstatus->size+1:-(tstatus->size+1)); + break; + + case TF_DOUBLE: //For NPC used skill. + case GS_CHAINACTION: + wd.type = 0x08; + break; + + case GS_GROUNDDRIFT: + case KN_SPEARSTAB: + case KN_BOWLINGBASH: + case MS_BOWLINGBASH: + case MO_BALKYOUNG: + case TK_TURNKICK: + wd.blewcount=0; + break; + + case KN_AUTOCOUNTER: + wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL; + break; + + case NPC_CRITICALSLASH: + case LG_PINPOINTATTACK: + flag.cri = 1; //Always critical skill. + break; + + case LK_SPIRALPIERCE: + if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC; + break; + + case MO_INVESTIGATE: + flag.pdef = flag.pdef2 = 2; + break; + + case RA_AIMEDBOLT: + if( tsc && (tsc->data[SC_WUGBITE] || tsc->data[SC_ANKLESNARE] || tsc->data[SC_ELECTRICSHOCKER]) ) + wd.div_ = tstatus->size + 2 + ( (rnd()%100 < 50-tstatus->size*10) ? 1 : 0 ); + break; #ifdef RENEWAL - ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); + case HW_MAGICCRASHER: + flag.tdef = 1; + break; #endif - if(sd) { - //Damage bonuses - if ((i = pc->skillatk_bonus(sd, skill_id))) - ad.damage += ad.damage*i/100; - - if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) - MATK_RATE(i); + } + } else //Range for normal attacks. + wd.flag |= flag.arrow?BF_LONG:BF_SHORT; + if ( (!skill_id || skill_id == PA_SACRIFICE) && tstatus->flee2 && rnd()%1000 < tstatus->flee2 ) + { //Check for Lucky Dodge + wd.type=0x0b; + wd.dmg_lv=ATK_LUCKY; + if (wd.div_ < 0) wd.div_*=-1; + return wd; + } - //Ignore Defense? - if (!flag.imdef && ( - sd->bonus.ignore_mdef_ele & ( 1 << tstatus->def_ele ) || - sd->bonus.ignore_mdef_race & ( 1 << tstatus->race ) || - sd->bonus.ignore_mdef_race & ( is_boss(target) ? 1 << RC_BOSS : 1 << RC_NONBOSS ) - )) - flag.imdef = 1; + t_class = status_get_class(target); + s_ele = s_ele_ = skill->get_ele(skill_id, skill_lv); + if( !skill_id || s_ele == -1 ) + { //Take weapon's element + s_ele = sstatus->rhw.ele; + s_ele_ = sstatus->lhw.ele; + if( sd ){ //Summoning 10 charm will endow your weapon. + ARR_FIND(1, 6, i, sd->charm[i] >= 10); + if( i < 5 ) s_ele = s_ele_ = i; + } + if( flag.arrow && sd && sd->bonus.arrow_ele ) + s_ele = sd->bonus.arrow_ele; + if( battle_config.attack_attr_none&src->type ) + n_ele = true; //Weapon's element is "not elemental" + } + else if( s_ele == -2 ) //Use enchantment's element + s_ele = s_ele_ = status_get_attack_sc_element(src,sc); + else if( s_ele == -3 ) //Use random element + s_ele = s_ele_ = rnd()%ELE_MAX; + switch( skill_id ) + { + case GS_GROUNDDRIFT: + s_ele = s_ele_ = wflag; //element comes in flag. + break; + case LK_SPIRALPIERCE: + if (!sd) n_ele = false; //forced neutral for monsters + break; + } + + if (!(nk & NK_NO_ELEFIX) && !n_ele) + if (src->type == BL_HOM) + n_ele = true; //skill is "not elemental" + if (sc && sc->data[SC_GOLDENE_FERSE] && ((!skill_id && (rnd() % 100 < sc->data[SC_GOLDENE_FERSE]->val4)) || skill_id == MH_STAHL_HORN)) { + s_ele = s_ele_ = ELE_HOLY; + n_ele = false; + } + + if(!skill_id) + { //Skills ALWAYS use ONLY your right-hand weapon (tested on Aegis 10.2) + if (sd && sd->weapontype1 == 0 && sd->weapontype2 > 0) + { + flag.rh=0; + flag.lh=1; } + if (sstatus->lhw.atk) + flag.lh=1; + } - if(!flag.imdef){ - defType mdef = tstatus->mdef; - int mdef2= tstatus->mdef2; -#ifdef RENEWAL - if(tsc && tsc->data[SC_ASSUMPTIO]) - mdef <<= 1; // only eMDEF is doubled -#endif - if(sd) { - i = sd->ignore_mdef[is_boss(target)?RC_BOSS:RC_NONBOSS]; - i+= sd->ignore_mdef[tstatus->race]; - if (i) - { - if (i > 100) i = 100; - mdef -= mdef * i/100; - //mdef2-= mdef2* i/100; + if( sd && !skill_id ) { //Check for double attack. + if( ( ( skill_lv = pc->checkskill(sd,TF_DOUBLE) ) > 0 && sd->weapontype1 == W_DAGGER ) + || ( sd->bonus.double_rate > 0 && sd->weapontype1 != W_FIST ) //Will fail bare-handed + || ( sc && sc->data[SC_KAGEMUSYA] && sd->weapontype1 != W_FIST )) // Need confirmation + { //Success chance is not added, the higher one is used [Skotlex] + if( rnd()%100 < ( 5*skill_lv > sd->bonus.double_rate ? 5*skill_lv : sc && sc->data[SC_KAGEMUSYA]?sc->data[SC_KAGEMUSYA]->val1*3:sd->bonus.double_rate ) ) + { + wd.div_ = skill->get_num(TF_DOUBLE,skill_lv?skill_lv:1); + wd.type = 0x08; + } + } + else if( sd->weapontype1 == W_REVOLVER && (skill_lv = pc->checkskill(sd,GS_CHAINACTION)) > 0 && rnd()%100 < 5*skill_lv ) + { + wd.div_ = skill->get_num(GS_CHAINACTION,skill_lv); + wd.type = 0x08; + } + else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW + && (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1){ + int chance = rand()%100; + wd.type = 0x08; + switch(sc->data[SC_FEARBREEZE]->val1){ + case 5: + if( chance < 3){// 3 % chance to attack 5 times. + wd.div_ = 5; + break; + } + case 4: + if( chance < 7){// 6 % chance to attack 4 times. + wd.div_ = 4; + break; + } + case 3: + if( chance < 10){// 9 % chance to attack 3 times. + wd.div_ = 3; + break; + } + case 2: + case 1: + if( chance < 13){// 12 % chance to attack 2 times. + wd.div_ = 2; + break; + } } - } - #ifdef RENEWAL - /** - * RE MDEF Reduction - * Damage = Magic Attack * (1000+eMDEF)/(1000+eMDEF) - sMDEF - **/ - ad.damage = ad.damage * (1000 + mdef) / (1000 + mdef * 10) - mdef2; - #else - if(battle_config.magic_defense_type) - ad.damage = ad.damage - mdef*battle_config.magic_defense_type - mdef2; - else - ad.damage = ad.damage * (100-mdef)/100 - mdef2; - #endif + wd.div_ = min(wd.div_,sd->status.inventory[i].amount); + sc->data[SC_FEARBREEZE]->val4 = wd.div_-1; } + } - if (skill_id == NPC_EARTHQUAKE) - { //Adds atk2 to the damage, should be influenced by number of hits and skill-ratio, but not mdef reductions. [Skotlex] - //Also divide the extra bonuses from atk2 based on the number in range [Kevin] - if(mflag>0) - ad.damage+= (sstatus->rhw.atk2*skillratio/100)/mflag; - else - ShowError("Zero range by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); + //Check for critical + if( !flag.cri && !(wd.type&0x08) && sstatus->cri && + (!skill_id || + skill_id == KN_AUTOCOUNTER || + skill_id == SN_SHARPSHOOTING || skill_id == MA_SHARPSHOOTING || + skill_id == NJ_KIRIKAGE)) + { + short cri = sstatus->cri; + if (sd) + { + cri+= sd->critaddrace[tstatus->race]; + if(flag.arrow) + cri += sd->bonus.arrow_cri; } + if( sc && sc->data[SC_CAMOUFLAGE] ) + cri += 10 * (10-sc->data[SC_CAMOUFLAGE]->val4); +#ifndef RENEWAL + //The official equation is *2, but that only applies when sd's do critical. + //Therefore, we use the old value 3 on cases when an sd gets attacked by a mob + cri -= tstatus->luk*(!sd&&tsd?3:2); +#else + cri -= status_get_lv(target) / 15 + 2 * status_get_luk(target); +#endif - if(ad.damage<1) - ad.damage=1; - else if(sc){//only applies when hit - // TODO: there is another factor that contribute with the damage and need to be formulated. [malufett] - switch(skill_id){ - case MG_LIGHTNINGBOLT: - case MG_THUNDERSTORM: - case MG_FIREBOLT: - case MG_FIREWALL: - case MG_COLDBOLT: - case MG_FROSTDIVER: - case WZ_EARTHSPIKE: - case WZ_HEAVENDRIVE: - if(sc->data[SC_GUST_OPTION] || sc->data[SC_PETROLOGY_OPTION] - || sc->data[SC_PYROTECHNIC_OPTION] || sc->data[SC_AQUAPLAY_OPTION]) - ad.damage += (6 + sstatus->int_/4) + max(sstatus->dex-10,0)/30; - break; - } + if( tsc && tsc->data[SC_SLEEP] ) { + cri <<= 1; } - - if (!(nk&NK_NO_ELEFIX)) - ad.damage=battle->attr_fix(src, target, ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); - - if( skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS ) - { //Apply the physical part of the skill's damage. [Skotlex] - struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); - ad.damage = battle->attr_fix(src, target, wd.damage + ad.damage, s_ele, tstatus->def_ele, tstatus->ele_lv) * (100 + 40*skill_lv)/100; - if( src == target ) - { - if( src->type == BL_PC ) - ad.damage = ad.damage/2; + switch (skill_id) { + case KN_AUTOCOUNTER: + if(battle_config.auto_counter_type && + (battle_config.auto_counter_type&src->type)) + flag.cri = 1; else - ad.damage = 0; - } + cri <<= 1; + break; + case SN_SHARPSHOOTING: + case MA_SHARPSHOOTING: + cri += 200; + break; + case NJ_KIRIKAGE: + cri += 250 + 50*skill_lv; + break; } - + if(tsd && tsd->bonus.critical_def) + cri = cri * ( 100 - tsd->bonus.critical_def ) / 100; + if (rnd()%1000 < cri) + flag.cri = 1; + } + if (flag.cri) { + wd.type = 0x0a; #ifndef RENEWAL - ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); + flag.idef = flag.idef2 = #endif + flag.hit = 1; + } else { //Check for Perfect Hit + if(sd && sd->bonus.perfect_hit > 0 && rnd()%100 < sd->bonus.perfect_hit) + flag.hit = 1; + if (sc && sc->data[SC_FUSION]) { + flag.hit = 1; //SG_FUSION always hit [Komurka] + flag.idef = flag.idef2 = 1; //def ignore [Komurka] + } + if( !flag.hit ) + switch(skill_id) + { + case AS_SPLASHER: + if( !wflag ) // Always hits the one exploding. + flag.hit = 1; + break; + case CR_SHIELDBOOMERANG: + if( sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_CRUSADER ) + flag.hit = 1; + break; + } + if (tsc && !flag.hit && tsc->opt1 && tsc->opt1 != OPT1_STONEWAIT && tsc->opt1 != OPT1_BURNING) + flag.hit = 1; } - damage_div_fix(ad.damage, ad.div_); - - if (flag.infdef && ad.damage) - ad.damage = ad.damage>0?1:-1; - - ad.damage=battle->calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv); - if( map_flag_gvg2(target->m) ) - ad.damage=battle->calc_gvg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); - else if( map[target->m].flag.battleground ) - ad.damage=battle->calc_bg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); + if (!flag.hit) + { //Hit/Flee calculation + short + flee = tstatus->flee, +#ifdef RENEWAL + hitrate = 0; //Default hitrate +#else + hitrate = 80; //Default hitrate +#endif - switch( skill_id ) { /* post-calc modifiers */ - case SO_VARETYR_SPEAR: { // Physical damage. - struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); - if(!flag.infdef && ad.damage > 1) - ad.damage += wd.damage; - break; + if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { + unsigned char attacker_count; //256 max targets should be a sane max + attacker_count = unit_counttargeted(target); + if(attacker_count >= battle_config.agi_penalty_count) { + if (battle_config.agi_penalty_type == 1) + flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; + else //asume type 2: absolute reduction + flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; + if(flee < 1) flee = 1; + } } - //case HM_ERASER_CUTTER: - } - return ad; -} - -/*========================================== - * Calculate Misc dammage for skill_id - *------------------------------------------*/ -struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { - int temp; - short i, nk; - short s_ele; + hitrate+= sstatus->hit - flee; - struct map_session_data *sd, *tsd; - struct Damage md; //DO NOT CONFUSE with md of mob_data! - struct status_data *sstatus = status_get_status_data(src); - struct status_data *tstatus = status_get_status_data(target); + if(wd.flag&BF_LONG && !skill_id && //Fogwall's hit penalty is only for normal ranged attacks. + tsc && tsc->data[SC_FOGWALL]) + hitrate -= 50; - memset(&md,0,sizeof(md)); + if(sd && flag.arrow) + hitrate += sd->bonus.arrow_hit; +#ifdef RENEWAL + if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window + hitrate += pc->checkskill(sd,AC_VULTURE); +#endif + if(skill_id) + switch(skill_id) + { //Hit skill modifiers + //It is proven that bonus is applied on final hitrate, not hit. + case SM_BASH: + case MS_BASH: + hitrate += hitrate * 5 * skill_lv / 100; + break; + case MS_MAGNUM: + case SM_MAGNUM: + hitrate += hitrate * 10 * skill_lv / 100; + break; + case KN_AUTOCOUNTER: + case PA_SHIELDCHAIN: + case NPC_WATERATTACK: + case NPC_GROUNDATTACK: + case NPC_FIREATTACK: + case NPC_WINDATTACK: + case NPC_POISONATTACK: + case NPC_HOLYATTACK: + case NPC_DARKNESSATTACK: + case NPC_UNDEADATTACK: + case NPC_TELEKINESISATTACK: + case NPC_BLEEDING: + hitrate += hitrate * 20 / 100; + break; + case KN_PIERCE: + case ML_PIERCE: + hitrate += hitrate * 5 * skill_lv / 100; + break; + case AS_SONICBLOW: + if(sd && pc->checkskill(sd,AS_SONICACCEL)>0) + hitrate += hitrate * 50 / 100; + break; + case MC_CARTREVOLUTION: + case GN_CART_TORNADO: + case GN_CARTCANNON: + if( sd && pc->checkskill(sd, GN_REMODELING_CART) ) + hitrate += pc->checkskill(sd, GN_REMODELING_CART) * 4; + break; + case GC_VENOMPRESSURE: + hitrate += 10 + 4 * skill_lv; + break; + } - if( src == NULL || target == NULL ){ - nullpo_info(NLP_MARK); - return md; - } + if( sd ) { + // Weaponry Research hidden bonus + if ((temp = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0) + hitrate += hitrate * ( 2 * temp ) / 100; - //Some initial values - md.amotion=skill->get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; - md.dmotion=tstatus->dmotion; - md.div_=skill->get_num( skill_id,skill_lv ); - md.blewcount=skill->get_blewcount(skill_id,skill_lv); - md.dmg_lv=ATK_DEF; - md.flag=BF_MISC|BF_SKILL; + if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) && + (temp = pc->checkskill(sd, GN_TRAINING_SWORD))>0 ) + hitrate += 3 * temp; + } - nk = skill->get_nk(skill_id); + hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); +#ifdef RENEWAL + if( !sd ) + hitrate = cap_value(hitrate, 5, 95); +#endif + if(rnd()%100 >= hitrate) + wd.dmg_lv = ATK_FLEE; + else + flag.hit = 1; + } //End hit/miss calculation - sd = BL_CAST(BL_PC, src); - tsd = BL_CAST(BL_PC, target); + if (flag.hit && !flag.infdef) //No need to do the math for plants + { //Hitting attack - if(sd) { - sd->state.arrow_atk = 0; - md.blewcount += battle->blewcount_bonus(sd, skill_id); - } +//Assuming that 99% of the cases we will not need to check for the flag.rh... we don't. +//ATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc +#define ATK_RATE( a ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(a)/100; } +#define ATK_RATE2( a , b ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(b)/100; } +#define ATK_RATER(a){ wd.damage = wd.damage*(a)/100;} +#define ATK_RATEL(a){ wd.damage2 = wd.damage2*(a)/100;} +//Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage +#define ATK_ADDRATE( a ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(a)/100; } +#define ATK_ADDRATE2( a , b ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(b)/100; } +//Adds an absolute value to damage. 100 = +100 damage +#define ATK_ADD( a ) { wd.damage+= a; if (flag.lh) wd.damage2+= a; } +#define ATK_ADD2( a , b ) { wd.damage+= a; if (flag.lh) wd.damage2+= b; } - s_ele = skill->get_ele(skill_id, skill_lv); - if (s_ele < 0 && s_ele != -3) //Attack that takes weapon's element for misc attacks? Make it neutral [Skotlex] - s_ele = ELE_NEUTRAL; - else if (s_ele == -3) //Use random element - s_ele = rnd()%ELE_MAX; + switch (skill_id) + { //Calc base damage according to skill + case PA_SACRIFICE: + wd.damage = sstatus->max_hp* 9/100; + wd.damage2 = 0; + break; + +#ifdef RENEWAL + case MO_EXTREMITYFIST: // [malufett] + wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|8, wd.flag); + // first value is still not confirm. + wd.damage = status_get_sp(src) + 10 * status_get_sp(src) * wd.damage / 100 + 8 * wd.damage; + flag.tdef = 1; + break; + case NJ_ISSEN: // [malufett] + { + short totaldef = status_get_total_def(target); + i = 0; + wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), wd.flag); + if( sc && sc->data[SC_NJ_BUNSINJYUTSU] && (i=sc->data[SC_NJ_BUNSINJYUTSU]->val2) > 0 ) + wd.div_ = ~( i++ + 2 ) + 1; + wd.damage *= sstatus->hp * skill_lv; + wd.damage = wd.damage / sstatus->max_hp + sstatus->hp + i * (wd.damage / sstatus->max_hp + sstatus->hp) / 5; + ATK_ADD(-totaldef); + if( is_boss(target) ) + ATK_RATE(50); + flag.idef = 1; + } +#else + + wd.damage = 40*sstatus->str +skill_lv*(sstatus->hp/10 + 35); + wd.damage2 = 0; +#endif + break; +#ifndef RENEWAL + case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: + if (sd) { + short index = sd->equip_index[EQI_HAND_R]; - //Skill Range Criteria - md.flag |= battle->range_type(src, target, skill_id, skill_lv); + if (index >= 0 && + sd->inventory_data[index] && + sd->inventory_data[index]->type == IT_WEAPON) + wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight + } else + wd.damage = sstatus->rhw.atk2*8/10; //Else use Atk2 - switch( skill_id ) - { + ATK_ADDRATE(50*skill_lv); //Skill modifier applies to weight only. + i = sstatus->str/10; + i*=i; + ATK_ADD(i); //Add str bonus. + switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection? + case SZ_SMALL: //Small: 125% + ATK_RATE(125); + break; + //case SZ_MEDIUM: //Medium: 100% + case SZ_BIG: //Large: 75% + ATK_RATE(75); + break; + } + break; +#endif + case CR_SHIELDBOOMERANG: + case PA_SHIELDCHAIN: + case LG_SHIELDPRESS: + case LG_EARTHDRIVE: + wd.damage = sstatus->batk; + if (sd) { + short index = sd->equip_index[EQI_HAND_L]; + + if (index >= 0 && + sd->inventory_data[index] && + sd->inventory_data[index]->type == IT_ARMOR) + ATK_ADD(sd->inventory_data[index]->weight/10); + } else + ATK_ADD(sstatus->rhw.atk2); //Else use Atk2 + break; + case HFLI_SBR44: //[orn] + if(src->type == BL_HOM) { + wd.damage = ((TBL_HOM*)src)->homunculus.intimacy ; + break; + } + default: + { + i = (flag.cri #ifdef RENEWAL - case HT_LANDMINE: - case MA_LANDMINE: - case HT_BLASTMINE: - case HT_CLAYMORETRAP: - md.damage = skill_lv * sstatus->dex * (3+status_get_lv(src)/100) * (1+sstatus->int_/35); - md.damage += md.damage * (rnd()%20-10) / 100; - md.damage += 40 * (sd?pc->checkskill(sd,RA_RESEARCHTRAP):0); - break; + || (sc && sc->data[SC_MAXIMIZEPOWER]) +#endif + ?1:0)| + (flag.arrow?2:0)| +#ifndef RENEWAL + (skill_id == HW_MAGICCRASHER?4:0)| + (skill_id == MO_EXTREMITYFIST?8:0)| +#endif + (!skill_id && sc && sc->data[SC_HLIF_CHANGE]?4:0)| + (sc && sc->data[SC_WEAPONPERFECT]?8:0); + if (flag.arrow && sd) + switch(sd->status.weapon) { + case W_BOW: + case W_REVOLVER: + case W_GATLING: + case W_SHOTGUN: + case W_GRENADE: + break; + default: + i |= 16; // for ex. shuriken must not be influenced by DEX + } +#ifdef RENEWAL + wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, i, wd.flag); + wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); + if (flag.lh){ + wd.damage2 = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_L, i, wd.flag); + wd.damage2 = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage2, wd.div_, 1, flag.weapon); + } #else - case HT_LANDMINE: - case MA_LANDMINE: - md.damage=skill_lv*(sstatus->dex+75)*(100+sstatus->int_)/100; - break; - case HT_BLASTMINE: - md.damage=skill_lv*(sstatus->dex/2+50)*(100+sstatus->int_)/100; - break; - case HT_CLAYMORETRAP: - md.damage=skill_lv*(sstatus->dex/2+75)*(100+sstatus->int_)/100; - break; + wd.damage = battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i); + if (flag.lh) + wd.damage2 = battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i); #endif - case HT_BLITZBEAT: - case SN_FALCONASSAULT: - //Blitz-beat Damage. - if(!sd || (temp = pc->checkskill(sd,HT_STEELCROW)) <= 0) - temp=0; - md.damage=(sstatus->dex/10+sstatus->int_/2+temp*3+40)*2; - if(mflag > 1) //Autocasted Blitz. - nk|=NK_SPLASHSPLIT; + if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets + if(wflag>0) + wd.damage/= wflag; + else + ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); + } - if (skill_id == SN_FALCONASSAULT) { - //Div fix of Blitzbeat - temp = skill->get_num(HT_BLITZBEAT, 5); - damage_div_fix(md.damage, temp); + //Add any bonuses that modify the base baseatk+watk (pre-skills) + if(sd) { + if (sd->bonus.atk_rate) + ATK_ADDRATE(sd->bonus.atk_rate); - //Falcon Assault Modifier - md.damage=md.damage*(150+70*skill_lv)/100; - } - break; - case TF_THROWSTONE: - md.damage=50; - break; - case BA_DISSONANCE: - md.damage=30+skill_lv*10; - if (sd) - md.damage+= 3*pc->checkskill(sd,BA_MUSICALLESSON); - break; - case NPC_SELFDESTRUCTION: - md.damage = sstatus->hp; - break; - case NPC_SMOKING: - md.damage=3; - break; - case NPC_DARKBREATH: - md.damage = 500 + (skill_lv-1)*1000 + rnd()%1000; - if(md.damage > 9999) md.damage = 9999; - break; - case PA_PRESSURE: - md.damage=500+300*skill_lv; - break; - case PA_GOSPEL: - md.damage = 1+rnd()%9999; - break; - case CR_ACIDDEMONSTRATION: // updated the formula based on a Japanese formula found to be exact [Reddozen] - if(tstatus->vit+sstatus->int_) //crash fix - md.damage = (int)(7*tstatus->vit*sstatus->int_*sstatus->int_ / (10*(tstatus->vit+sstatus->int_))); - else - md.damage = 0; - if (tsd) md.damage>>=1; - if (md.damage < 0 || md.damage > INT_MAX>>1) - //Overflow prevention, will anyone whine if I cap it to a few billion? - //Not capped to INT_MAX to give some room for further damage increase. - md.damage = INT_MAX>>1; - break; - case NJ_ZENYNAGE: - case KO_MUCHANAGE: - md.damage = skill->get_zeny(skill_id ,skill_lv); - if (!md.damage) md.damage = 2; - md.damage = rand()%md.damage + md.damage / (skill_id==NJ_ZENYNAGE?1:2) ; - if (is_boss(target)) - md.damage=md.damage / (skill_id==NJ_ZENYNAGE?3:2); - else if (tsd) // need confirmation for KO_MUCHANAGE - md.damage=md.damage/2; - break; - case GS_FLING: - md.damage = sd?sd->status.job_level:status_get_lv(src); - break; - case HVAN_EXPLOSION: //[orn] - md.damage = sstatus->max_hp * (50 + 50 * skill_lv) / 100; - break ; - case ASC_BREAKER: - md.damage = 500+rnd()%500 + 5*skill_lv * sstatus->int_; - nk|=NK_IGNORE_FLEE|NK_NO_ELEFIX; //These two are not properties of the weapon based part. - break; - case HW_GRAVITATION: - md.damage = 200+200*skill_lv; - md.dmotion = 0; //No flinch animation. - break; - case NPC_EVILLAND: - md.damage = skill->calc_heal(src,target,skill_id,skill_lv,false); - break; - case RK_DRAGONBREATH: - md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv; - RE_LVL_MDMOD(150); - if (sd) md.damage = md.damage * (100 + 5 * (pc->checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100; - md.flag |= BF_LONG|BF_WEAPON; - break; - /** - * Ranger - **/ - case RA_CLUSTERBOMB: - case RA_FIRINGTRAP: - case RA_ICEBOUNDTRAP: - md.damage = skill_lv * sstatus->dex + sstatus->int_ * 5 ; - RE_LVL_TMDMOD(); - if(sd) - { - int researchskill_lv = pc->checkskill(sd,RA_RESEARCHTRAP); - if(researchskill_lv) - md.damage = md.damage * 20 * researchskill_lv / (skill_id == RA_CLUSTERBOMB?50:100); - else - md.damage = 0; - }else - md.damage = md.damage * 200 / (skill_id == RA_CLUSTERBOMB?50:100); + if(flag.cri && sd->bonus.crit_atk_rate) + ATK_ADDRATE(sd->bonus.crit_atk_rate); + + if(sd->status.party_id && (temp=pc->checkskill(sd,TK_POWER)) > 0){ + if( (i = party_foreachsamemap(party->sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish] + ATK_ADDRATE(2*temp*i); + } + } + break; + } //End default case + } //End switch(skill_id) - break; - /** - * Mechanic - **/ - case NC_SELFDESTRUCTION: + //Skill damage modifiers that stack linearly + if( sd && sd->status.weapon == W_KATAR && (i=pc->checkskill(sd,ASC_KATAR)) > 0 ) + skillratio += skillratio * (13 + 2 * i) / 100; + if(sc && skill_id != PA_SACRIFICE) { - short totaldef = tstatus->def2 + (short)status_get_def(target); - md.damage = ( (sd?pc->checkskill(sd,NC_MAINFRAME):10) + 8 ) * ( skill_lv + 1 ) * ( status_get_sp(src) + sstatus->vit ); - RE_LVL_MDMOD(100); - md.damage += status_get_hp(src) - totaldef; + if(sc->data[SC_OVERTHRUST]) + skillratio += sc->data[SC_OVERTHRUST]->val3; + if(sc->data[SC_OVERTHRUSTMAX]) + skillratio += sc->data[SC_OVERTHRUSTMAX]->val2; + if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC__BLOODYLUST]) + skillratio += 100; +#ifdef RENEWAL + if( sc->data[SC_TRUESIGHT] ) + skillratio += 2*sc->data[SC_TRUESIGHT]->val1; + if( sc->data[SC_LKCONCENTRATION] ) + skillratio += sc->data[SC_LKCONCENTRATION]->val2; +#endif + if( sc->data[SC_UNLIMIT] && wd.flag&BF_LONG ) + ATK_ADD( 50 * sc->data[SC_UNLIMIT]->val1 ); } - break; - case GN_THORNS_TRAP: - md.damage = 100 + 200 * skill_lv + sstatus->int_; - break; - case GN_HELLS_PLANT_ATK: - //[{( Hell Plant Skill Level x Casters Base Level ) x 10 } + {( Casters INT x 7 ) / 2 } x { 18 + ( Casters Job Level / 4 )] x ( 5 / ( 10 - Summon Flora Skill Level )) - md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( sstatus->int_ * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - (sd?pc->checkskill(sd,AM_CANNIBALIZE):0)) ); - break; - case KO_HAPPOKUNAI: - { - struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); - short totaldef = tstatus->def2 + (short)status_get_def(target); - md.damage = wd.damage * 60 * (5 + skill_lv) / 100; - md.damage -= totaldef; + if( tsc && skill_id != PA_SACRIFICE ){ + if( tsc->data[SC_DARKCROW] && wd.flag&BF_SHORT ) + ATK_ADD( 30 * tsc->data[SC_DARKCROW]->val1 ); } - break; - case KO_MAKIBISHI: - md.damage = 20 * skill_lv; - break; - } - if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets - if(mflag>0) - md.damage/= mflag; + if( !skill_id ) + { + ATK_RATE(skillratio); + } else - ShowError("0 enemies targeted by %d:%s, divide per 0 avoided!\n", skill_id, skill->get_name(skill_id)); - } + { + switch(skill_id){ + #ifdef RENEWAL + case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: + {// Formula: Floor[Floor(Weapon Weight/2)*skill level + ATK ]*(100%+50%*s.lvl) * 5 multi-hits + short index = sd?sd->equip_index[EQI_HAND_R]:0; + int weight = 0; - damage_div_fix(md.damage, md.div_); + if (sd && index >= 0 && + sd->inventory_data[index] && + sd->inventory_data[index]->type == IT_WEAPON) + weight = sd->inventory_data[index]->weight/20; + ATK_ADD(weight * skill_lv); + } + case NJ_TATAMIGAESHI: + if( skill_id != LK_SPIRALPIERCE && skill_id != ML_SPIRALPIERCE ) + ATK_RATE(200); + #endif + default: + ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag)); + } - if (!(nk&NK_IGNORE_FLEE)) - { - struct status_change *sc = status_get_sc(target); - i = 0; //Temp for "hit or no hit" - if(sc && sc->opt1 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING) - i = 1; - else { - short - flee = tstatus->flee, + //Constant/misc additions from skills + switch (skill_id) { + case MO_EXTREMITYFIST: + ATK_ADD(250 + 150*skill_lv); + break; #ifdef RENEWAL - hitrate = 0; //Default hitrate + case HW_MAGICCRASHER: + ATK_ADD(battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage / 5); + break; +#endif + case TK_DOWNKICK: + case TK_STORMKICK: + case TK_TURNKICK: + case TK_COUNTER: + case TK_JUMPKICK: + //TK_RUN kick damage bonus. + if(sd && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST) + ATK_ADD(10*pc->checkskill(sd, TK_RUN)); + break; + case GS_MAGICALBULLET: +#ifndef RENEWAL + ATK_ADD( status_get_matk(src, 2) ); #else - hitrate = 80; //Default hitrate + ATK_ADD( battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage ); + flag.tdef = 1; +#endif + case NJ_SYURIKEN: + ATK_ADD(4*skill_lv); + break; + case HT_FREEZINGTRAP: + if(sd) + ATK_ADD( 40 * pc->checkskill(sd, RA_RESEARCHTRAP) ); + break; + case RA_WUGDASH ://(Caster Current Weight x 10 / 8) + if( sd && sd->weight ) + ATK_ADD( sd->weight / 8 ); + break; + case SR_TIGERCANNON: // (Tiger Cannon skill level x 240) + (Target Base Level x 40) + ATK_ADD( skill_lv * 240 + status_get_lv(target) * 40 ); + if( sc && sc->data[SC_COMBOATTACK] + && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) // (Tiger Cannon skill level x 500) + (Target Base Level x 40) + ATK_ADD( skill_lv * 500 + status_get_lv(target) * 40 ); + break; + case SR_FALLENEMPIRE:// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)] + ATK_ADD( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str); + if( tsd && tsd->weight ){ + ATK_ADD( (tsd->weight/10) * sstatus->dex / 120 ); + }else{ + ATK_ADD( status_get_lv(target) * 50 ); //mobs + } + break; + case KO_SETSUDAN: + if( tsc && tsc->data[SC_SOULLINK] ){ + ATK_ADDRATE(200*tsc->data[SC_SOULLINK]->val1); + status_change_end(target,SC_SOULLINK,INVALID_TIMER); + } + break; + case KO_MAKIBISHI: + wd.damage = 20 * skill_lv; + break; + } + } +#ifndef RENEWAL + //Div fix. + damage_div_fix(wd.damage, wd.div_); +#endif + //The following are applied on top of current damage and are stackable. + if ( sc ) { +#ifndef RENEWAL + if( sc->data[SC_TRUESIGHT] ) + ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1); +#endif + if( sc->data[SC_GLOOMYDAY_SK] && + ( skill_id == LK_SPIRALPIERCE || skill_id == KN_BRANDISHSPEAR || + skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN || + skill_id == LG_SHIELDPRESS || skill_id == RK_HUNDREDSPEAR || + skill_id == CR_SHIELDCHARGE ) ) + ATK_ADDRATE(sc->data[SC_GLOOMYDAY_SK]->val2); + if( sc->data[SC_EDP] ){ + switch(skill_id){ +#ifndef RENEWAL_EDP + case AS_SPLASHER: case AS_VENOMKNIFE: + case AS_GRIMTOOTH: + break; + case ASC_METEORASSAULT: break; + default: + ATK_ADDRATE(sc->data[SC_EDP]->val3); #endif + } + } + if(sc->data[SC_STYLE_CHANGE]){ + TBL_HOM *hd = BL_CAST(BL_HOM,src); + if (hd) ATK_ADD(hd->homunculus.spiritball * 3); + } + } - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) - { - if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; - else //asume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; + switch (skill_id) { + case AS_SONICBLOW: + if (sc && sc->data[SC_SOULLINK] && + sc->data[SC_SOULLINK]->val2 == SL_ASSASIN) + ATK_ADDRATE(map_flag_gvg(src->m)?25:100); //+25% dmg on woe/+100% dmg on nonwoe + + if(sd && pc->checkskill(sd,AS_SONICACCEL)>0) + ATK_ADDRATE(10); + break; + case CR_SHIELDBOOMERANG: + if(sc && sc->data[SC_SOULLINK] && + sc->data[SC_SOULLINK]->val2 == SL_CRUSADER) + ATK_ADDRATE(100); + break; + case NC_AXETORNADO: + if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) + ATK_ADDRATE(50); + break; + } + + if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) + ATK_RATE(i); + + if( sd ) { + if (skill_id && (i = pc->skillatk_bonus(sd, skill_id))) + ATK_ADDRATE(i); + if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && + (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) + ATK_ADDRATE(-i); + if( skill_id != PA_SACRIFICE && skill_id != MO_INVESTIGATE && skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS && skill_id != PA_SHIELDCHAIN && !flag.cri ) + { //Elemental/Racial adjustments + if( sd->right_weapon.def_ratio_atk_ele & (1<def_ele) || + sd->right_weapon.def_ratio_atk_race & (1<race) || + sd->right_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS)) + ) + flag.pdef = 1; + + if( sd->left_weapon.def_ratio_atk_ele & (1<def_ele) || + sd->left_weapon.def_ratio_atk_race & (1<race) || + sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS)) + ) + { //Pass effect onto right hand if configured so. [Skotlex] + if (battle_config.left_cardfix_to_right && flag.rh) + flag.pdef = 1; + else + flag.pdef2 = 1; + } + } + + if (skill_id != CR_GRANDCROSS && skill_id != NPC_GRANDDARKNESS) + { //Ignore Defense? + if (!flag.idef && ( + sd->right_weapon.ignore_def_ele & (1<def_ele) || + sd->right_weapon.ignore_def_race & (1<race) || + sd->right_weapon.ignore_def_race & (is_boss(target)?1<left_weapon.ignore_def_ele & (1<def_ele) || + sd->left_weapon.ignore_def_race & (1<race) || + sd->left_weapon.ignore_def_race & (is_boss(target)?1<calc_defense(BF_WEAPON, src, target, skill_id, skill_lv, wd.damage, (flag.idef?1:0)|(flag.pdef?2:0)|(flag.tdef?4:0), flag.pdef); + if( wd.damage2 ) + wd.damage2 = battle->calc_defense(BF_WEAPON, src, target, skill_id, skill_lv, wd.damage2, (flag.idef2?1:0)|(flag.pdef2?2:0)|(flag.tdef?4:0), flag.pdef2); + } + +#ifdef RENEWAL + //Div fix. + damage_div_fix(wd.damage, wd.div_); +#endif + //Post skill/vit reduction damage increases + if( sc ) + { //SC skill damages + if(sc->data[SC_AURABLADE] +#ifndef RENEWAL + && skill_id != LK_SPIRALPIERCE && skill_id != ML_SPIRALPIERCE +#endif + ){ + int lv = sc->data[SC_AURABLADE]->val1; +#ifdef RENEWAL + lv *= ((skill_id == LK_SPIRALPIERCE || skill_id == ML_SPIRALPIERCE)?wd.div_:1); // +100 per hit in lv 5 +#endif + ATK_ADD(20*lv); + } + } +#ifndef RENEWAL + //Refine bonus + if( sd && flag.weapon && skill_id != MO_INVESTIGATE && skill_id != MO_EXTREMITYFIST ) + { // Counts refine bonus multiple times + if( skill_id == MO_FINGEROFFENSIVE ) + { + ATK_ADD2(wd.div_*sstatus->rhw.atk2, wd.div_*sstatus->lhw.atk2); + } else { + ATK_ADD2(sstatus->rhw.atk2, sstatus->lhw.atk2); + } + } + //Set to min of 1 + if (flag.rh && wd.damage < 1) wd.damage = 1; + if (flag.lh && wd.damage2 < 1) wd.damage2 = 1; +#else + if (flag.rh && wd.damage < 1) wd.damage = 0; + if (flag.lh && wd.damage2 < 1) wd.damage2 = 0; +#endif + +#ifndef RENEWAL + wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); + if( flag.lh) + wd.damage2 = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage2, wd.div_, 1, flag.weapon); +#else + if( flag.cri ) + ATK_ADDRATE(40); +#endif + } //Here ends flag.hit section, the rest of the function applies to both hitting and missing attacks + else if(wd.div_ < 0) //Since the attack missed... + wd.div_ *= -1; +#ifndef RENEWAL + if(sd && (temp=pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0) + ATK_ADD(temp*2); +#endif + if(skill_id==TF_POISON) + ATK_ADD(15*skill_lv); - hitrate+= sstatus->hit - flee; -#ifdef RENEWAL - if( sd ) //in Renewal hit bonus from Vultures Eye is not anymore shown in status window - hitrate += pc->checkskill(sd,AC_VULTURE); +#ifndef RENEWAL + wd.damage = battle->calc_elefix(src, target, skill_id, skill_lv, wd.damage, nk, n_ele, s_ele, s_ele_, false, flag.arrow); + if( flag.lh ) + wd.damage2 = battle->calc_elefix(src, target, skill_id, skill_lv, wd.damage2, nk, n_ele, s_ele, s_ele_, true, flag.arrow); #endif - hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); - if(rnd()%100 < hitrate) - i = 1; - } - if (!i) { - md.damage = 0; - md.dmg_lv=ATK_FLEE; - } - } + if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) + return wd; //Enough, rest is not needed. #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { @@ -4497,75 +4764,251 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( md.damage > map[target->m].zone->capped_skills[i]->cap ) - md.damage = map[target->m].zone->capped_skills[i]->cap; - if( md.damage2 > map[target->m].zone->capped_skills[i]->cap ) - md.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( wd.damage > map[target->m].zone->capped_skills[i]->cap ) + wd.damage = map[target->m].zone->capped_skills[i]->cap; + if( wd.damage2 > map[target->m].zone->capped_skills[i]->cap ) + wd.damage2 = map[target->m].zone->capped_skills[i]->cap; break; } } } #endif - md.damage = battle->calc_cardfix(BF_MISC, src, target, nk, s_ele, 0, md.damage, 0, md.flag); - - if (sd && (i = pc->skillatk_bonus(sd, skill_id))) - md.damage += md.damage*i/100; +#ifndef RENEWAL + if (sd) { + if (skill_id != CR_SHIELDBOOMERANG) //Only Shield boomerang doesn't takes the Star Crumbs bonus. + ATK_ADD2(wd.div_*sd->right_weapon.star, wd.div_*sd->left_weapon.star); + if (skill_id==MO_FINGEROFFENSIVE) { //The finger offensive spheres on moment of attack do count. [Skotlex] + ATK_ADD(wd.div_*sd->spiritball_old*3); + } else { + ATK_ADD(wd.div_*sd->spiritball*3); + } + //Card Fix, sd side + wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, 2, wd.flag); + if( flag.lh ) + wd.damage2 = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage2, 3, wd.flag); +#ifdef RENEWAL + if( flag.cri ) + ATK_ADDRATE(sd->bonus.crit_atk_rate>=100?sd->bonus.crit_atk_rate-60:40); +#endif + if( skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN ) + { //Refine bonus applies after cards and elements. + short index= sd->equip_index[EQI_HAND_L]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) + ATK_ADD(10*sd->status.inventory[index].refine); + } + } + //Card Fix, tsd side + if(tsd){ //if player on player then it was already measured above + wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, 2, wd.flag); + if( flag.lh ) + wd.damage2 = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage2, 3, wd.flag); + } +#endif + if( flag.infdef ) { //Plants receive 1 damage when hit + short class_ = status_get_class(target); + if( flag.hit || wd.damage > 0 ) + wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage + if( flag.lh && (flag.hit || wd.damage2 > 0) ) + wd.damage2 = wd.div_; + if( flag.hit && class_ == MOBID_EMPERIUM ) { + if(wd.damage2 > 0) { + wd.damage2 = battle->attr_fix(src,target,wd.damage2,s_ele_,tstatus->def_ele, tstatus->ele_lv); + wd.damage2 = battle->calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); + } + else if(wd.damage > 0) { + wd.damage = battle->attr_fix(src,target,wd.damage,s_ele_,tstatus->def_ele, tstatus->ele_lv); + wd.damage = battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); + } + return wd; + } + if( !(battle_config.skill_min_damage&1) ) + //Do not return if you are supposed to deal greater damage to plants than 1. [Skotlex] + return wd; + } - if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) - md.damage = md.damage * i / 100; + if (sd) { + if (!flag.rh && flag.lh) { //Move lh damage to the rh + wd.damage = wd.damage2; + wd.damage2 = 0; + flag.rh=1; + flag.lh=0; + } else if(flag.rh && flag.lh) { //Dual-wield + if (wd.damage) { + temp = pc->checkskill(sd,AS_RIGHT) * 10; + if( (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO ) + temp = pc->checkskill(sd,KO_RIGHT) * 10 + 20; + ATK_RATER( 50 + temp ); + } + if (wd.damage2) { + temp = pc->checkskill(sd,AS_LEFT) * 10; + if( (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO ) + temp = pc->checkskill(sd,KO_LEFT) * 10 + 20; + ATK_RATEL( 30 + temp ); + } +#ifdef RENEWAL + if(wd.damage < 0) wd.damage = 0; + if(wd.damage2 < 0) wd.damage2 = 0; +#else + if(wd.damage < 1) wd.damage = 1; + if(wd.damage2 < 1) wd.damage2 = 1; +#endif + } else if(sd->status.weapon == W_KATAR && !skill_id) { //Katars (offhand damage only applies to normal attacks, tested on Aegis 10.2) + temp = pc->checkskill(sd,TF_DOUBLE); + wd.damage2 = wd.damage * (1 + (temp * 2))/100; - if(md.damage < 0) - md.damage = 0; - else if(md.damage && tstatus->mode&MD_PLANT){ - switch(skill_id){ - case HT_LANDMINE: - case MA_LANDMINE: - case HT_BLASTMINE: - case HT_CLAYMORETRAP: - case RA_CLUSTERBOMB: + if(wd.damage && !wd.damage2) wd.damage2 = #ifdef RENEWAL - break; + 0; +#else + 1; #endif - default: - md.damage = 1; + flag.lh = 1; } - }else if( target->type == BL_SKILL ){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - md.damage = 1; } - if(!(nk&NK_NO_ELEFIX)) - md.damage=battle->attr_fix(src, target, md.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); + if(!flag.rh && wd.damage) + wd.damage=0; - md.damage=battle->calc_damage(src,target,&md,md.damage,skill_id,skill_lv); - if( map_flag_gvg2(target->m) ) - md.damage=battle->calc_gvg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); - else if( map[target->m].flag.battleground ) - md.damage=battle->calc_bg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); + if(!flag.lh && wd.damage2) + wd.damage2=0; - switch( skill_id ) { - case RA_FIRINGTRAP: - case RA_ICEBOUNDTRAP: - if( md.damage == 1 ) break; - case RA_CLUSTERBOMB: - { - struct Damage wd; - wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); - md.damage += wd.damage; + if( sc ) { + //SG_FUSION hp penalty [Komurka] + if (sc->data[SC_FUSION]) { + int hp= sstatus->max_hp; + if (sd && tsd) { + hp = 8*hp/100; + if ((sstatus->hp * 100) <= (sstatus->max_hp * 20)) + hp = sstatus->hp; + } else + hp = 2*hp/100; //2% hp loss per hit + status_zap(src, hp, 0); + } + if( !skill_id ) { + if( sc->data[SC_ENCHANTBLADE] ) { // it also works with bear hands..intended in official + //[( ( Skill Lv x 20 ) + 100 ) x ( casterBaseLevel / 150 )] + casterInt + ATK_ADD(( sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100 ) * status_get_lv(src) / 150 + status_get_int(src)); } + } + status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); + } + + switch(skill_id){ + case LG_RAYOFGENESIS: + { + struct Damage md = battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag); + wd.damage += md.damage; break; - case NJ_ZENYNAGE: - if( sd ) { - if ( md.damage > sd->status.zeny ) - md.damage = sd->status.zeny; - pc->payzeny(sd, md.damage,LOG_TYPE_STEAL,NULL); } - break; + case SR_GATEOFHELL: + ATK_ADD (sstatus->max_hp - status_get_hp(src)); + if(sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE){ + ATK_ADD ( (sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status_get_lv(src) ); + }else{ + ATK_ADD ( (sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status_get_lv(src) ); + } + break; } - return md; + if( wd.damage + wd.damage2 ) + { //There is a total damage value + int damage = wd.damage + wd.damage2, rdamage = 0, rdelay = 0; + + if( src != target && + (!skill_id || skill_id || + ( src->type == BL_SKILL && ( skill_id == SG_SUN_WARM || skill_id == SG_MOON_WARM || skill_id == SG_STAR_WARM ) )) ){ + + rdamage = battle->calc_return_damage(target, src, &damage, wd.flag, 0, &rdelay); + + if( tsc && tsc->count ) { + if( tsc && tsc->data[SC_DEATHBOUND] ){ + wd.damage = damage; + wd.damage2 = 0; + status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); + } + } + if( rdamage > 0 ) { + if( tsc && tsc->data[SC_LG_REFLECTDAMAGE] ) { + if( src != target ) {// Don't reflect your own damage (Grand Cross) + bool change = false; + if( sd && !sd->state.autocast ) + change = true; + if( change ) + sd->state.autocast = 1; + iMap->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,iTimer->gettick(),target,wd.amotion,sstatus->dmotion,rdamage,tstatus->race); + if( change ) + sd->state.autocast = 0; + } + } else { + //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] + if( tsd && src != target ) + battle->drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); + battle->delay_damage(iTimer->gettick(), wd.amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + skill->additional_effect(target, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,iTimer->gettick()); + } + } + } + if(!wd.damage2) + { + wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); + if( map_flag_gvg2(target->m) ) + wd.damage=battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage=battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); + } + else if(!wd.damage) + { + wd.damage2 = battle->calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv); + if( map_flag_gvg2(target->m) ) + wd.damage2 = battle->calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage = battle->calc_bg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); + } + else + { +#ifdef RENEWAL + wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); + wd.damage2 = battle->calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv); +#else + int d1 = wd.damage + wd.damage2,d2 = wd.damage2; + wd.damage = battle->calc_damage(src,target,&wd,d1,skill_id,skill_lv); +#endif + if( map_flag_gvg2(target->m) ) + wd.damage = battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); + else if( map[target->m].flag.battleground ) + wd.damage = battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); +#ifndef RENEWAL + wd.damage2 = d2*100/d1 * wd.damage/100; + if(wd.damage > 1 && wd.damage2 < 1) wd.damage2 = 1; + wd.damage-=wd.damage2; +#endif + } + } + //Reject Sword bugreport:4493 by Daegaladh + if(wd.damage && tsc && tsc->data[SC_SWORDREJECT] && + (src->type!=BL_PC || ( + ((TBL_PC *)src)->weapontype1 == W_DAGGER || + ((TBL_PC *)src)->weapontype1 == W_1HSWORD || + ((TBL_PC *)src)->status.weapon == W_2HSWORD + )) && + rnd()%100 < tsc->data[SC_SWORDREJECT]->val2 + ) { + ATK_RATER(50) + status_fix_damage(target,src,wd.damage,clif->damage(target,src,iTimer->gettick(),0,0,wd.damage,0,0,0)); + clif->skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_SWORDREJECT]->val1,1); + if( --(tsc->data[SC_SWORDREJECT]->val3) <= 0 ) + status_change_end(target, SC_SWORDREJECT, INVALID_TIMER); + } +#ifndef RENEWAL + if(skill_id == ASC_BREAKER) { //Breaker's int-based damage (a misc attack?) + struct Damage md = battle->calc_misc_attack(src, target, skill_id, skill_lv, wflag); + wd.damage += md.damage; + } +#endif + + return wd; } + /*========================================== * Battle main entry, from skill->attack *------------------------------------------*/ @@ -4614,19 +5057,19 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl } //Calculates BF_WEAPON returned damage. -int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int *dmg, int flag, uint16 skill_id){ +int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int *dmg, int flag, uint16 skill_id, int *delay){ + int rdamage = 0, damage = *dmg, rdelay = *delay, trdamage = 0; struct map_session_data* sd; - int rdamage = 0, damage = *dmg; struct status_change* sc; + int max_reflect_damage; sd = BL_CAST(BL_PC, bl); sc = status_get_sc(bl); + max_reflect_damage = max(status_get_max_hp(bl), status_get_max_hp(bl) * status_get_lv(bl) / 100); - if( sc && sc->data[SC_REFLECTDAMAGE] ) { - int max_damage = status_get_max_hp(bl) * status_get_lv(bl) / 100; - rdamage = (*dmg) * sc->data[SC_REFLECTDAMAGE]->val2 / 100; - if( rdamage > max_damage ) rdamage = max_damage; - }else if( sc && sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ +#define NORMALIZE_RDAMAGE(d){ trdamage += rdamage = max(1, min(max_reflect_damage, d)); } + + if( sc && sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ //ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}] int ratio = (status_get_hp(src) / 100) * sc->data[SC_CRESCENTELBOW]->val1 * status_get_lv(bl) / 125; if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK @@ -4638,42 +5081,56 @@ int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int status_damage(src, bl, status_damage(bl, src, rdamage, 0, 0, 1)/10, 0, 0, 1); status_change_end(bl, SC_CRESCENTELBOW, INVALID_TIMER); return 0; // Just put here to minimize redundancy - }else if (flag & BF_SHORT) {//Bounces back part of the damage. - if ( sd && sd->bonus.short_weapon_damage_return ) { - rdamage += damage * sd->bonus.short_weapon_damage_return / 100; - if(rdamage < 1) rdamage = 1; + } + if( flag & BF_SHORT) {//Bounces back part of the damage. + if ( sd && sd->bonus.short_weapon_damage_return ){ + NORMALIZE_RDAMAGE(damage * sd->bonus.short_weapon_damage_return / 100); + rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); } if( sc && sc->count ) { - if ( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) { - rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100; - if (rdamage < 1) rdamage = 1; + if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ){ + NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100); + rdelay = clif->skill_damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, CR_REFLECTSHIELD, 1, 4); + } + if( sc->data[SC_LG_REFLECTDAMAGE] && rand()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { + if( skill_id != HT_LANDMINE && skill_id != HT_CLAYMORETRAP + && skill_id != RA_CLUSTERBOMB && (skill_id <= RA_VERDURETRAP || skill_id > RA_ICEBOUNDTRAP && skill_id != MA_LANDMINE) ){ + NORMALIZE_RDAMAGE((*dmg) * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); + rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + } } - if(sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && !(src->type == BL_MOB && is_boss(src)) ) { + if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && !is_boss(src) ) { uint8 dir = iMap->calc_dir(bl,src->x,src->y), - t_dir = unit_getdir(bl); - - if( distance_bl(src,bl) <= 0 || !iMap->check_dir(dir,t_dir) ) { - int rd1 = 0; - rd1 = min(damage,status_get_max_hp(bl)) * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. - *dmg = rd1 * 30 / 100; // Received damage = 30% of amplifly damage. - clif->skill_damage(src,bl,iTimer->gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1,6); - status_change_end(bl,SC_DEATHBOUND,INVALID_TIMER); - rdamage += rd1; - if (rdamage < 1) rdamage = 1; + t_dir = unit_getdir(bl); + + if( !iMap->check_dir(dir,t_dir) ) { + int rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. + trdamage += rdamage = rd1 - (*dmg = rd1 * 30 / 100); // not normalized as intended. + clif->skill_damage(src, bl, iTimer->gettick(), status_get_amotion(src), 0, -3000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, 6); + skill->blown(bl, src, skill->get_blewcount(RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1), unit_getdir(src), 0); + if( skill_id ) + status_change_end(bl, SC_DEATHBOUND, INVALID_TIMER); + rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); } } } + if( sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 2 && !is_boss(src) ){ + NORMALIZE_RDAMAGE(damage * sc->data[SC_SHIELDSPELL_DEF]->val2 / 100); + rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + } } else { - if (sd && sd->bonus.long_weapon_damage_return) { - rdamage += damage * sd->bonus.long_weapon_damage_return / 100; - if (rdamage < 1) rdamage = 1; + if (sd && sd->bonus.long_weapon_damage_return){ + NORMALIZE_RDAMAGE(damage * sd->bonus.long_weapon_damage_return / 100); + rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); } } + + if( !(sc && sc->data[SC_DEATHBOUND]) ){ + if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability + return 0; + } - if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability - rdamage = 0; - - return rdamage; + return max(0, trdamage); } void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss) @@ -4898,17 +5355,17 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t return ATK_DEF; return ATK_MISS; } - if( sc->data[SC_GT_ENERGYGAIN] ) { - if( sd && rnd()%100 < 10 + 5 * sc->data[SC_GT_ENERGYGAIN]->val1) + if( sc->data[SC_GENTLETOUCH_ENERGYGAIN] ) { + if( sd && rnd()%100 < 10 + 5 * sc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1) pc->addspiritball(sd, - skill->get_time(MO_CALLSPIRITS, sc->data[SC_GT_ENERGYGAIN]->val1), - sc->data[SC_GT_ENERGYGAIN]->val1); + skill->get_time(MO_CALLSPIRITS, sc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1), + sc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1); } - if( tsc && tsc->data[SC_GT_ENERGYGAIN] ) { - if( tsd && rnd()%100 < 10 + 5 * tsc->data[SC_GT_ENERGYGAIN]->val1) + if( tsc && tsc->data[SC_GENTLETOUCH_ENERGYGAIN] ) { + if( tsd && rnd()%100 < 10 + 5 * tsc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1) pc->addspiritball(tsd, - skill->get_time(MO_CALLSPIRITS, tsc->data[SC_GT_ENERGYGAIN]->val1), - tsc->data[SC_GT_ENERGYGAIN]->val1); + skill->get_time(MO_CALLSPIRITS, tsc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1), + tsc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1); } if( sc && sc->data[SC_CRUSHSTRIKE] ){ uint16 skill_lv = sc->data[SC_CRUSHSTRIKE]->val1; @@ -4958,19 +5415,6 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t skill_id = AB_DUPLELIGHT_MAGIC; skill->attack(skill->get_type(skill_id), src, src, target, skill_id, sc->data[SC_DUPLELIGHT]->val1, tick, SD_LEVEL); } - - rdamage = battle->calc_return_damage(target,src, &damage, wd.flag, 0); - if( rdamage > 0 ) { - if( tsc && tsc->data[SC_REFLECTDAMAGE] ) { - if( src != target ) {// Don't reflect your own damage (Grand Cross) - iMap->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd.amotion,wd.dmotion,rdamage,tstatus->race); - } - } else { - rdelay = clif->damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0); - //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] - skill->additional_effect(target,src,CR_REFLECTSHIELD,1,BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); - } - } } wd.dmotion = clif->damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); @@ -5023,7 +5467,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t uint16 skill_id = sc->data[SC_AUTOSPELL]->val2; uint16 skill_lv = sc->data[SC_AUTOSPELL]->val3; int i = rnd()%100; - if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_SAGE) + if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_SAGE) i = 0; //Max chance, no skill_lv reduction. [Skotlex] if (i >= 50) skill_lv -= 2; else if (i >= 15) skill_lv--; @@ -5099,7 +5543,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t sd->state.autocast = 0; sd->ud.canact_tick = tick + skill->delay_fix(src, r_skill, r_lv); - clif->status_change(src, SI_ACTIONDELAY, 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1); + clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1); } } @@ -5110,11 +5554,6 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t battle->drain(sd, target, wd.damage, wd.damage2, tstatus->race, is_boss(target)); } } - if (rdamage > 0 && !(tsc && tsc->data[SC_REFLECTDAMAGE])) { //By sending attack type "none" skill->additional_effect won't be invoked. [Skotlex] - if(tsd && src != target) - battle->drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); - battle->delay_damage(tick, wd.amotion, target, src, 0, CR_REFLECTSHIELD, 0, rdamage, ATK_DEF, rdelay, true); - } if (tsc) { if (tsc->data[SC_POISONREACT] && @@ -5243,7 +5682,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target)) return -1; //Cannot be targeted yet. if( sc && sc->count ) { - if( sc->data[SC_VOICEOFSIREN] && sc->data[SC_VOICEOFSIREN]->val2 == target->id ) + if( sc->data[SC_SIREN] && sc->data[SC_SIREN]->val2 == target->id ) return -1; } } @@ -5265,6 +5704,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if( skill->get_inf2(su->group->skill_id)&INF2_TRAP ) { //Only a few skills can target traps... switch( battle->get_current_skill(src) ) { case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps + case RK_DRAGONBREATH_WATER: if( !map[m].flag.pvp && !map[m].flag.gvg ) break; case 0://you can hit them without skills @@ -5838,7 +6278,6 @@ static const struct _battle_data { { "ignore_items_gender", &battle_config.ignore_items_gender, 1, 0, 1, }, { "copyskill_restrict", &battle_config.copyskill_restrict, 2, 0, 2, }, { "berserk_cancels_buffs", &battle_config.berserk_cancels_buffs, 0, 0, 1, }, - { "debuff_on_logout", &battle_config.debuff_on_logout, 1|2, 0, 1|2, }, { "monster_ai", &battle_config.mob_ai, 0x000, 0x000, 0x77F, }, { "hom_setting", &battle_config.hom_setting, 0xFFFF, 0x0000, 0xFFFF, }, { "dynamic_mobs", &battle_config.dynamic_mobs, 1, 0, 1, }, @@ -6239,9 +6678,15 @@ void battle_defaults(void) { battle->drain = battle_drain; battle->calc_return_damage = battle_calc_return_damage; battle->calc_weapon_attack = battle_calc_weapon_attack; + battle->calc_weapon_damage = battle_calc_weapon_damage; + battle->calc_defense = battle_calc_defense; battle->attr_ratio = battle_attr_ratio; battle->attr_fix = battle_attr_fix; battle->calc_cardfix = battle_calc_cardfix; + battle->calc_elefix = battle_calc_elefix; + battle->calc_masteryfix = battle_calc_masteryfix; + battle->calc_skillratio = battle_calc_skillratio; + battle->calc_sizefix = battle_calc_sizefix; battle->get_master = battle_get_master; battle->get_targeted = battle_gettargeted; battle->get_enemy = battle_getenemy; diff --git a/src/map/battle.h b/src/map/battle.h index f2d870032..bbe723f36 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -348,7 +348,6 @@ struct Battle_Config { int copyskill_restrict; // [Aru] int berserk_cancels_buffs; // [Aru] - int debuff_on_logout; // Removes a few "official" negative Scs on logout. [Skotlex] int mob_ai; //Configures various mob_ai settings to make them smarter or dumber(official). [Skotlex] int hom_setting; //Configures various homunc settings which make them behave unlike normal characters.. [Skotlex] int dynamic_mobs; // Dynamic Mobs [Wizputer] - battle.conf flag implemented by [random] @@ -489,13 +488,25 @@ struct battle_interface { /* drain damage */ void (*drain) (struct map_session_data *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss); /* damage return/reflect */ - int (*calc_return_damage) (struct block_list *bl, struct block_list *src, int *, int flag, uint16 skill_id); + int (*calc_return_damage) (struct block_list *bl, struct block_list *src, int *, int flag, uint16 skill_id, int*); /* attribute rate */ int (*attr_ratio) (int atk_elem, int def_type, int def_lv); /* applies attribute modifiers */ int (*attr_fix) (struct block_list *src, struct block_list *target, int damage, int atk_elem, int def_type, int def_lv); /* applies card modifiers */ int (*calc_cardfix) (int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int damage, int left, int flag); + /* applies element modifiers */ + int (*calc_elefix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag); + /* applies mastery modifiers */ + int (*calc_masteryfix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int div, bool left, bool weapon); + /* applies skill modifiers */ + int (*calc_skillratio) (int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag); + /* applies size modifiers */ + int (*calc_sizefix) (struct map_session_data *sd, int damage, int type, int size, bool ignore); + /* get weapon damage */ + int (*calc_weapon_damage) (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2); + /* applies defense reductions */ + int (*calc_defense) (int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int flag, int pdef); /* get master (who does this unit respond to?) */ struct block_list *(*get_master) (struct block_list *src); /* returns a random unit who is targeting this unit */ @@ -521,7 +532,12 @@ struct battle_interface { int (*blewcount_bonus) (struct map_session_data *sd, uint16 skill_id); /* skill range criteria */ int (*range_type) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv); - int (*calc_base_damage) (struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag); + int (*calc_base_damage) +#ifdef RENEWAL + (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2); +#else + (struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag); +#endif struct Damage (*calc_misc_attack) (struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag); struct Damage (*calc_magic_attack) (struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag); int (*adjust_skill_damage) (int m, unsigned short skill_id); diff --git a/src/map/clif.c b/src/map/clif.c index 202469605..2f8ecd6a4 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1259,12 +1259,12 @@ void clif_spiritball_single(int fd, struct map_session_data *sd) { /*========================================== * Kagerou/Oboro amulet spirit *------------------------------------------*/ -void clif_talisman_single(int fd, struct map_session_data *sd, short type) { +void clif_charm_single(int fd, struct map_session_data *sd, short type) { WFIFOHEAD(fd, packet_len(0x08cf)); WFIFOW(fd,0)=0x08cf; WFIFOL(fd,2)=sd->bl.id; WFIFOW(fd,6)=type; - WFIFOW(fd,8)=sd->talisman[type]; + WFIFOW(fd,8)=sd->charm[type]; WFIFOSET(fd, packet_len(0x08cf)); } @@ -1358,8 +1358,8 @@ int clif_spawn(struct block_list *bl) clif->sc_load(&sd->bl, sd->bl.id,AREA,StatusIconChangeTable[sd->sc_display[i]->type],sd->sc_display[i]->val1,sd->sc_display[i]->val2,sd->sc_display[i]->val3); } for(i = 1; i < 5; i++){ - if( sd->talisman[i] > 0 ) - clif->talisman(sd, i); + if( sd->charm[i] > 0 ) + clif->charm(sd, i); } if (sd->status.robe) clif->refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA); @@ -3461,7 +3461,9 @@ void clif_arrowequip(struct map_session_data *sd,int val) nullpo_retv(sd); pc_stop_attack(sd); // [Valaris] - +#if PACKETVER >= 20121128 + clif->status_change(&sd->bl, SI_CLIENT_ONLY_EQUIP_ARROW, 1, INVALID_TIMER, 0, 0, 0); +#endif fd=sd->fd; WFIFOHEAD(fd, packet_len(0x013c)); WFIFOW(fd,0)=0x013c; @@ -4309,8 +4311,8 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds if(dstsd->spiritball > 0) clif->spiritball_single(sd->fd, dstsd); for(i = 1; i < 5; i++){ - if( dstsd->talisman[i] > 0 ) - clif->talisman_single(sd->fd, dstsd, i); + if( dstsd->charm[i] > 0 ) + clif->charm_single(sd->fd, dstsd, i); } for( i = 0; i < dstsd->sc_display_count; i++ ) { clif->sc_load(&sd->bl,dstsd->bl.id,SELF,StatusIconChangeTable[dstsd->sc_display[i]->type],dstsd->sc_display[i]->val1,dstsd->sc_display[i]->val2,dstsd->sc_display[i]->val3); @@ -4471,9 +4473,9 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic type = clif_calc_delay(type,div,damage+damage2,ddelay); sc = status_get_sc(dst); if(sc && sc->count) { - if(sc->data[SC_HALLUCINATION]) { - if(damage) damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rnd()%100; - if(damage2) damage2 = damage2*(sc->data[SC_HALLUCINATION]->val2) + rnd()%100; + if(sc->data[SC_ILLUSION]) { + if(damage) damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + if(damage2) damage2 = damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } } @@ -4643,12 +4645,21 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi /// Notifies the client of a skill unit. /// 011f .L .L .W .W .B .B (ZC_SKILL_ENTRY) /// 01c9 .L .L .W .W .B .B .B .80B (ZC_SKILL_ENTRY2) +/// 08c7 .W L .L .W .W .B .W .B (ZC_SKILL_ENTRY3) +/// 099f .W L .L .W .W .L .W .B (ZC_SKILL_ENTRY4) void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit) { - int fd = sd->fd; + int fd = sd->fd, header = 0x11f, pos=0; if( unit->group->state.guildaura ) return; +#if PACKETVER >= 20130320 + if(unit->group->unit_id > UCHAR_MAX){ + header = 0x99f; + pos = 2; + } +#endif + #if PACKETVER >= 3 if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] WFIFOHEAD(fd,packet_len(0x1c9)); @@ -4665,20 +4676,26 @@ void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit * return; } #endif - WFIFOHEAD(fd,packet_len(0x11f)); - WFIFOW(fd, 0)=0x11f; - WFIFOL(fd, 2)=unit->bl.id; - WFIFOL(fd, 6)=unit->group->src_id; - WFIFOW(fd,10)=unit->bl.x; - WFIFOW(fd,12)=unit->bl.y; + WFIFOHEAD(fd,packet_len(header)); + WFIFOW(fd, 0)=header; + if(pos > 0) + WFIFOL(fd, pos)=packet_len(header); + WFIFOL(fd, 2 + pos)=unit->bl.id; + WFIFOL(fd, 6 + pos)=unit->group->src_id; + WFIFOW(fd,10 + pos)=unit->bl.x; + WFIFOW(fd,12 + pos)=unit->bl.y; if (battle_config.traps_setting&1 && skill->get_inf2(unit->group->skill_id)&INF2_TRAP) WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. else if (skill->get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else + else if(pos > 0){ + WFIFOL(fd,16)=unit->group->unit_id; + WFIFOW(fd,20)=unit->range; + pos += 5; + }else WFIFOB(fd,14)=unit->group->unit_id; - WFIFOB(fd,15)=1; // ignored by client (always gets set to 1) - WFIFOSET(fd,packet_len(0x11f)); + WFIFOB(fd,15 + pos)=1; // ignored by client (always gets set to 1) + WFIFOSET(fd,packet_len(header)); if(unit->group->skill_id == WZ_ICEWALL) clif->changemapcell(fd,unit->bl.m,unit->bl.x,unit->bl.y,5,SELF); @@ -5134,8 +5151,8 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int type = clif_calc_delay(type,div,damage,ddelay); sc = status_get_sc(dst); if(sc && sc->count) { - if(sc->data[SC_HALLUCINATION] && damage) - damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rnd()%100; + if(sc->data[SC_ILLUSION] && damage) + damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } #if PACKETVER < 3 @@ -5223,8 +5240,8 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in sc = status_get_sc(dst); if(sc && sc->count) { - if(sc->data[SC_HALLUCINATION] && damage) - damage = damage*(sc->data[SC_HALLUCINATION]->val2) + rnd()%100; + if(sc->data[SC_ILLUSION] && damage) + damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } WBUFW(buf,0)=0x115; @@ -5330,12 +5347,20 @@ void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,i void clif_skill_setunit(struct skill_unit *unit) { unsigned char buf[128]; + int header = 0x11f, pos = 0; nullpo_retv(unit); if( unit->group->state.guildaura ) return; +#if PACKETVER >= 20130320 + if(unit->group->unit_id > UCHAR_MAX){ + header = 0x99f; + pos = 2; + } +#endif + #if PACKETVER >= 3 if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] WBUFW(buf, 0)=0x1c9; @@ -5351,19 +5376,25 @@ void clif_skill_setunit(struct skill_unit *unit) return; } #endif - WBUFW(buf, 0)=0x11f; - WBUFL(buf, 2)=unit->bl.id; - WBUFL(buf, 6)=unit->group->src_id; - WBUFW(buf,10)=unit->bl.x; - WBUFW(buf,12)=unit->bl.y; + WBUFW(buf, 0)=header; + if(pos > 0) + WBUFW(buf, pos)=packet_len(header); + WBUFL(buf, 2 + pos)=unit->bl.id; + WBUFL(buf, 6 + pos)=unit->group->src_id; + WBUFW(buf,10 + pos)=unit->bl.x; + WBUFW(buf,12 + pos)=unit->bl.y; if (unit->group->state.song_dance&0x1 && unit->val2&UF_ENSEMBLE) WBUFB(buf,14)=unit->val2&UF_SONG?UNT_DISSONANCE:UNT_UGLYDANCE; else if (skill->get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) WBUFB(buf, 14) = UNT_DUMMYSKILL; // Only display the unit at center. - else + else if(pos > 0){ + WBUFL(buf,16)=unit->group->unit_id; + WBUFW(buf,20)=unit->range; + pos += 5; + }else WBUFB(buf,14)=unit->group->unit_id; - WBUFB(buf,15)=1; // ignored by client (always gets set to 1) - clif->send(buf,packet_len(0x11f),&unit->bl,AREA); + WBUFB(buf,15 + pos)=1; // ignored by client (always gets set to 1) + clif->send(buf,packet_len(header),&unit->bl,AREA); } @@ -5388,9 +5419,10 @@ void clif_skill_warppoint(struct map_session_data* sd, uint16 skill_id, uint16 s WFIFOSET(fd,packet_len(0x11c)); sd->menuskill_id = skill_id; - if (skill_id == AL_WARP) + if (skill_id == AL_WARP){ sd->menuskill_val = (sd->ud.skillx<<16)|sd->ud.skilly; //Store warp position here. - else + sd->state.workinprogress = 3; + }else sd->menuskill_val = skill_lv; } @@ -5423,10 +5455,11 @@ void clif_skill_memomessage(struct map_session_data* sd, int type) /// type: /// 0 = "Unable to Teleport in this area" in color 0xFFFF00 (cyan) /// 1 = "Saved point cannot be memorized." in color 0x0000FF (red) +/// 2 = "This skill cannot be used within this area." in color 0xFFFF00 (cyan) /// /// @param sd Who receives the message /// @param type What message -void clif_skill_teleportmessage(struct map_session_data *sd, int type) +void clif_skill_mapinfomessage(struct map_session_data *sd, int type) { int fd; @@ -5621,6 +5654,9 @@ void clif_status_change(struct block_list *bl,int type,int flag,int tick,int val if (!(status_type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client return; + if ( tick < 0 ) + tick = 9999; + sd = BL_CAST(BL_PC, bl); p.PacketType = status_changeType; @@ -6061,6 +6097,7 @@ void clif_item_identify_list(struct map_session_data *sd) WFIFOSET(fd,WFIFOW(fd,2)); sd->menuskill_id = MC_IDENTIFY; sd->menuskill_val = c; + sd->state.workinprogress = 3; } } @@ -6163,25 +6200,20 @@ void clif_item_refine_list(struct map_session_data *sd) int fd; uint16 skill_lv; int wlv; - int refine_item[5]; nullpo_retv(sd); skill_lv = pc->checkskill(sd,WS_WEAPONREFINE); fd=sd->fd; - - refine_item[0] = -1; - refine_item[1] = pc->search_inventory(sd,1010); - refine_item[2] = pc->search_inventory(sd,1011); - refine_item[3] = refine_item[4] = pc->search_inventory(sd,984); - + WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4); WFIFOW(fd,0)=0x221; for(i=c=0;istatus.inventory[i].nameid > 0 && sd->status.inventory[i].refine < skill_lv && - sd->status.inventory[i].identify && (wlv=itemdb_wlv(sd->status.inventory[i].nameid)) >=1 && - refine_item[wlv]!=-1 && !(sd->status.inventory[i].equip&EQP_ARMS)){ + if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify + && (wlv=itemdb_wlv(sd->status.inventory[i].nameid)) >=1 + && !sd->inventory_data[i]->flag.no_refine + && !(sd->status.inventory[i].equip&EQP_ARMS)){ WFIFOW(fd,c*13+ 4)=i+2; WFIFOW(fd,c*13+ 6)=sd->status.inventory[i].nameid; WFIFOB(fd,c*13+ 8)=sd->status.inventory[i].refine; @@ -8498,8 +8530,8 @@ void clif_refresh(struct map_session_data *sd) if (sd->spiritball) clif->spiritball_single(sd->fd, sd); for(i = 1; i < 5; i++){ - if( sd->talisman[i] > 0 ) - clif->talisman_single(sd->fd, sd, i); + if( sd->charm[i] > 0 ) + clif->charm_single(sd->fd, sd, i); } if (sd->vd.cloth_color) clif->refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); @@ -9499,7 +9531,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if (iMap->night_flag && map[sd->bl.m].flag.nightenabled) { sd->state.night = 1; - clif->status_change(&sd->bl, SI_NIGHT, 1, 0, 0, 0, 0); + clif->status_change(&sd->bl, SI_SKE, 1, 0, 0, 0, 0); } // Notify everyone that this char logged in [Skotlex]. @@ -9537,11 +9569,11 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if( iMap->night_flag && map[sd->bl.m].flag.nightenabled ) { //Display night. if( !sd->state.night ) { sd->state.night = 1; - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_NIGHT); + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_SKE); } } else if( sd->state.night ) { //Clear night display. sd->state.night = 0; - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_NIGHT); + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_SKE); } if( map[sd->bl.m].flag.battleground ) { @@ -9586,7 +9618,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) npc_script_event(sd, NPCE_LOADMAP); if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) //blindness [Komurka] - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL); + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1); if (sd->sc.opt2) //Client loses these on warp. clif->changeoption(&sd->bl); @@ -9862,7 +9894,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) if( atcommand->parse(fd, sd, message, 1) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] @@ -10321,7 +10353,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) if ( atcommand->parse(fd, sd, message, 1) ) return; - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)) + if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)) return; if (battle_config.min_chat_delay) { //[Skotlex] @@ -10602,7 +10634,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) return; } else if ( sd->state.storage_flag || sd->sc.opt1 ) ; //You can equip/unequip stuff while storage is open/under status changes - else if ( pc_cant_act2(sd) ) + else if ( pc_cant_act2(sd) || sd->state.prerefining ) return; if(!sd->status.inventory[index].identify) { @@ -10730,7 +10762,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) return; } else if ( sd->state.storage_flag || sd->sc.opt1 ) ; //You can equip/unequip stuff while storage is open/under status changes - else if ( pc_cant_act2(sd) ) + else if ( pc_cant_act2(sd) || sd->state.prerefining ) return; index = RFIFOW(fd,2)-2; @@ -10751,7 +10783,12 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) clif_clearunit_area(&sd->bl,CLR_DEAD); return; } - + if( sd->npc_id || sd->state.workinprogress&2 ){ +#ifdef RENEWAL + clif->msg(sd, 0x783); // TODO look for the client date that has this message. +#endif + return; + } if ( pc_cant_act2(sd) || !(bl = iMap->id2bl(RFIFOL(fd,2))) ) return; @@ -10761,8 +10798,10 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) clif->pActionRequest_sub(sd, 0x07, bl->id, iTimer->gettick()); break; case BL_NPC: - if( sd->ud.skilltimer != INVALID_TIMER ) { - clif->colormes(fd,COLOR_WHITE,msg_txt(1476)); + if( sd->ud.skill_id < RK_ENCHANTBLADE && sd->ud.skilltimer != INVALID_TIMER ) {// TODO: should only work with none 3rd job skills +#ifdef RENEWAL + clif->msg(sd, 0x783); +#endif break; } if( bl->m != -1 )// the user can't click floating npcs directly (hack attempt) @@ -11270,7 +11309,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] sd->idletime = last_tick; - if( sd->npc_id ){ + if( sd->npc_id || sd->state.workinprogress&1 ){ #ifdef RENEWAL clif->msg(sd, 0x783); // TODO look for the client date that has this message. #endif @@ -11563,6 +11602,8 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) { int idx; + sd->state.prerefining = 0; + if (sd->menuskill_id != WS_WEAPONREFINE) //Packet exploit? return; if (pc_istrading(sd)) { @@ -11664,6 +11705,8 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) if (sd->menuskill_id != MC_IDENTIFY) return; if( idx == -1 ) {// cancel pressed + sd->state.workinprogress = 0; + clif->item_identified(sd,idx-2,1); clif_menuskill_clear(sd); return; } @@ -12096,7 +12139,7 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) if( atcommand->parse(fd, sd, message, 1) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) @@ -12658,7 +12701,7 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) const uint8* data = (uint8*)RFIFOP(fd,85); if( !flag ) - sd->state.prevend = 0; + sd->state.prevend = sd->state.workinprogress = 0; if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM ) return; @@ -12937,7 +12980,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) if( atcommand->parse(fd, sd, message, 1) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) @@ -15790,7 +15833,7 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd) if( atcommand->parse(fd, sd, message, 1) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEPSLEEP] || sd->sc.data[SC__BLOODYLUST] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { @@ -16735,7 +16778,7 @@ int clif_spellbook_list(struct map_session_data *sd) if( itemdb_is_spellbook(sd->status.inventory[i].nameid) ) { WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid; - c ++; + c++; } } @@ -16926,7 +16969,7 @@ void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd) { /*========================================== * Kagerou/Oboro amulet spirit *------------------------------------------*/ -void clif_talisman(struct map_session_data *sd,short type) +void clif_charm(struct map_session_data *sd,short type) { unsigned char buf[10]; @@ -16935,7 +16978,7 @@ void clif_talisman(struct map_session_data *sd,short type) WBUFW(buf,0)=0x08cf; WBUFL(buf,2)=sd->bl.id; WBUFW(buf,6)=type; - WBUFW(buf,8)=sd->talisman[type]; + WBUFW(buf,8)=sd->charm[type]; clif->send(buf,packet_len(0x08cf),&sd->bl,AREA); } /// Move Item from or to Personal Tab (CZ_WHATSOEVER) [FE] @@ -17744,7 +17787,7 @@ void clif_defaults(void) { clif->skill_fail = clif_skill_fail; clif->skill_cooldown = clif_skill_cooldown; clif->skill_memomessage = clif_skill_memomessage; - clif->skill_teleportmessage = clif_skill_teleportmessage; + clif->skill_mapinfomessage = clif_skill_mapinfomessage; clif->skill_produce_mix_list = clif_skill_produce_mix_list; clif->cooking_list = clif_cooking_list; clif->autospell = clif_autospell; @@ -17845,8 +17888,8 @@ void clif_defaults(void) { clif->specialeffect_single = clif_specialeffect_single; clif->specialeffect_value = clif_specialeffect_value; clif->millenniumshield = clif_millenniumshield; - clif->talisman = clif_talisman; - clif->talisman_single = clif_talisman_single; + clif->charm = clif_charm; + clif->charm_single = clif_charm_single; clif->snap = clif_snap; clif->weather_check = clif_weather_check; /* sound effects client-side */ diff --git a/src/map/clif.h b/src/map/clif.h index 5393ef5b7..b447687ea 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -231,7 +231,7 @@ enum map_type { // clif_map_type MAPTYPE_UNUSED = 29, }; -enum useskill_fail_cause { // clif_skill_fail +typedef enum useskill_fail_cause { // clif_skill_fail USESKILL_FAIL_LEVEL = 0, USESKILL_FAIL_SP_INSUFFICIENT = 1, USESKILL_FAIL_HP_INSUFFICIENT = 2, @@ -272,7 +272,7 @@ enum useskill_fail_cause { // clif_skill_fail USESKILL_FAIL_CANONBALL = 37, //XXX_USESKILL_FAIL_II_MADOGEAR_ACCELERATION = 38, //XXX_USESKILL_FAIL_II_MADOGEAR_HOVERING_BOOSTER = 39, - USESKILL_FAIL_MADOGEAR_HOVERING = 40, + //XXX_USESKILL_FAIL_MADOGEAR_HOVERING = 40, //XXX_USESKILL_FAIL_II_MADOGEAR_SELFDESTRUCTION_DEVICE = 41, //XXX_USESKILL_FAIL_II_MADOGEAR_SHAPESHIFTER = 42, USESKILL_FAIL_GUILLONTINE_POISON = 43, @@ -316,7 +316,7 @@ enum useskill_fail_cause { // clif_skill_fail USESKILL_FAIL_STYLE_CHANGE_FIGHTER = 81, USESKILL_FAIL_STYLE_CHANGE_GRAPPLER = 82, USESKILL_FAIL_THERE_ARE_NPC_AROUND = 83, -}; +}useskill_fail_cause; enum clif_messages { SKILL_CANT_USE_AREA = 0x536, @@ -571,7 +571,7 @@ struct clif_interface { void (*skill_fail) (struct map_session_data *sd,uint16 skill_id,enum useskill_fail_cause cause,int btype); void (*skill_cooldown) (struct map_session_data *sd, uint16 skill_id, unsigned int tick); void (*skill_memomessage) (struct map_session_data* sd, int type); - void (*skill_teleportmessage) (struct map_session_data *sd, int type); + void (*skill_mapinfomessage) (struct map_session_data *sd, int type); void (*skill_produce_mix_list) (struct map_session_data *sd, int skill_id, int trigger); void (*cooking_list) (struct map_session_data *sd, int trigger, uint16 skill_id, int qty, int list_type); void (*autospell) (struct map_session_data *sd,uint16 skill_lv); @@ -672,8 +672,8 @@ struct clif_interface { void (*specialeffect_single) (struct block_list* bl, int type, int fd); void (*specialeffect_value) (struct block_list* bl, int effect_id, int num, send_target target); void (*millenniumshield) (struct map_session_data *sd, short shields ); - void (*talisman) (struct map_session_data *sd, short type); - void (*talisman_single) (int fd, struct map_session_data *sd, short type); + void (*charm) (struct map_session_data *sd, short type); + void (*charm_single) (int fd, struct map_session_data *sd, short type); void (*snap) ( struct block_list *bl, short x, short y ); void (*weather_check) (struct map_session_data *sd); /* sound effects client-side */ diff --git a/src/map/itemdb.h b/src/map/itemdb.h index c441de26a..ea478d135 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -22,11 +22,13 @@ #define MAX_ITEMS_PER_COMBO 6 enum item_itemid { + ITEMID_HOLY_WATER = 523, ITEMID_EMPERIUM = 714, ITEMID_YELLOW_GEMSTONE = 715, ITEMID_RED_GEMSTONE = 716, ITEMID_BLUE_GEMSTONE = 717, ITEMID_TRAP = 1065, + ITEMID_FACE_PAINT = 6120, ITEMID_STONE = 7049, ITEMID_SKULL_ = 7420, ITEMID_TOKEN_OF_SIEGFRIED = 7621, @@ -66,6 +68,7 @@ enum { ITEMID_CAMOUFLAGE_GENERATOR, ITEMID_HIGH_QUALITY_COOLER, ITEMID_SPECIAL_COOLER, + ITEMID_MONKEY_SPANNER = 6186, } mecha_item_list; enum { diff --git a/src/map/map.c b/src/map/map.c index 0dab56d21..510f36109 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -358,10 +358,10 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) sc = status_get_sc(bl); skill->unit_move(bl,tick,2); - status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); - status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); // status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... - status_change_end(bl, SC_TATAMIGAESHI, INVALID_TIMER); + status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); if (sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) @@ -1667,45 +1667,19 @@ int map_quit(struct map_session_data *sd) { //(changing map-servers invokes unit_free but bypasses iMap->quit) if( sd->sc.count ) { //Status that are not saved... - status_change_end(&sd->bl, SC_BOSSMAPINFO, INVALID_TIMER); - status_change_end(&sd->bl, SC_AUTOTRADE, INVALID_TIMER); - status_change_end(&sd->bl, SC_SPURT, INVALID_TIMER); - status_change_end(&sd->bl, SC_BERSERK, INVALID_TIMER); - status_change_end(&sd->bl, SC__BLOODYLUST, INVALID_TIMER); - status_change_end(&sd->bl, SC_TRICKDEAD, INVALID_TIMER); - status_change_end(&sd->bl, SC_LEADERSHIP, INVALID_TIMER); - status_change_end(&sd->bl, SC_GLORYWOUNDS, INVALID_TIMER); - status_change_end(&sd->bl, SC_SOULCOLD, INVALID_TIMER); - status_change_end(&sd->bl, SC_HAWKEYES, INVALID_TIMER); - if(sd->sc.data[SC_ENDURE] && sd->sc.data[SC_ENDURE]->val4) - status_change_end(&sd->bl, SC_ENDURE, INVALID_TIMER); //No need to save infinite endure. - status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER); - status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER); - status_change_end(&sd->bl, SC_SATURDAYNIGHTFEVER, INVALID_TIMER); - status_change_end(&sd->bl, SC_KYOUGAKU, INVALID_TIMER); - if (battle_config.debuff_on_logout&1) { - status_change_end(&sd->bl, SC_ORCISH, INVALID_TIMER); - status_change_end(&sd->bl, SC_STRIPWEAPON, INVALID_TIMER); - status_change_end(&sd->bl, SC_STRIPARMOR, INVALID_TIMER); - status_change_end(&sd->bl, SC_STRIPSHIELD, INVALID_TIMER); - status_change_end(&sd->bl, SC_STRIPHELM, INVALID_TIMER); - status_change_end(&sd->bl, SC_EXTREMITYFIST, INVALID_TIMER); - status_change_end(&sd->bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER); - if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) - status_change_end(&sd->bl, SC_REGENERATION, INVALID_TIMER); - //TO-DO Probably there are way more NPC_type negative status that are removed - status_change_end(&sd->bl, SC_CHANGEUNDEAD, INVALID_TIMER); - // Both these statuses are removed on logout. [L0ne_W0lf] - status_change_end(&sd->bl, SC_SLOWCAST, INVALID_TIMER); - status_change_end(&sd->bl, SC_CRITICALWOUND, INVALID_TIMER); - } - if (battle_config.debuff_on_logout&2) { - status_change_end(&sd->bl, SC_MAXIMIZEPOWER, INVALID_TIMER); - status_change_end(&sd->bl, SC_MAXOVERTHRUST, INVALID_TIMER); - status_change_end(&sd->bl, SC_STEELBODY, INVALID_TIMER); - status_change_end(&sd->bl, SC_PRESERVE, INVALID_TIMER); - status_change_end(&sd->bl, SC_KAAHI, INVALID_TIMER); - status_change_end(&sd->bl, SC_SPIRIT, INVALID_TIMER); + for(i=0; i < SC_MAX; i++){ + if ( status_get_sc_type(i)&SC_NO_SAVE ){ + if ( !sd->sc.data[i] ) + continue; + switch( i ){ + case SC_ENDURE: + case SC_GDSKILL_REGENERATION: + if( !sd->sc.data[i]->val4 ) + break; + default: + status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER); + } + } } } diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 91d685a49..566f68409 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -361,7 +361,7 @@ int mercenary_dead(struct mercenary_data *md) int mercenary_killbonus(struct mercenary_data *md) { - const enum sc_type scs[] = { SC_MERC_FLEEUP, SC_MERC_ATKUP, SC_MERC_HPUP, SC_MERC_SPUP, SC_MERC_HITUP }; + const enum sc_type scs[] = { SC_MER_FLEE, SC_MER_ATK, SC_MER_HP, SC_MER_SP, SC_MER_HIT }; int index = rnd() % ARRAYLENGTH(scs); sc_start(&md->bl, scs[index], 100, rnd() % 5, 600000); diff --git a/src/map/mob.c b/src/map/mob.c index 04c4bba38..6bb40478f 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1461,7 +1461,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) if( !battle->check_range(&md->bl, tbl, md->status.rhw.range) && ( //Can't attack back and can't reach back. (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) - || md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP] + || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. || !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) ) @@ -1484,7 +1484,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) || (!battle->check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... && ( // Reach check (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) - || md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP] + || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. || !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH) ) @@ -2360,9 +2360,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) (int)(md->level - sd->status.base_level) >= 20) drop_rate = (int)(drop_rate*1.25); // pk_mode increase drops if 20 level difference [Valaris] - // Increase drop rate if user has SC_ITEMBOOST - if (sd && sd->sc.data[SC_ITEMBOOST]) // now rig the drop rate to never be over 90% unless it is originally >90%. - drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_ITEMBOOST]->val1)/100.),0,9000)); + // Increase drop rate if user has SC_CASH_RECEIVEITEM + if (sd && sd->sc.data[SC_CASH_RECEIVEITEM]) // now rig the drop rate to never be over 90% unless it is originally >90%. + drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_CASH_RECEIVEITEM]->val1)/100.),0,9000)); #ifdef RENEWAL_DROP if( drop_modifier != 100 ) { drop_rate = drop_rate * drop_modifier / 100; diff --git a/src/map/packets.h b/src/map/packets.h index 4f2b119fb..bcce36040 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -2091,6 +2091,7 @@ packet(0x020d,-1); // New Packets packet(0x0998,8,clif->pEquipItem,2,4); packet(0x0447,2); // PACKET_CZ_BLOCKING_PLAY_CANCEL + packet(0x099f,24); // New Packets End #endif diff --git a/src/map/party.c b/src/map/party.c index e30d16c07..adcb35c5a 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -840,7 +840,7 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id break; case MO_COMBOFINISH: //Increase Counter rate of Star Gladiators if((p_sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR - && sd->sc.data[SC_READYCOUNTER] + && sd->sc.data[SC_COUNTERKICK_READY] && pc->checkskill(p_sd,SG_FRIEND)) { sc_start4(&p_sd->bl,SC_SKILLRATE_UP,100,TK_COUNTER, 50+50*pc->checkskill(p_sd,SG_FRIEND), //+100/150/200% rate diff --git a/src/map/pc.c b/src/map/pc.c index 170de63ff..155812836 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -868,20 +868,20 @@ int pc_isequip(struct map_session_data *sd,int n) if (sd->sc.count) { - if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_STRIPWEAPON]) // Also works with left-hand weapons [DracoRPG] + if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_NOEQUIPWEAPON]) // Also works with left-hand weapons [DracoRPG] return 0; - if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_STRIPSHIELD]) + if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_NOEQUIPSHIELD]) return 0; - if(item->equip & EQP_ARMOR && sd->sc.data[SC_STRIPARMOR]) + if(item->equip & EQP_ARMOR && sd->sc.data[SC_NOEQUIPARMOR]) return 0; - if(item->equip & EQP_HEAD_TOP && sd->sc.data[SC_STRIPHELM]) + if(item->equip & EQP_HEAD_TOP && sd->sc.data[SC_NOEQUIPHELM]) return 0; - if(item->equip & EQP_ACC && sd->sc.data[SC__STRIPACCESSORY]) + if(item->equip & EQP_ACC && sd->sc.data[SC__STRIPACCESSARY]) return 0; if(item->equip && sd->sc.data[SC_KYOUGAKU]) return 0; - if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SUPERNOVICE) { + if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SUPERNOVICE) { //Spirit of Super Novice equip bonuses. [Skotlex] if (sd->status.base_level > 90 && item->equip & EQP_HELM) return 1; //Can equip all helms @@ -1338,7 +1338,7 @@ int pc_calc_skilltree(struct map_session_data *sd) sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } - if( sd->sc.count && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_BARDDANCER && skill_db[i].nameid >= DC_HUMMING && skill_db[i].nameid <= DC_SERVICEFORYOU ) + if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill_db[i].nameid >= DC_HUMMING && skill_db[i].nameid <= DC_SERVICEFORYOU ) { //Enable Bard/Dancer spirit linked skills. if( sd->status.sex ) { //Link dancer skills to bard. @@ -1427,7 +1427,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if(!sd->status.skill[idx].lv && ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || inf2&INF2_WEDDING_SKILL || - (inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT]) + (inf2&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SOULLINK]) )) continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills. @@ -1459,7 +1459,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if( sd->status.skill[idx].id == 0 ) { sd->status.skill[idx].id = id; sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; // So it is not saved, and tagged as a "bonus" skill. - } else if( id != NV_BASIC) { + } else if( id != NV_BASIC ) { sd->status.skill[idx].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[idx].lv; // Remember original level } @@ -1518,7 +1518,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) if( !sd->status.skill[idx].lv && ( (j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || j&INF2_WEDDING_SKILL || - (j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SPIRIT]) + (j&INF2_SPIRIT_SKILL && !sd->sc.data[SC_SOULLINK]) ) ) continue; //Cannot be learned via normal means. @@ -1620,7 +1620,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) *------------------------------------------ * 1: overweight 50% * 2: overweight 90% - * It's assumed that SC_WEIGHT50 and SC_WEIGHT90 are only started/stopped here. + * It's assumed that SC_WEIGHTOVER50 and SC_WEIGHTOVER90 are only started/stopped here. */ int pc_updateweightstatus(struct map_session_data *sd) { @@ -1629,7 +1629,7 @@ int pc_updateweightstatus(struct map_session_data *sd) nullpo_retr(1, sd); - old_overweight = (sd->sc.data[SC_WEIGHT90]) ? 2 : (sd->sc.data[SC_WEIGHT50]) ? 1 : 0; + old_overweight = (sd->sc.data[SC_WEIGHTOVER90]) ? 2 : (sd->sc.data[SC_WEIGHTOVER50]) ? 1 : 0; new_overweight = (pc_is90overweight(sd)) ? 2 : (pc_is50overweight(sd)) ? 1 : 0; if( old_overweight == new_overweight ) @@ -1637,15 +1637,15 @@ int pc_updateweightstatus(struct map_session_data *sd) // stop old status change if( old_overweight == 1 ) - status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER); + status_change_end(&sd->bl, SC_WEIGHTOVER50, INVALID_TIMER); else if( old_overweight == 2 ) - status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER); + status_change_end(&sd->bl, SC_WEIGHTOVER90, INVALID_TIMER); // start new status change if( new_overweight == 1 ) - sc_start(&sd->bl, SC_WEIGHT50, 100, 0, 0); + sc_start(&sd->bl, SC_WEIGHTOVER50, 100, 0, 0); else if( new_overweight == 2 ) - sc_start(&sd->bl, SC_WEIGHT90, 100, 0, 0); + sc_start(&sd->bl, SC_WEIGHTOVER90, 100, 0, 0); // update overweight status sd->regen.state.overweight = new_overweight; @@ -2070,12 +2070,13 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_BASE_ATK: if(sd->state.lr_flag != 2) { - //#ifdef RENEWAL - // sd->bonus.eatk += val; - //#else +#ifdef RENEWAL + sd->bonus.eatk += val; + clif->updatestatus(sd,SP_ATK2); +#else bonus = status->batk + val; status->batk = cap_value(bonus, 0, USHRT_MAX); - //#endif +#endif } break; case SP_DEF1: @@ -2431,7 +2432,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG] if(sd->state.lr_flag != 2) { sd->special_state.intravision = 1; - clif->status_change(&sd->bl, SI_INTRAVISION, 1, 0, 0, 0, 0); + clif->status_change(&sd->bl, SI_CLAIRVOYANCE, 1, 0, 0, 0, 0); } break; case SP_NO_KNOCKBACK: @@ -4122,7 +4123,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) case 12212: // Giant Fly Wing if( map[sd->bl.m].flag.noteleport || map_flag_gvg(sd->bl.m) ) { - clif->skill_teleportmessage(sd,0); + clif->skill_mapinfomessage(sd,0); return 0; } case 602: // ButterFly Wing @@ -4150,7 +4151,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) break; case 12210: // Bubble Gum case 12264: // Comp Bubble Gum - if( sd->sc.data[SC_ITEMBOOST] ) + if( sd->sc.data[SC_CASH_RECEIVEITEM] ) return 0; break; case 12208: // Battle Manual @@ -4160,11 +4161,11 @@ int pc_isUseitem(struct map_session_data *sd,int n) case 14532: // Battle_Manual25 case 14533: // Battle_Manual100 case 14545: // Battle_Manual300 - if( sd->sc.data[SC_EXPBOOST] ) + if( sd->sc.data[SC_CASH_PLUSEXP] ) return 0; break; case 14592: // JOB_Battle_Manual - if( sd->sc.data[SC_JEXPBOOST] ) + if( sd->sc.data[SC_CASH_PLUSONLYJOBEXP] ) return 0; break; @@ -4177,7 +4178,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) case 12243: // Mercenary's Berserk Potion if( sd->md == NULL || sd->md->db == NULL ) return 0; - if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAYNIGHTFEVER] || sd->md->sc.data[SC__BLOODYLUST]) + if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->md->sc.data[SC__BLOODYLUST]) return 0; if( nameid == 12242 && sd->md->db->lv < 40 ) return 0; @@ -4281,7 +4282,8 @@ int pc_useitem(struct map_session_data *sd,int n) sd->sc.data[SC_HIDING] || sd->sc.data[SC__SHADOWFORM] || sd->sc.data[SC__MANHOLE] || - sd->sc.data[SC_KAGEHUMI] || + sd->sc.data[SC_KG_KAGEHUMI] || + sd->sc.data[SC_WHITEIMPRISON] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) )) return 0; @@ -4315,16 +4317,7 @@ int pc_useitem(struct map_session_data *sd,int n) if( sd->item_delay[i].nameid ) {// found if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) { int e_tick = DIFF_TICK(sd->item_delay[i].tick, tick)/1000; - char e_msg[100]; - if( e_tick > 99 ) - sprintf(e_msg,"Item Failed. [%s] is cooling down. wait %.1f minutes.", - itemdb_jname(sd->status.inventory[n].nameid), - (double)e_tick / 60); - else - sprintf(e_msg,"Item Failed. [%s] is cooling down. wait %d seconds.", - itemdb_jname(sd->status.inventory[n].nameid), - e_tick+1); - clif->colormes(sd->fd,COLOR_RED,e_msg); + clif->msgtable_num(sd->fd, 0x746, e_tick + 1); // [%d] seconds left until you can use return 0; // Delay has not expired yet } } else {// not yet used item (all slots are initially empty) @@ -4375,7 +4368,7 @@ int pc_useitem(struct map_session_data *sd,int n) pc->famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST)) { potion_flag = 2; // Famous player's potions have 50% more efficiency - if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ROGUE) + if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ROGUE) potion_flag = 3; //Even more effective potions. } @@ -4781,7 +4774,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y if (sd->sc.count) { // Cancel some map related stuff. if (sd->sc.data[SC_JAILED]) return 1; //You may not get out! - status_change_end(&sd->bl, SC_BOSSMAPINFO, INVALID_TIMER); + status_change_end(&sd->bl, SC_CASH_BOSS_ALARM, INVALID_TIMER); status_change_end(&sd->bl, SC_WARM, INVALID_TIMER); status_change_end(&sd->bl, SC_SUN_COMFORT, INVALID_TIMER); status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER); @@ -4947,7 +4940,7 @@ int pc_memo(struct map_session_data* sd, int pos) // check mapflags if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { - clif->skill_teleportmessage(sd, 1); // "Saved point cannot be memorized." + clif->skill_mapinfomessage(sd, 1); // "Saved point cannot be memorized." return 0; } @@ -5038,21 +5031,24 @@ int pc_checkallowskill(struct map_session_data *sd) { const enum sc_type scw_list[] = { SC_TWOHANDQUICKEN, - SC_ONEHAND, + SC_ONEHANDQUICKEN, SC_AURABLADE, SC_PARRYING, SC_SPEARQUICKEN, SC_ADRENALINE, SC_ADRENALINE2, SC_DANCING, - SC_GATLINGFEVER, + SC_GS_GATLINGFEVER, +#ifdef RENEWAL + SC_EDP, +#endif SC_FEARBREEZE }; const enum sc_type scs_list[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, - SC_REFLECTDAMAGE + SC_LG_REFLECTDAMAGE }; int i; nullpo_ret(sd); @@ -5069,9 +5065,9 @@ int pc_checkallowskill(struct map_session_data *sd) status_change_end(&sd->bl, scw_list[i], INVALID_TIMER); } - if(sd->sc.data[SC_SPURT] && sd->status.weapon) + if(sd->sc.data[SC_STRUP] && sd->status.weapon) // Spurt requires bare hands (feet, in fact xD) - status_change_end(&sd->bl, SC_SPURT, INVALID_TIMER); + status_change_end(&sd->bl, SC_STRUP, INVALID_TIMER); if(sd->status.shield <= 0) { // Skills requiring a shield for (i = 0; i < ARRAYLENGTH(scs_list); i++) @@ -5755,7 +5751,7 @@ int pc_checkjoblevelup(struct map_session_data *sd) status_calc_pc(sd,0); clif->misceffect(&sd->bl,1); if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) - clif->status_change(&sd->bl,SI_DEVIL, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. + clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. npc_script_event(sd, NPCE_JOBLVUP); return 1; @@ -5777,13 +5773,13 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi (int)(status_get_lv(src) - sd->status.base_level) >= 20) bonus += 15; // pk_mode additional exp if monster >20 levels [Valaris] - if (sd->sc.data[SC_EXPBOOST]) - bonus += sd->sc.data[SC_EXPBOOST]->val1; + if (sd->sc.data[SC_CASH_PLUSEXP]) + bonus += sd->sc.data[SC_CASH_PLUSEXP]->val1; *base_exp = (unsigned int) cap_value(*base_exp + (double)*base_exp * bonus/100., 1, UINT_MAX); - if (sd->sc.data[SC_JEXPBOOST]) - bonus += sd->sc.data[SC_JEXPBOOST]->val1; + if (sd->sc.data[SC_CASH_PLUSONLYJOBEXP]) + bonus += sd->sc.data[SC_CASH_PLUSONLYJOBEXP]->val1; *job_exp = (unsigned int) cap_value(*job_exp + (double)*job_exp * bonus/100., 1, UINT_MAX); @@ -6134,6 +6130,19 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { clif->updatestatus(sd,SP_CARTINFO); if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown clif->skillinfoblock(sd); + }else if( battle_config.skillup_limit ){ + int pts = 0, i, id; + for(i = 0; i < MAX_SKILL_TREE && (id=skill_tree[pc_class2idx(sd->status.class_)][i].id) > 0 ; i++){ + int inf2 = skill->get_inf2(id); + if ( inf2&INF2_QUEST_SKILL || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || id == NV_BASIC ) + continue; + if( sd->status.skill[id].id && sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) + pts += pc_checkskill(sd, id); + } + if( pts < sd->change_level_2nd ) + clif->msg_value(sd, 0x61E, sd->change_level_2nd-pts); + else if( pts < (sd->change_level_3rd + sd->change_level_2nd) ) + clif->msg_value(sd, 0x61F, sd->change_level_3rd - (pts - sd->change_level_2nd)); } return 0; @@ -6370,7 +6379,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) return 0; if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex] - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL); + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1); i = sd->sc.option; if( i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) ) i &= ~OPTION_RIDING; @@ -6691,7 +6700,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { pc->delspiritball(sd,sd->spiritball,0); for(i = 1; i < 5; i++) - pc->del_talisman(sd, sd->talisman[i], i); + pc->del_charm(sd, sd->charm[i], i); if (src) { switch (src->type) { @@ -6801,7 +6810,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { if(battle_config.death_penalty_type && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty && !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m) - && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_LIFEINSURANCE]) + && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]) { unsigned int base_penalty =0; if (battle_config.death_penalty_base > 0) { @@ -7304,8 +7313,8 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) hp = hp * bonus / 100; // Recovery Potion - if( sd->sc.data[SC_INCHEALRATE] ) - hp += (int)(hp * sd->sc.data[SC_INCHEALRATE]->val1/100.); + if( sd->sc.data[SC_HEALPLUS] ) + hp += (int)(hp * sd->sc.data[SC_HEALPLUS]->val1/100.); } if(sp) { bonus = 100 + (sd->battle_status.int_<<1) @@ -7529,7 +7538,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) //Remove peco/cart/falcon i = sd->sc.option; - if( i&OPTION_RIDING && !pc->checkskill(sd, KN_RIDING) ) + if( i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) ) i&=~OPTION_RIDING; if( i&OPTION_FALCON && !pc->checkskill(sd, HT_FALCON) ) i&=~OPTION_FALCON; @@ -7715,22 +7724,23 @@ int pc_setoption(struct map_session_data *sd,int type) } } if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) { - if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) { + int i; + if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) status_calc_pc(sd, 0); - status_change_end(&sd->bl,SC_MAXIMIZEPOWER,INVALID_TIMER); - status_change_end(&sd->bl,SC_OVERTHRUST,INVALID_TIMER); - status_change_end(&sd->bl,SC_WEAPONPERFECTION,INVALID_TIMER); - status_change_end(&sd->bl,SC_ADRENALINE,INVALID_TIMER); - status_change_end(&sd->bl,SC_CARTBOOST,INVALID_TIMER); - status_change_end(&sd->bl,SC_MELTDOWN,INVALID_TIMER); - status_change_end(&sd->bl,SC_MAXOVERTHRUST,INVALID_TIMER); - } else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) { + else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) status_calc_pc(sd, 0); - status_change_end(&sd->bl,SC_SHAPESHIFT,INVALID_TIMER); - status_change_end(&sd->bl,SC_HOVERING,INVALID_TIMER); - status_change_end(&sd->bl,SC_ACCELERATION,INVALID_TIMER); - status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER); - status_change_end(&sd->bl,SC_OVERHEAT,INVALID_TIMER); + for( i = 0; i < SC_MAX; i++ ){ + if ( !sd->sc.data[i] || !status_get_sc_type(i) ) + continue; + if ( status_get_sc_type(i)&SC_MADO_NO_RESET ) + continue; + switch (i) { + case SC_BERSERK: + case SC_SATURDAY_NIGHT_FEVER: + sd->sc.data[i]->val2 = 0; + break; + } + status_change_end(&sd->bl, (sc_type)i, INVALID_TIMER); } } @@ -8503,7 +8513,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) return 0; } - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || sd->sc.data[SC__BLOODYLUST]) + if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST]) { clif->equipitemack(sd,n,0,0); // fail return 0; @@ -8699,7 +8709,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { } // if player is berserk then cannot unequip - if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || sd->sc.data[SC__BLOODYLUST])) + if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST])) { clif->unequipitemack(sd,n,0,0); return 0; @@ -8780,7 +8790,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { clif->unequipitemack(sd,n,sd->status.inventory[n].equip,1); if((sd->status.inventory[n].equip & EQP_ARMS) && - sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) + sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_TK_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) skill->enchant_elemental_end(&sd->bl,-1); if(sd->status.inventory[n].equip & EQP_ARMOR) { @@ -8822,8 +8832,8 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { status_calc_pc(sd,0); } - if(sd->sc.data[SC_SIGNUMCRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele)) - status_change_end(&sd->bl, SC_SIGNUMCRUCIS, INVALID_TIMER); + if(sd->sc.data[SC_CRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele)) + status_change_end(&sd->bl, SC_CRUCIS, INVALID_TIMER); //OnUnEquip script [Skotlex] if (sd->inventory_data[n]) { @@ -9209,7 +9219,7 @@ int pc_autosave(int tid, unsigned int tick, int id, intptr_t data) static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) { if (sd->state.night != iMap->night_flag && map[sd->bl.m].flag.nightenabled) { //Night/day state does not match. - clif->status_change(&sd->bl, SI_NIGHT, iMap->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] + clif->status_change(&sd->bl, SI_SKE, iMap->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] sd->state.night = iMap->night_flag; return 1; } @@ -9313,7 +9323,7 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command) { return atcommand->can_use(sd,command); } -static int pc_talisman_timer(int tid, unsigned int tick, int id, intptr_t data) +static int pc_charm_timer(int tid, unsigned int tick, int id, intptr_t data) { struct map_session_data *sd; int i, type; @@ -9321,33 +9331,33 @@ static int pc_talisman_timer(int tid, unsigned int tick, int id, intptr_t data) if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; - ARR_FIND(1, 5, type, sd->talisman[type] > 0); + ARR_FIND(1, 5, type, sd->charm[type] > 0); - if( sd->talisman[type] <= 0 ) + if( sd->charm[type] <= 0 ) { - ShowError("pc_talisman_timer: %d talisman's available. (aid=%d cid=%d tid=%d)\n", sd->talisman[type], sd->status.account_id, sd->status.char_id, tid); - sd->talisman[type] = 0; + ShowError("pc_charm_timer: %d charm's available. (aid=%d cid=%d tid=%d)\n", sd->charm[type], sd->status.account_id, sd->status.char_id, tid); + sd->charm[type] = 0; return 0; } - ARR_FIND(0, sd->talisman[type], i, sd->talisman_timer[type][i] == tid); - if( i == sd->talisman[type] ) + ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == tid); + if( i == sd->charm[type] ) { - ShowError("pc_talisman_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid); + ShowError("pc_charm_timer: timer not found (aid=%d cid=%d tid=%d)\n", sd->status.account_id, sd->status.char_id, tid); return 0; } - sd->talisman[type]--; - if( i != sd->talisman[type] ) - memmove(sd->talisman_timer[type]+i, sd->talisman_timer[type]+i+1, (sd->talisman[type]-i)*sizeof(int)); - sd->talisman_timer[type][sd->talisman[type]] = INVALID_TIMER; + sd->charm[type]--; + if( i != sd->charm[type] ) + memmove(sd->charm_timer[type]+i, sd->charm_timer[type]+i+1, (sd->charm[type]-i)*sizeof(int)); + sd->charm_timer[type][sd->charm[type]] = INVALID_TIMER; - clif->talisman(sd, type); + clif->charm(sd, type); return 0; } -int pc_add_talisman(struct map_session_data *sd,int interval,int max,int type) +int pc_add_charm(struct map_session_data *sd,int interval,int max,int type) { int tid, i; @@ -9355,61 +9365,61 @@ int pc_add_talisman(struct map_session_data *sd,int interval,int max,int type) if(max > 10) max = 10; - if(sd->talisman[type] < 0) - sd->talisman[type] = 0; + if(sd->charm[type] < 0) + sd->charm[type] = 0; - if( sd->talisman[type] && sd->talisman[type] >= max ) + if( sd->charm[type] && sd->charm[type] >= max ) { - if(sd->talisman_timer[type][0] != INVALID_TIMER) - iTimer->delete_timer(sd->talisman_timer[type][0],pc_talisman_timer); - sd->talisman[type]--; - if( sd->talisman[type] != 0 ) - memmove(sd->talisman_timer[type]+0, sd->talisman_timer[type]+1, (sd->talisman[type])*sizeof(int)); - sd->talisman_timer[type][sd->talisman[type]] = INVALID_TIMER; - } - - tid = iTimer->add_timer(iTimer->gettick()+interval, pc_talisman_timer, sd->bl.id, 0); - ARR_FIND(0, sd->talisman[type], i, sd->talisman_timer[type][i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick,iTimer->get_timer(sd->talisman_timer[type][i])->tick) < 0); - if( i != sd->talisman[type] ) - memmove(sd->talisman_timer[type]+i+1, sd->talisman_timer[type]+i, (sd->talisman[type]-i)*sizeof(int)); - sd->talisman_timer[type][i] = tid; - sd->talisman[type]++; - - clif->talisman(sd, type); + if(sd->charm_timer[type][0] != INVALID_TIMER) + iTimer->delete_timer(sd->charm_timer[type][0],pc_charm_timer); + sd->charm[type]--; + if( sd->charm[type] != 0 ) + memmove(sd->charm_timer[type]+0, sd->charm_timer[type]+1, (sd->charm[type])*sizeof(int)); + sd->charm_timer[type][sd->charm[type]] = INVALID_TIMER; + } + + tid = iTimer->add_timer(iTimer->gettick()+interval, pc_charm_timer, sd->bl.id, 0); + ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick, iTimer->get_timer(sd->charm_timer[type][i])->tick) < 0); + if( i != sd->charm[type] ) + memmove(sd->charm_timer[type]+i+1, sd->charm_timer[type]+i, (sd->charm[type]-i)*sizeof(int)); + sd->charm_timer[type][i] = tid; + sd->charm[type]++; + + clif->charm(sd, type); return 0; } -int pc_del_talisman(struct map_session_data *sd,int count,int type) +int pc_del_charm(struct map_session_data *sd,int count,int type) { int i; nullpo_ret(sd); - if( sd->talisman[type] <= 0 ) { - sd->talisman[type] = 0; + if( sd->charm[type] <= 0 ) { + sd->charm[type] = 0; return 0; } if( count <= 0 ) return 0; - if( count > sd->talisman[type] ) - count = sd->talisman[type]; - sd->talisman[type] -= count; + if( count > sd->charm[type] ) + count = sd->charm[type]; + sd->charm[type] -= count; if( count > 10 ) count = 10; for(i = 0; i < count; i++) { - if(sd->talisman_timer[type][i] != INVALID_TIMER) { - iTimer->delete_timer(sd->talisman_timer[type][i],pc_talisman_timer); - sd->talisman_timer[type][i] = INVALID_TIMER; + if(sd->charm_timer[type][i] != INVALID_TIMER) { + iTimer->delete_timer(sd->charm_timer[type][i],pc_charm_timer); + sd->charm_timer[type][i] = INVALID_TIMER; } } for(i = count; i < 10; i++) { - sd->talisman_timer[type][i-count] = sd->talisman_timer[type][i]; - sd->talisman_timer[type][i] = INVALID_TIMER; + sd->charm_timer[type][i-count] = sd->charm_timer[type][i]; + sd->charm_timer[type][i] = INVALID_TIMER; } - clif->talisman(sd, type); + clif->charm(sd, type); return 0; } #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) @@ -9854,7 +9864,7 @@ int do_init_pc(void) { iTimer->add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); iTimer->add_timer_func_list(pc_follow_timer, "pc_follow_timer"); iTimer->add_timer_func_list(pc->endautobonus, "pc->endautobonus"); - iTimer->add_timer_func_list(pc_talisman_timer, "pc_talisman_timer"); + iTimer->add_timer_func_list(pc_charm_timer, "pc_charm_timer"); iTimer->add_timer(iTimer->gettick() + iMap->autosave_interval, pc_autosave, 0, 0); @@ -10087,8 +10097,8 @@ void pc_defaults(void) { pc->load_combo = pc_load_combo; - pc->add_talisman = pc_add_talisman; - pc->del_talisman = pc_del_talisman; + pc->add_charm = pc_add_charm; + pc->del_charm = pc_del_charm; pc->baselevelchanged = pc_baselevelchanged; #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) diff --git a/src/map/pc.h b/src/map/pc.h index ebf474823..cd2a45a6b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -160,6 +160,8 @@ struct map_session_data { unsigned int warping : 1;//states whether you're in the middle of a warp processing unsigned int permanent_speed : 1; // When 1, speed cannot be changed through status_calc_pc(). unsigned int dialog : 1; + unsigned int prerefining : 1; + unsigned int workinprogress : 3; // 1 = disable skill/item, 2 = disable npc interaction, 3 = disable both } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -190,7 +192,7 @@ struct map_session_data { unsigned char head_dir; //0: Look forward. 1: Look right, 2: Look left. unsigned int client_tick; int npc_id,areanpc_id,npc_shopid,touching_id; //for script follow scriptoid; ,npcid - int npc_item_flag; //Marks the npc_id with which you can use items during interactions with said npc (see script command enable_itemuse) + int npc_item_flag; //Marks the npc_id with which you can change equipments during interactions with said npc (see script command enable_itemuse) int npc_menu; // internal variable, used in npc menu handling int npc_amount; struct script_state *st; @@ -324,7 +326,7 @@ struct map_session_data { int fixcastrate,varcastrate; int add_fixcast,add_varcast; int ematk; // matk bonus from equipment -// int eatk; // atk bonus from equipment + int eatk; // atk bonus from equipment } bonus; // zeroed vars end here. int castrate,delayrate,hprate,sprate,dsprate; @@ -336,8 +338,8 @@ struct map_session_data { short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo] short spiritball, spiritball_old; int spirit_timer[MAX_SPIRITBALL]; - short talisman[ELE_POISON+1]; // There are actually 5 talisman Fire, Ice, Wind, Earth & Poison maybe because its color violet. - int talisman_timer[ELE_POISON+1][10]; + short charm[ELE_POISON+1]; // There are actually 5 charm Fire, Ice, Wind, Earth & Poison maybe because its color violet. + int charm_timer[ELE_POISON+1][10]; unsigned char potion_success_counter; //Potion successes in row counter unsigned char mission_count; //Stores the bounty kill count for TK_MISSION short mission_mobid; //Stores the target mob_id for TK_MISSION @@ -650,13 +652,13 @@ enum equip_pos { // clientside display macros (values to the left/right of the "+") #ifdef RENEWAL #define pc_leftside_atk(sd) ((sd)->battle_status.batk) - #define pc_rightside_atk(sd) ((sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk + (sd)->battle_status.rhw.atk2 + (sd)->battle_status.lhw.atk2) + #define pc_rightside_atk(sd) ((sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk + (sd)->battle_status.rhw.atk2 + (sd)->battle_status.lhw.atk2 + (sd)->bonus.eatk ) #define pc_leftside_def(sd) ((sd)->battle_status.def2) #define pc_rightside_def(sd) ((sd)->battle_status.def) #define pc_leftside_mdef(sd) ((sd)->battle_status.mdef2) #define pc_rightside_mdef(sd) ((sd)->battle_status.mdef) #define pc_leftside_matk(sd) (status_base_matk(status_get_status_data(&(sd)->bl), (sd)->status.base_level)) -#define pc_rightside_matk(sd) ((sd)->battle_status.rhw.matk+(sd)->bonus.ematk) +#define pc_rightside_matk(sd) ((sd)->battle_status.rhw.matk+(sd)->battle_status.lhw.matk+(sd)->bonus.ematk) #else #define pc_leftside_atk(sd) ((sd)->battle_status.batk + (sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk) #define pc_rightside_atk(sd) ((sd)->battle_status.rhw.atk2 + (sd)->battle_status.lhw.atk2) @@ -940,8 +942,8 @@ struct pc_interface { int (*load_combo) (struct map_session_data *sd); - int (*add_talisman) (struct map_session_data *sd,int interval,int max,int type); - int (*del_talisman) (struct map_session_data *sd,int count,int type); + int (*add_charm) (struct map_session_data *sd,int interval,int max,int type); + int (*del_charm) (struct map_session_data *sd,int count,int type); void (*baselevelchanged) (struct map_session_data *sd); #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) diff --git a/src/map/script.c b/src/map/script.c index e1015a718..a01372385 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9581,8 +9581,8 @@ BUILDIN(sc_end) switch (type) { - case SC_WEIGHT50: - case SC_WEIGHT90: + case SC_WEIGHTOVER50: + case SC_WEIGHTOVER90: case SC_NOCHAT: case SC_PUSH_CART: return true; diff --git a/src/map/skill.c b/src/map/skill.c index 15c133dc1..dcc422da5 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -346,7 +346,6 @@ int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { **/ case WL_WHITEIMPRISON: case WL_SOULEXPANSION: - case WL_FROSTMISTY: case WL_MARSHOFABYSS: case WL_SIENNAEXECRATE: case WL_DRAINLIFE: @@ -355,6 +354,7 @@ int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { case WL_COMET: case WL_CHAINLIGHTNING: case WL_TETRAVORTEX: + case WL_EARTHSTRAIN: case WL_RELEASE: if( bl->type == BL_PC ) range += pc->checkskill((TBL_PC*)bl, WL_RADIUS); @@ -385,13 +385,13 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk struct status_change* sc; switch( skill_id ) { - case BA_APPLEIDUN: + case BA_APPLEIDUN: #ifdef RENEWAL - hp = 100+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery + hp = 100+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery #else - hp = 30+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery + hp = 30+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery #endif - if( sd ) + if( sd ) hp += 5*pc->checkskill(sd,BA_MUSICALLESSON); break; case PR_SANCTUARY: @@ -406,7 +406,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk #ifdef RENEWAL /** * Renewal Heal Formula - * Formula: ( [(Base Level + INT) / 5] � 30 ) � (Heal Level / 10) � (Modifiers) + MATK + * Formula: ( [(Base Level + INT) / 5] ? 30 ) ? (Heal Level / 10) ? (Modifiers) + MATK **/ hp = (status_get_lv(src) + status_get_int(src)) / 5 * 30 * skill_lv / 10; #else @@ -434,10 +434,12 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk hp -= hp * sc->data[SC_CRITICALWOUND]->val2/100; if( sc->data[SC_DEATHHURT] && heal ) hp -= hp * 20/100; - if( sc->data[SC_INCHEALRATE] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN ) - hp += hp * sc->data[SC_INCHEALRATE]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish] + if( sc->data[SC_HEALPLUS] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN ) + hp += hp * sc->data[SC_HEALPLUS]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish] if( sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) hp += hp / 10; + if( sc->data[SC_OFFERTORIUM] && (skill_id == AB_HIGHNESSHEAL || skill_id == AB_CHEAL || skill_id == PR_SANCTUARY || skill_id == AL_HEAL) ) + hp += hp * sc->data[SC_OFFERTORIUM]->val2 / 100; } #ifdef RENEWAL @@ -447,32 +449,7 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk case BA_APPLEIDUN: case PR_SANCTUARY: case NPC_EVILLAND: break; default: - { - struct status_data *status = status_get_status_data(src); - int min, max; - - min = max = status_base_matk(status, status_get_lv(src)); - if( status->rhw.matk > 0 ){ - int wMatk, variance; - wMatk = status->rhw.matk; - variance = wMatk * status->rhw.wlv / 10; - min += wMatk - variance; - max += wMatk + variance; - } - - if( sc && sc->data[SC_RECOGNIZEDSPELL] ) - min = max; - - if( sd && sd->right_weapon.overrefine > 0 ){ - min++; - max += sd->right_weapon.overrefine - 1; - } - - if(max > min) - hp += min+rnd()%(max-min); - else - hp += min; - } + hp += status_get_matk(src, 3); } #endif return hp; @@ -557,7 +534,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case RETURN_TO_ELDICASTES: case ALL_GUARDIAN_RECALL: if(map[m].flag.nowarp) { - clif->skill_teleportmessage(sd,0); + clif->skill_mapinfomessage(sd,0); return 1; } return 0; @@ -565,7 +542,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case SC_FATALMENACE: case SC_DIMENSIONDOOR: if(map[m].flag.noteleport) { - clif->skill_teleportmessage(sd,0); + clif->skill_mapinfomessage(sd,0); return 1; } return 0; // gonna be checked in 'skill->castend_nodamage_id' @@ -573,7 +550,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case WE_CALLPARENT: case WE_CALLBABY: if (map[m].flag.nomemo) { - clif->skill_teleportmessage(sd,1); + clif->skill_mapinfomessage(sd,1); return 1; } break; @@ -625,7 +602,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) * These skills cannot be used while in mado gear (credits to Xantara) **/ if( pc_ismadogear(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR_RIDE,0); return 1; } break; @@ -636,7 +613,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case WM_LULLABY_DEEPSLEEP: case WM_SATURDAY_NIGHT_FEVER: if( !map_flag_vs(m) ) { - clif->skill_teleportmessage(sd,2); // This skill uses this msg instead of skill fails. + clif->skill_mapinfomessage(sd,2); // This skill uses this msg instead of skill fails. return 1; } break; @@ -815,12 +792,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if(sd) { // Automatic trigger of Blitz Beat if (pc_isfalcon(sd) && sd->status.weapon == W_BOW && (temp=pc->checkskill(sd,HT_BLITZBEAT))>0 && - rnd()%1000 <= sstatus->luk*10/3+1 ) { - rate=(sd->status.job_level+9)/10; + rnd()%1000 <= sstatus->luk*3 ) { + rate = sd->status.job_level / 10 + 1; skill->castend_damage_id(src,bl,HT_BLITZBEAT,(tempstatus.weapon == W_BOW || sd->status.weapon == W_FIST) && (temp=pc->checkskill(sd,RA_WUGSTRIKE)) > 0 && rnd()%1000 <= sstatus->luk*10/3+1 ) + if( pc_iswug(sd) && (temp=pc->checkskill(sd,RA_WUGSTRIKE)) > 0 && rnd()%1000 <= sstatus->luk*3 ) skill->castend_damage_id(src,bl,RA_WUGSTRIKE,temp,tick,0); // Gank if(dstmd && sd->status.weapon != W_BOW && @@ -832,26 +809,26 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint clif->skill_fail(sd,RG_SNATCHER,USESKILL_FAIL_LEVEL,0); } // Chance to trigger Taekwon kicks [Dralnu] - if(sc && !sc->data[SC_COMBO]) { - if(sc->data[SC_READYSTORM] && - sc_start(src,SC_COMBO, 15, TK_STORMKICK, + if(sc && !sc->data[SC_COMBOATTACK]) { + if(sc->data[SC_STORMKICK_READY] && + sc_start(src,SC_COMBOATTACK, 15, TK_STORMKICK, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered - else if(sc->data[SC_READYDOWN] && - sc_start(src,SC_COMBO, 15, TK_DOWNKICK, + else if(sc->data[SC_DOWNKICK_READY] && + sc_start(src,SC_COMBOATTACK, 15, TK_DOWNKICK, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered - else if(sc->data[SC_READYTURN] && - sc_start(src,SC_COMBO, 15, TK_TURNKICK, + else if(sc->data[SC_TURNKICK_READY] && + sc_start(src,SC_COMBOATTACK, 15, TK_TURNKICK, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered - else if (sc->data[SC_READYCOUNTER]) { //additional chance from SG_FRIEND [Komurka] + else if (sc->data[SC_COUNTERKICK_READY]) { //additional chance from SG_FRIEND [Komurka] rate = 20; if (sc->data[SC_SKILLRATE_UP] && sc->data[SC_SKILLRATE_UP]->val1 == TK_COUNTER) { rate += rate*sc->data[SC_SKILLRATE_UP]->val2/100; status_change_end(src, SC_SKILLRATE_UP, INVALID_TIMER); } - sc_start2(src, SC_COMBO, rate, TK_COUNTER, bl->id, + sc_start2(src, SC_COMBOATTACK, rate, TK_COUNTER, bl->id, (2000 - 4*sstatus->agi - 2*sstatus->dex)); } } @@ -862,7 +839,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if (sc) { struct status_change_entry *sce; // Enchant Poison gives a chance to poison attacked enemies - if((sce=sc->data[SC_ENCPOISON])) //Don't use sc_start since chance comes in 1/10000 rate. + if((sce=sc->data[SC_ENCHANTPOISON])) //Don't use sc_start since chance comes in 1/10000 rate. status_change_start(bl,SC_POISON,sce->val2, sce->val1,src->id,0,0, skill->get_time2(AS_ENCHANTPOISON,sce->val1),0); // Enchant Deadly Poison gives a chance to deadly poison attacked enemies @@ -871,7 +848,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint skill->get_time2(ASC_EDP,sce->val1)); } } - break; + break; case SM_BASH: if( sd && skill_lv > 5 && pc->checkskill(sd,SM_FATALBLOW)>0 ){ @@ -990,7 +967,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case AM_ACIDTERROR: - sc_start2(bl,SC_BLEEDING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); if (skill->break_equip(bl, EQP_ARMOR, 100*skill->get_time(skill_id,skill_lv), BCT_ENEMY)) clif->emotion(bl,E_OMG); break; @@ -1062,14 +1039,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint sc_start(bl,status_skill2sc(skill_id),70,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_BLEEDING: - sc_start2(bl,SC_BLEEDING,(20*skill_lv),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(bl,SC_BLOODING,(20*skill_lv),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); break; case NPC_MENTALBREAKER: { //Based on observations by Tharis, Mental Breaker should do SP damage - //equal to Matk*skLevel. - rate = sstatus->matk_min; - if (rate < sstatus->matk_max) - rate += rnd()%(sstatus->matk_max - sstatus->matk_min); + //equal to Matk*skLevel. + rate = status_get_matk(src, 2); rate*=skill_lv; status_zap(bl, 0, rate); break; @@ -1108,7 +1083,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case LK_HEADCRUSH: //Headcrush has chance of causing Bleeding status, except on demon and undead element if (!(battle->check_undead(tstatus->race, tstatus->def_ele) || tstatus->race == RC_DEMON)) - sc_start2(bl, SC_BLEEDING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv)); + sc_start2(bl, SC_BLOODING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv)); break; case LK_JOINTBEAT: @@ -1128,8 +1103,8 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint sc_start(bl,SC_STUN,(5+skill_lv*5),skill_lv,skill->get_time2(skill_id,2)); break; default: - sc_start2(bl,SC_BLEEDING,(5+skill_lv*5),skill_lv,src->id,skill->get_time2(skill_id,3)); - } + sc_start2(bl,SC_BLOODING,(5+skill_lv*5),skill_lv,src->id,skill->get_time2(skill_id,3)); + } break; case HW_NAPALMVULCAN: @@ -1151,12 +1126,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case TK_JUMPKICK: if( dstsd && dstsd->class_ != MAPID_SOUL_LINKER && !tsc->data[SC_PRESERVE] ) {// debuff the following statuses - status_change_end(bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); status_change_end(bl, SC_KAITE, INVALID_TIMER); status_change_end(bl, SC_KAAHI, INVALID_TIMER); - status_change_end(bl, SC_ONEHAND, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION2, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); } break; case TK_TURNKICK: @@ -1169,7 +1144,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint status_change_start(bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); break; case GS_PIERCINGSHOT: - sc_start2(bl,SC_BLEEDING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); break; case NJ_HYOUSYOURAKU: sc_start(bl,SC_FREEZE,(10+10*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); @@ -1204,34 +1179,37 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint sc_start(bl,SC_FEAR,3+2*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; case RK_DRAGONBREATH: - sc_start4(bl,SC_BURNING,5+5*skill_lv,skill_lv,1000,src->id,0,skill->get_time(skill_id,skill_lv)); + sc_start4(bl,SC_BURNING,5+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); + break; + case RK_DRAGONBREATH_WATER: + sc_start4(bl,SC_FROSTMISTY,5+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); break; case AB_ADORAMUS: - if( tsc && !tsc->data[SC_DECREASEAGI] ) //Prevent duplicate agi-down effect. + if( tsc && !tsc->data[SC_DEC_AGI] ) //Prevent duplicate agi-down effect. sc_start(bl, SC_ADORAMUS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; case WL_CRIMSONROCK: sc_start(bl, SC_STUN, 40, skill_lv, skill->get_time(skill_id, skill_lv)); break; case WL_COMET: - sc_start4(bl,SC_BURNING,100,skill_lv,1000,src->id,0,skill->get_time(skill_id,skill_lv)); + sc_start4(bl,SC_BURNING,100,skill_lv,0,src->id,0,skill->get_time2(skill_id,skill_lv)); break; case WL_EARTHSTRAIN: { - int rate = 0, i; - const int pos[5] = { EQP_WEAPON, EQP_HELM, EQP_SHIELD, EQP_ARMOR, EQP_ACC }; - rate = 6 * skill_lv + sstatus->dex / 10 + (sd? sd->status.job_level / 4 : 0) - tstatus->dex /5;// The tstatus->dex / 5 part is unofficial, but players gotta have some kind of way to have resistance. [Rytech] - //rate -= rate * tstatus->dex / 200; // Disabled until official resistance is found. - - for( i = 0; i < skill_lv; i++ ) - skill->strip_equip(bl,pos[i],rate,skill_lv,skill->get_time2(skill_id,skill_lv)); + // lv 1 & 2 = Strip Helm, lv 3 = Strip Armor, lv 4 = Strip Weapon and lv 5 = Strip Accessory. [malufett] + const int pos[5] = { EQP_HELM, EQP_HELM, EQP_ARMOR, EQP_WEAPON, EQP_ACC }; + skill->strip_equip(bl, pos[skill_lv], 6 * skill_lv + status_get_lv(src) / 4 + status_get_dex(src) / 10, + skill_lv, skill->get_time2(skill_id,skill_lv)); } break; case WL_JACKFROST: sc_start(bl,SC_FREEZE,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; + case WL_FROSTMISTY: + sc_start(bl,SC_FROSTMISTY,25 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + break; case RA_WUGBITE: - sc_start(bl, SC_BITE, (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*2 : 0), skill_lv, (skill->get_time(skill_id,skill_lv) + (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*500 : 0)) ); + sc_start(bl, SC_WUGBITE, (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*2 : 0), skill_lv, (skill->get_time(skill_id,skill_lv) + (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*500 : 0)) ); break; case RA_SENSITIVEKEEN: if( rnd()%100 < 8 * skill_lv ) @@ -1239,7 +1217,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - sc_start(bl, (skill_id == RA_FIRINGTRAP) ? SC_BURNING:SC_FREEZING, 40 + 10 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); + sc_start4(bl, (skill_id == RA_FIRINGTRAP) ? SC_BURNING:SC_FROSTMISTY, 40 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); break; case NC_PILEBUNKER: if( rnd()%100 < 5 + 15*skill_lv ) @@ -1252,20 +1230,27 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint } break; case NC_FLAMELAUNCHER: - sc_start4(bl, SC_BURNING, 50 + 10 * skill_lv, skill_lv, 1000, src->id, 0, skill->get_time2(skill_id, skill_lv)); + sc_start4(bl, SC_BURNING, 50 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); break; case NC_COLDSLOWER: sc_start(bl, SC_FREEZE, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); - sc_start(bl, SC_FREEZING, 20 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(bl, SC_FROSTMISTY, 20 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case NC_POWERSWING: sc_start(bl, SC_STUN, 5*skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); if( rnd()%100 < 5*skill_lv ) skill->castend_damage_id(src, bl, NC_AXEBOOMERANG, pc->checkskill(sd, NC_AXEBOOMERANG), tick, 1); break; + case NC_MAGMA_ERUPTION: + sc_start4(bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); + sc_start(bl, SC_STUN, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + break; case GC_WEAPONCRUSH: skill->castend_nodamage_id(src,bl,skill_id,skill_lv,tick,BCT_ENEMY); break; + case GC_DARKCROW: + sc_start(bl, SC_DARKCROW, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + break; case LG_SHIELDPRESS: sc_start(bl, SC_STUN, 30 + 8 * skill_lv, skill_lv, skill->get_time(skill_id,skill_lv)); break; @@ -1273,7 +1258,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint rate = 30 + (((5 * (sd?pc->checkskill(sd,LG_PINPOINTATTACK):skill_lv)) + (sstatus->agi + status_get_lv(src))) / 10); switch( skill_lv ) { case 1: - sc_start2(bl,SC_BLEEDING,rate,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); + sc_start2(bl,SC_BLOODING,rate,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); break; case 2: if( dstsd && dstsd->spiritball && rnd()%100 < rate ) @@ -1335,25 +1320,25 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint status_change_end(bl, SC_APPLEIDUN, INVALID_TIMER); status_change_end(bl, SC_HUMMING, INVALID_TIMER); status_change_end(bl, SC_FORTUNE, INVALID_TIMER); - status_change_end(bl, SC_SERVICE4U, INVALID_TIMER); + status_change_end(bl, SC_SERVICEFORYOU, INVALID_TIMER); status_change_end(bl, SC_LONGING, INVALID_TIMER); - status_change_end(bl, SC_SWINGDANCE, INVALID_TIMER); - status_change_end(bl, SC_SYMPHONYOFLOVER, INVALID_TIMER); - status_change_end(bl, SC_MOONLITSERENADE, INVALID_TIMER); - status_change_end(bl, SC_RUSHWINDMILL, INVALID_TIMER); + status_change_end(bl, SC_SWING, INVALID_TIMER); + status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - status_change_end(bl, SC_WINKCHARM, INVALID_TIMER); - status_change_end(bl, SC_SONGOFMANA, INVALID_TIMER); - status_change_end(bl, SC_DANCEWITHWUG, INVALID_TIMER); - status_change_end(bl, SC_LERADSDEW, INVALID_TIMER); + status_change_end(bl, SC_DC_WINKCHARM, INVALID_TIMER); + status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - status_change_end(bl, SC_BEYONDOFWARCRY, INVALID_TIMER); - status_change_end(bl, SC_UNLIMITEDHUMMINGVOICE, INVALID_TIMER); + status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); } break; case SO_EARTHGRAVE: - sc_start2(bl, SC_BLEEDING, 5 * skill_lv, skill_lv, src->id, skill->get_time2(skill_id, skill_lv)); // Need official rate. [LimitLine] + sc_start2(bl, SC_BLOODING, 5 * skill_lv, skill_lv, src->id, skill->get_time2(skill_id, skill_lv)); // Need official rate. [LimitLine] break; case SO_DIAMONDDUST: rate = 5 + 5 * skill_lv; @@ -1369,14 +1354,14 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint switch( sd->itemid ) { // Starting SCs here instead of do it in skill->additional_effect to simplify the code. case 13261: sc_start(bl, SC_STUN, 100, skill_lv, skill->get_time2(GN_SLINGITEM, skill_lv)); - sc_start2(bl, SC_BLEEDING, 100, skill_lv, src->id, skill->get_time2(GN_SLINGITEM, skill_lv)); + sc_start2(bl, SC_BLOODING, 100, skill_lv, src->id, skill->get_time2(GN_SLINGITEM, skill_lv)); break; case 13262: sc_start(bl, SC_MELON_BOMB, 100, skill_lv, skill->get_time(GN_SLINGITEM, skill_lv)); // Reduces ASPD and moviment speed break; case 13264: sc_start(bl, SC_BANANA_BOMB, 100, skill_lv, skill->get_time(GN_SLINGITEM, skill_lv)); // Reduces LUK ??Needed confirm it, may be it's bugged in kRORE? - sc_start(bl, SC_BANANA_BOMB_SITDOWN, 75, skill_lv, skill->get_time(GN_SLINGITEM_RANGEMELEEATK,skill_lv)); // Sitdown for 3 seconds. + sc_start(bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, 75, skill_lv, skill->get_time(GN_SLINGITEM_RANGEMELEEATK,skill_lv)); // Sitdown for 3 seconds. break; } sd->itemid = -1; @@ -1384,10 +1369,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case GN_HELLS_PLANT_ATK: sc_start(bl, SC_STUN, 5 + 5 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); - sc_start2(bl, SC_BLEEDING, 20 + 10 * skill_lv, skill_lv, src->id,skill->get_time2(skill_id, skill_lv)); + sc_start2(bl, SC_BLOODING, 20 + 10 * skill_lv, skill_lv, src->id,skill->get_time2(skill_id, skill_lv)); break; case EL_WIND_SLASH: // Non confirmed rate. - sc_start2(bl, SC_BLEEDING, 25, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); + sc_start2(bl, SC_BLOODING, 25, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); break; case EL_STONE_HAMMER: rate = 10 * skill_lv; @@ -1400,20 +1385,20 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case EL_TYPOON_MIS: sc_start(bl,SC_SILENCE,10*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; - case KO_JYUMONJIKIRI: // needs more info - sc_start(bl,SC_JYUMONJIKIRI,25,skill_lv,skill->get_time(skill_id,skill_lv)); + case KO_JYUMONJIKIRI: + sc_start(bl,SC_KO_JYUMONJIKIRI,90,skill_lv,skill->get_time(skill_id,skill_lv)); break; case KO_MAKIBISHI: - sc_start(bl, SC_STUN, 100, skill_lv, skill->get_time2(skill_id,skill_lv)); + sc_start(bl, SC_STUN, 10 * skill_lv, skill_lv, 1000 * (skill_lv / 2 + 2)); break; case MH_LAVA_SLIDE: - if (tsc && !tsc->data[SC_BURNING]) sc_start4(bl, SC_BURNING, 10 * skill_lv, skill_lv, 1000, src->id, 0, skill->get_time(skill_id, skill_lv)); + if (tsc && !tsc->data[SC_BURNING]) sc_start4(bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time(skill_id, skill_lv)); break; case MH_STAHL_HORN: sc_start(bl, SC_STUN, (20 + 4 * (skill_lv-1)), skill_lv, skill->get_time(skill_id, skill_lv)); break; case MH_NEEDLE_OF_PARALYZE: - sc_start(bl, SC_PARALYSIS, 40 + (5*skill_lv), skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(bl, SC_NEEDLE_OF_PARALYZE, 40 + (5*skill_lv), skill_lv, skill->get_time(skill_id, skill_lv)); break; } @@ -1442,7 +1427,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint rate += 10; if(sc->data[SC_OVERTHRUST]) rate += 10; - if(sc->data[SC_MAXOVERTHRUST]) + if(sc->data[SC_OVERTHRUSTMAX]) rate += 10; } if( rate ) @@ -1492,7 +1477,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers ) - clif->status_change(src, SI_ACTIONDELAY, 1, rate, 0, 0, 0); + clif->status_change(src, SI_POSTDELAY, 1, rate, 0, 0, 0); } } } @@ -1589,7 +1574,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && sd ) - clif->status_change(src, SI_ACTIONDELAY, 1, rate, 0, 0, 0); + clif->status_change(src, SI_POSTDELAY, 1, rate, 0, 0, 0); } } } @@ -1828,10 +1813,10 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if( skill_id == WZ_WATERBALL ) {//(bugreport:5303) struct status_change *sc = NULL; if( ( sc = status_get_sc(src) ) ) { - if(sc->data[SC_SPIRIT] && - sc->data[SC_SPIRIT]->val2 == SL_WIZARD && - sc->data[SC_SPIRIT]->val3 == WZ_WATERBALL) - sc->data[SC_SPIRIT]->val3 = 0; //Clear bounced spell check. + if(sc->data[SC_SOULLINK] && + sc->data[SC_SOULLINK]->val2 == SL_WIZARD && + sc->data[SC_SOULLINK]->val3 == WZ_WATERBALL) + sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. } } } @@ -1925,7 +1910,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && dstsd ) - clif->status_change(bl, SI_ACTIONDELAY, 1, rate, 0, 0, 0); + clif->status_change(bl, SI_POSTDELAY, 1, rate, 0, 0, 0); } } } @@ -1957,8 +1942,8 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * --------------------------------------------------------------------------*/ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, int flag) { const int where_list[4] = {EQP_WEAPON, EQP_ARMOR, EQP_SHIELD, EQP_HELM}; - const enum sc_type scatk[4] = {SC_STRIPWEAPON, SC_STRIPARMOR, SC_STRIPSHIELD, SC_STRIPHELM}; - const enum sc_type scdef[4] = {SC_CP_WEAPON, SC_CP_ARMOR, SC_CP_SHIELD, SC_CP_HELM}; + const enum sc_type scatk[4] = {SC_NOEQUIPWEAPON, SC_NOEQUIPARMOR, SC_NOEQUIPSHIELD, SC_NOEQUIPHELM}; + const enum sc_type scdef[4] = {SC_PROTECTWEAPON, SC_PROTECTARMOR, SC_PROTECTSHIELD, SC_PROTECTHELM}; struct status_change *sc = status_get_sc(bl); int i,j; TBL_PC *sd; @@ -2048,8 +2033,8 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time) { struct status_change *sc; const int pos[5] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC}; - const enum sc_type sc_atk[5] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC__STRIPACCESSORY}; - const enum sc_type sc_def[5] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM, 0}; + const enum sc_type sc_atk[5] = {SC_NOEQUIPWEAPON, SC_NOEQUIPSHIELD, SC_NOEQUIPARMOR, SC_NOEQUIPHELM, SC__STRIPACCESSARY}; + const enum sc_type sc_def[5] = {SC_PROTECTWEAPON, SC_PROTECTSHIELD, SC_PROTECTARMOR, SC_PROTECTHELM, 0}; int i; if (rnd()%100 >= rate) @@ -2182,7 +2167,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds struct status_data *sstatus, *tstatus; struct status_change *sc; struct map_session_data *sd, *tsd; - int type,damage,rdamage=0; + int type,damage; int8 rmdamage=0;//magic reflected bool additional_effects = true; @@ -2253,15 +2238,15 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds flag |= 2; //Spirit of Wizard blocks Kaite's reflection - if( type == 2 && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD ) + if( type == 2 && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD ) { //Consume one Fragment per hit of the casted skill? [Skotlex] type = tsd?pc->search_inventory (tsd, 7321):0; if (type >= 0) { if ( tsd ) pc->delitem(tsd, type, 1, 0, 1, LOG_TYPE_CONSUME); dmg.damage = dmg.damage2 = 0; dmg.dmg_lv = ATK_MISS; - sc->data[SC_SPIRIT]->val3 = skill_id; - sc->data[SC_SPIRIT]->val4 = dsrc->id; + sc->data[SC_SOULLINK]->val3 = skill_id; + sc->data[SC_SOULLINK]->val4 = dsrc->id; } } else if( type != 2 ) /* Kaite bypasses */ additional_effects = false; @@ -2311,19 +2296,15 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( (skill_id == AL_INCAGI || skill_id == AL_BLESSING || skill_id == CASH_BLESSING || skill_id == CASH_INCAGI || - skill_id == MER_INCAGI || skill_id == MER_BLESSING) && tsd->sc.data[SC_CHANGEUNDEAD] ) + skill_id == MER_INCAGI || skill_id == MER_BLESSING) && tsd->sc.data[SC_PROPERTYUNDEAD] ) damage = 1; - if( damage > 0 && (( dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skill_id == SG_SUN_WARM || skill_id == SG_MOON_WARM || skill_id == SG_STAR_WARM ) ) )) - || (sc && sc->data[SC_REFLECTDAMAGE])) ) - rdamage = battle->calc_return_damage(bl,src, &damage, dmg.flag, skill_id); - if( damage && sc && sc->data[SC_GENSOU] && dmg.flag&BF_MAGIC ){ struct block_list *nbl; nbl = battle->get_enemy_area(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), dmg.div_, OB_OBOROGENSOU_TRANSITION_ATK, -1, 6); + int temp = (int)(damage / (float)(10 / skill_lv)); + clif->skill_damage(bl, nbl, tick, status_get_amotion(src), 0, status_fix_damage(bl,nbl,temp,0), 1, OB_OBOROGENSOU_TRANSITION_ATK, -1, 6); } } @@ -2348,7 +2329,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if(sd) { int flag = 0; //Used to signal if this skill can be combo'ed later on. struct status_change_entry *sce; - if ((sce = sd->sc.data[SC_COMBO])) {//End combo state after skill is invoked. [Skotlex] + if ((sce = sd->sc.data[SC_COMBOATTACK])) {//End combo state after skill is invoked. [Skotlex] switch (skill_id) { case TK_TURNKICK: case TK_STORMKICK: @@ -2359,14 +2340,14 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds sce->val3 = skill_id; if( sce->timer != INVALID_TIMER ) iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(tick+sce->val4, status_change_timer, src->id, SC_COMBO); + sce->timer = iTimer->add_timer(tick+sce->val4, status_change_timer, src->id, SC_COMBOATTACK); break; } unit_cancel_combo(src); // Cancel combo wait break; default: if( src == dsrc ) // Ground skills are exceptions. [Inkfish] - status_change_end(src, SC_COMBO, INVALID_TIMER); + status_change_end(src, SC_COMBOATTACK, INVALID_TIMER); } } switch(skill_id) { @@ -2394,7 +2375,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( (tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) && pc->checkskill(sd, HT_POWER)) { //TODO: This code was taken from Triple Blows, is this even how it should be? [Skotlex] - sc_start2(src,SC_COMBO,100,HT_POWER,bl->id,2000); + sc_start2(src,SC_COMBOATTACK,100,HT_POWER,bl->id,2000); clif->combo_delay(src,2000); } break; @@ -2407,8 +2388,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; case SL_STIN: case SL_STUN: - if (skill_lv >= 7 && !sd->sc.data[SC_SMA]) - sc_start(src,SC_SMA,100,skill_lv,skill->get_time(SL_SMA, skill_lv)); + if (skill_lv >= 7 && !sd->sc.data[SC_SMA_READY]) + sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA, skill_lv)); break; case GS_FULLBUSTER: //Can't attack nor use items until skill's delay expires. [Skotlex] @@ -2425,7 +2406,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } //Switch End if (flag) { //Possible to chain if ( (flag = DIFF_TICK(sd->ud.canact_tick, tick)) < 50 ) flag = 50;/* less is a waste. */ - sc_start2(src,SC_COMBO,100,skill_id,bl->id,flag); + sc_start2(src,SC_COMBOATTACK,100,skill_id,bl->id,flag); clif->combo_delay(src, flag); } } @@ -2459,9 +2440,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case SR_EARTHSHAKER: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skill_id,-2,6); break; + case KO_MUCHANAGE: + if( dmg.dmg_lv == ATK_FLEE ) + break; case WL_SOULEXPANSION: case WL_COMET: - case KO_MUCHANAGE: case NJ_HUUMA: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,skill_lv,8); break; @@ -2488,6 +2471,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case EL_HURRICANE_ATK: case KO_BAKURETSU: case GN_CRAZYWEED_ATK: + case NC_MAGMA_ERUPTION: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,5); break; case GN_SLINGITEM_RANGEMELEEATK: @@ -2503,6 +2487,12 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case WM_REVERBERATION_MAGIC: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,WM_REVERBERATION,-2,6); break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_, WL_TETRAVORTEX,-1,5); + break; case HT_CLAYMORETRAP: case HT_BLASTMINE: case HT_FLASHER: @@ -2518,7 +2508,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; case WZ_SIGHTBLASTER: dmg.dmotion = clif->skill_damage(src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skill_id, flag&SD_LEVEL?-1:skill_lv, 5); - break; + break; case AB_DUPLELIGHT_MELEE: case AB_DUPLELIGHT_MAGIC: dmg.amotion = 300;/* makes the damage value not overlap with previous damage (when displayed by the client) */ @@ -2643,8 +2633,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds skill->counter_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,tick); } // Hell Inferno burning status only starts if Fire part hits. - if( skill_id == WL_HELLINFERNO && dmg.damage > 0 ) - sc_start4(bl,SC_BURNING,55+5*skill_lv,skill_lv,1000,src->id,0,skill->get_time(skill_id,skill_lv)); + if( skill_id == WL_HELLINFERNO && dmg.damage > 0 && !(flag&ELE_DARK) ) + sc_start4(bl,SC_BURNING,55+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); // Apply knock back chance in SC_TRIANGLESHOT skill. else if( skill_id == SC_TRIANGLESHOT && rnd()%100 > (1 + skill_lv) ) dmg.blewcount = 0; @@ -2753,7 +2743,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds dmg.flag |= BF_WEAPON; if( sd && src != bl && damage > 0 && ( dmg.flag&BF_WEAPON || - (dmg.flag&BF_MISC && (skill_id == RA_CLUSTERBOMB || skill_id == RA_FIRINGTRAP || skill_id == RA_ICEBOUNDTRAP || skill_id == RK_DRAGONBREATH)) ) ) + (dmg.flag&BF_MISC && (skill_id == RA_CLUSTERBOMB || skill_id == RA_FIRINGTRAP || skill_id == RA_ICEBOUNDTRAP || skill_id == RK_DRAGONBREATH || skill_id == RK_DRAGONBREATH_WATER)) ) ) { if (battle_config.left_cardfix_to_right) battle->drain(sd, bl, dmg.damage, dmg.damage, tstatus->race, tstatus->mode&MD_BOSS); @@ -2761,30 +2751,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds battle->drain(sd, bl, dmg.damage, dmg.damage2, tstatus->race, tstatus->mode&MD_BOSS); } - if( rdamage > 0 ) { - if( sc && sc->data[SC_REFLECTDAMAGE] ) { - if( src != bl ) {// Don't reflect your own damage (Grand Cross) - bool change = false; - if( sd && !sd->state.autocast ) - change = true; - if( change ) - sd->state.autocast = 1; - iMap->foreachinshootrange(battle->damage_area,bl,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,bl,dmg.amotion,sstatus->dmotion,rdamage,tstatus->race); - if( change ) - sd->state.autocast = 0; - } - } else { - if( dmg.amotion ) - battle->delay_damage(tick, dmg.amotion,bl,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,0,additional_effects); - else - status_fix_damage(bl,src,rdamage,0); - clif->damage(src,src,tick, dmg.amotion,0,rdamage,1,4,0); // in aegis damage reflected is shown in single hit. - //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] - if( tsd && src != bl ) - battle->drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); - skill->additional_effect(bl, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); - } - } + if( damage > 0 ) { /** * Post-damage effects @@ -2818,8 +2785,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds skill_id == MG_COLDBOLT || skill_id == MG_FIREBOLT || skill_id == MG_LIGHTNINGBOLT ) && (sc = status_get_sc(src)) && - sc->data[SC_DOUBLECAST] && - rnd() % 100 < sc->data[SC_DOUBLECAST]->val2) + sc->data[SC_DOUBLECASTING] && + rnd() % 100 < sc->data[SC_DOUBLECASTING]->val2) { // skill->addtimerskill(src, tick + dmg.div_*dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag|2); skill->addtimerskill(src, tick + dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag|2); @@ -3101,7 +3068,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, index[i] = pc->search_inventory(sd, itemid[i]); if( index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i] ) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i]|(itemid[i] << 16)); return 0; } } @@ -3193,10 +3160,10 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { } else { struct status_change *sc = status_get_sc(src); if(sc) { - if(sc->data[SC_SPIRIT] && - sc->data[SC_SPIRIT]->val2 == SL_WIZARD && - sc->data[SC_SPIRIT]->val3 == skl->skill_id) - sc->data[SC_SPIRIT]->val3 = 0; //Clear bounced spell check. + if(sc->data[SC_SOULLINK] && + sc->data[SC_SOULLINK]->val2 == SL_WIZARD && + sc->data[SC_SOULLINK]->val3 == skl->skill_id) + sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. } } break; @@ -3205,48 +3172,33 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { **/ case WL_CHAINLIGHTNING_ATK: { struct block_list *nbl = NULL; // Next Target of Chain - skill->attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); // Hit a Lightning on the current Target + skill->attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, (9-skl->type)); // Hit a Lightning on the current Target skill->toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify - if( skl->type > 1 ) { // Remaining Chains Hit - nbl = battle->get_enemy_area(src,target->x,target->y,2,BL_CHAR|BL_SKILL,target->id); // Search for a new Target around current one... - if( nbl == NULL && skl->x > 1 ) { - nbl = target; - skl->x--; - } else - skl->x = 3; + + if( skl->type < (4 + skl->skill_lv - 1) && skl->x < 3 ) + { // Remaining Chains Hit + nbl = battle->get_enemy_area(src, target->x, target->y, (skl->type>2)?2:3, // After 2 bounces, it will bounce to other targets in 7x7 range. + BL_CHAR|BL_SKILL, target->id); // Search for a new Target around current one... + if( nbl == NULL) + skl->x++; + else + skl->x = 0; + + skill->addtimerskill(src, tick + 651, (nbl?nbl:target)->id, skl->x, 0, WL_CHAINLIGHTNING_ATK, skl->skill_lv, skl->type + 1, skl->flag); } - - if( nbl ) - skill->addtimerskill(src,tick+status_get_adelay(src),nbl->id,skl->x,0,WL_CHAINLIGHTNING_ATK,skl->skill_lv,skl->type-1,skl->flag); } break; case WL_TETRAVORTEX_FIRE: case WL_TETRAVORTEX_WATER: case WL_TETRAVORTEX_WIND: case WL_TETRAVORTEX_GROUND: - skill->attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag|SD_ANIMATION); + clif->skill_nodamage(src, target, skl->skill_id, skl->skill_lv, 1); + skill_attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag); skill->toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify - if( skl->type >= 3 ) { // Final Hit - if( !status_isdead(target) ) { // Final Status Effect - int effects[4] = { SC_BURNING, SC_FREEZING, SC_BLEEDING, SC_STUN }, - applyeffects[4] = { 0, 0, 0, 0 }, - i, j = 0, k = 0; - for( i = 1; i <= 8; i = i + i ) { - if( skl->x&i ) - { - applyeffects[j] = effects[k]; - j++; - } - k++; - } - if( j ) { - i = applyeffects[rnd()%j]; - status_change_start(target, i, 10000, skl->skill_lv, - (i == SC_BURNING ? 1000 : (i == SC_BLEEDING ? src->id : 0)), - (i == SC_BURNING ? src->id : 0), - 0, skill->get_time(WL_TETRAVORTEX,skl->skill_lv), 0); - } - } + if( skl->type == 4 ){ + const enum sc_type scs[] = { SC_BURNING, SC_BLOODING, SC_FROSTMISTY, SC_STUN }; // status inflicts are depend on what summoned element is used. + int rate = skl->y, index = skl->x-1; + sc_start2(target, scs[index], rate, skl->skill_lv, src->id, skill->get_time(WL_TETRAVORTEX,index)); } break; case WM_REVERBERATION_MELEE: @@ -3282,6 +3234,19 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { iMap->foreachinrange(skill->area_sub, target, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, src, skl->skill_id, skl->skill_lv, 0, skl->flag|1|BCT_ENEMY, skill->castend_damage_id); break; + case SR_FLASHCOMBO_ATK_STEP1: + case SR_FLASHCOMBO_ATK_STEP2: + case SR_FLASHCOMBO_ATK_STEP3: + case SR_FLASHCOMBO_ATK_STEP4: + if( src->type == BL_PC ) { + struct map_session_data *sd = NULL; + const enum e_skill combos[] = {SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW}; + if( (sd = ((TBL_PC*)src)) ){ + uint16 cid = combos[skl->skill_id-SR_FLASHCOMBO_ATK_STEP1]; + skill->castend_damage_id(src, target, cid, pc->checkskill(sd, cid), tick, 0); + } + } + break; case CH_PALMSTRIKE: { struct status_change* tsc = status_get_sc(target); @@ -3525,7 +3490,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case GS_FULLBUSTER: case NJ_SYURIKEN: case NJ_KUNAI: +#ifndef RENEWAL case ASC_BREAKER: +#endif case HFLI_MOON: //[orn] case HFLI_SBR44: //[orn] case NPC_BLEEDING: @@ -3533,6 +3500,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_HELLPOWER: case RK_SONICWAVE: case RK_HUNDREDSPEAR: + case RK_STORMBLAST: + case RK_CRUSHSTRIKE: case AB_DUPLELIGHT_MELEE: case RA_AIMEDBOLT: case NC_AXEBOOMERANG: @@ -3555,7 +3524,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case GN_SLINGITEM_RANGEMELEEATK: case KO_JYUMONJIKIRI: case KO_SETSUDAN: - case KO_KAIHOU: + case GC_DARKCROW: skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; @@ -3588,7 +3557,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case MO_COMBOFINISH: - if (!(flag&1) && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_MONK) + if (!(flag&1) && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_MONK) { //Becomes a splash attack when Soul Linked. iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv),splash_target(src), @@ -3687,9 +3656,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case NJ_ISSEN: - status_change_end(src, SC_NEN, INVALID_TIMER); - status_change_end(src, SC_HIDING, INVALID_TIMER); - // fall through case MO_EXTREMITYFIST: { short x, y, i = 2; // Move 2 cells for Issen(from target) @@ -3708,7 +3674,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint #ifdef RENEWAL sc_start(src,SC_EXTREMITYFIST2,100,skill_lv,skill->get_time(skill_id,skill_lv)); #endif - }else + }else{ + status_change_end(src, SC_NJ_NEN, INVALID_TIMER); + status_change_end(src, SC_HIDING, INVALID_TIMER); status_set_hp(src, #ifdef RENEWAL max(status_get_max_hp(src)/100, 1) @@ -3716,7 +3684,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint 1 #endif , 0); - + } dir = iMap->calc_dir(src,bl->x,bl->y); if( dir > 0 && dir < 4) x = -i; else if( dir > 4 ) x = i; @@ -3945,6 +3913,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case AB_DUPLELIGHT_MAGIC: case WM_METALICSOUND: case MH_ERASER_CUTTER: + case KO_KAIHOU: skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); break; @@ -4011,7 +3980,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case SL_SMA: - status_change_end(src, SC_SMA, INVALID_TIMER); + status_change_end(src, SC_SMA_READY, INVALID_TIMER); case SL_STIN: case SL_STUN: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { @@ -4033,11 +4002,15 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NJ_ZENYNAGE: case GN_THORNS_TRAP: case GN_HELLS_PLANT_ATK: +#ifdef RENEWAL + case ASC_BREAKER: +#endif skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); break; /** * Rune Knight **/ + case RK_DRAGONBREATH_WATER: case RK_DRAGONBREATH: { struct status_change *tsc = NULL; if( (tsc = status_get_sc(bl)) && (tsc->data[SC_HIDING] )) { @@ -4112,16 +4085,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; - case RK_STORMBLAST: - case RK_CRUSHSTRIKE: - if( sd ) { - if( pc->checkskill(sd,RK_RUNEMASTERY) >= ( skill_id == RK_CRUSHSTRIKE ? 7 : 3 ) ) - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - } else //non-sd support - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - break; case GC_DARKILLUSION: { short x, y; @@ -4145,9 +4108,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } break; - case GC_WEAPONCRUSH: - if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING ) + if( sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == GC_WEAPONBLOCKING ) skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_GC_WEAPONBLOCKING,0); @@ -4173,7 +4135,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case WL_CHAINLIGHTNING: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->addtimerskill(src,tick + 150,bl->id,3,0,WL_CHAINLIGHTNING_ATK,skill_lv,4+skill_lv,flag); + skill->addtimerskill(src,tick+status_get_amotion(src),bl->id,0,0,WL_CHAINLIGHTNING_ATK,skill_lv,0,flag); break; case WL_DRAINLIFE: { @@ -4182,7 +4144,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint heal = heal * (5 + 5 * skill_lv) / 100; - if( bl->type == BL_SKILL ) + if( bl->type == BL_SKILL || status_get_hp(src) == status_get_max_hp(src)) // Don't absorb when caster was in full HP heal = 0; // Don't absorb heal from Ice Walls or other skill units. if( heal && rnd()%100 < rate ) @@ -4194,61 +4156,43 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case WL_TETRAVORTEX: - if( sd ) { - int spheres[5] = { 0, 0, 0, 0, 0 }, - positions[5] = {-1,-1,-1,-1,-1 }, - i, j = 0, k, subskill = 0; - - for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) - if( sc && sc->data[i] ) - { - spheres[j] = i; - positions[j] = sc->data[i]->val2; - j++; // - } - - if( j < 4 ) - { // Need 4 spheres minimum - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - - // Sphere Sort, this time from new to old - for( i = 0; i <= j - 2; i++ ) - for( k = i + 1; k <= j - 1; k++ ) - if( positions[i] < positions[k] ) - { - swap(positions[i],positions[k]); - swap(spheres[i],spheres[k]); + if( sc ){ + int i = SC_SUMMON5, x = 0; + int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; + for(; i >= SC_SUMMON1; i--){ + if( sc->data[i] ){ + int skillid = WL_TETRAVORTEX_FIRE + (sc->data[i]->val1 - WLS_FIRE) + (sc->data[i]->val1 == WLS_WIND) - (sc->data[i]->val1 == WLS_WATER), sc_index = 0, rate = 0; + if( x < 4 ){ + types[x][0] = (sc->data[i]->val1 - WLS_FIRE) + 1; + types[x][1] = 25; // 25% each for equal sharing + if( x == 3 ){ + x = 0; + sc_index = types[rand()%4][0]; + for(; x < 4; x++) + if(types[x][0] == sc_index) + rate += types[x][1]; + } + skill->addtimerskill(src, tick + (SC_SUMMON5-i) * 206, bl->id, sc_index, rate, skillid, skill_lv, x, flag); } - - k = 0; - for( i = 0; i < 4; i++ ) - { - switch( sc->data[spheres[i]]->val1 ) - { - case WLS_FIRE: subskill = WL_TETRAVORTEX_FIRE; k |= 1; break; - case WLS_WIND: subskill = WL_TETRAVORTEX_WIND; k |= 4; break; - case WLS_WATER: subskill = WL_TETRAVORTEX_WATER; k |= 2; break; - case WLS_STONE: subskill = WL_TETRAVORTEX_GROUND; k |= 8; break; + status_change_end(src, (sc_type)i, INVALID_TIMER); + x++; } - skill->addtimerskill(src, tick + i * 200, bl->id, k, 0, subskill, skill_lv, i, flag); - clif->skill_nodamage(src, bl, subskill, skill_lv, 1); - status_change_end(src, spheres[i], INVALID_TIMER); } } break; case WL_RELEASE: if( sd ) { - int i; + int i, cooldown; + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill->toggle_magicpower(src, skill_id); // Priority is to release SpellBook if( sc && sc->data[SC_READING_SB] ) { // SpellBook uint16 skill_id, skill_lv, point, s = 0; - int spell[SC_MAXSPELLBOOK-SC_SPELLBOOK1 + 1]; + int spell[SC_SPELLBOOK7-SC_SPELLBOOK1 + 1]; - for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) // List all available spell to be released - if( sc->data[i] ) spell[s++] = i; + for(i = SC_SPELLBOOK7; i >= SC_SPELLBOOK1; i--) // List all available spell to be released + if( sc->data[i] ) spell[s++] = i; if ( s == 0 ) break; @@ -4261,13 +4205,12 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint status_change_end(src, (sc_type)i, INVALID_TIMER); }else //something went wrong :( break; - + if( sc->data[SC_READING_SB]->val2 > point ) sc->data[SC_READING_SB]->val2 -= point; else // Last spell to be released status_change_end(src, SC_READING_SB, INVALID_TIMER); - if( bl->type != BL_SKILL ) /* skill types will crash the client */ - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + if( !skill->check_condition_castbegin(sd, skill_id, skill_lv) ) break; @@ -4284,47 +4227,32 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } sd->ud.canact_tick = tick + skill->delay_fix(src, skill_id, skill_lv); - clif->status_change(src, SI_ACTIONDELAY, 1, skill->delay_fix(src, skill_id, skill_lv), 0, 0, 0); - } else { // Summon Balls - int j = 0, k, skele; - int spheres[5] = { 0, 0, 0, 0, 0 }, - positions[5] = {-1,-1,-1,-1,-1 }; - - for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) - if( sc && sc->data[i] ) { - spheres[j] = i; - positions[j] = sc->data[i]->val2; - sc->data[i]->val2--; // Prepares for next position - j++; - } + clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, skill_id, skill_lv), 0, 0, 0); - if( j == 0 ) { // No Spheres - clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0); - break; + cooldown = skill_get_cooldown(skill_id, skill_lv); + for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { + if (sd->skillcooldown[i].id == skill_id){ + cooldown += sd->skillcooldown[i].val; + break; + } } - - // Sphere Sort - for( i = 0; i <= j - 2; i++ ) - for( k = i + 1; k <= j - 1; k++ ) - if( positions[i] > positions[k] ) { - swap(positions[i],positions[k]); - swap(spheres[i],spheres[k]); - } - - if( skill_lv == 1 ) j = 1; // Limit only to one ball - for( i = 0; i < j; i++ ) { - skele = WL_RELEASE - 5 + sc->data[spheres[i]]->val1 - WLS_FIRE; // Convert Ball Element into Skill ATK for balls - // WL_SUMMON_ATK_FIRE, WL_SUMMON_ATK_WIND, WL_SUMMON_ATK_WATER, WL_SUMMON_ATK_GROUND - skill->addtimerskill(src,tick+status_get_adelay(src)*i,bl->id,0,0,skele,sc->data[spheres[i]]->val3,BF_MAGIC,flag|SD_LEVEL); - status_change_end(src, spheres[i], INVALID_TIMER); // Eliminate ball + if(cooldown) + skill->blockpc_start(sd, skill_id, cooldown, false); + }else if( sc ){ // Summon Balls + int i = SC_SUMMON5; + for(; i >= SC_SUMMON1; i--){ + if( sc->data[i] ){ + int skillid = WL_SUMMON_ATK_FIRE + (sc->data[i]->val1 - WLS_FIRE); + skill->addtimerskill(src, tick + status_get_adelay(src) * (SC_SUMMON5 - i), bl->id, 0, 0, skillid, skill_lv, BF_MAGIC, flag); + status_change_end(src, (sc_type)i, INVALID_TIMER); + if(skill_lv == 1) + break; + } } - clif->skill_nodamage(src,bl,skill_id,0,1); } } break; case WL_FROSTMISTY: - // Causes Freezing status through walls. - sc_start(bl,status_skill2sc(skill_id),20+12*skill_lv+(sd ? sd->status.job_level : 50)/5,skill_lv,skill->get_time(skill_id,skill_lv)); // Doesn't deal damage through non-shootable walls. if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) ) skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION); @@ -4453,19 +4381,19 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case SR_HOWLINGOFLION: - status_change_end(bl, SC_SWINGDANCE, INVALID_TIMER); - status_change_end(bl, SC_SYMPHONYOFLOVER, INVALID_TIMER); - status_change_end(bl, SC_MOONLITSERENADE, INVALID_TIMER); - status_change_end(bl, SC_RUSHWINDMILL, INVALID_TIMER); + status_change_end(bl, SC_SWING, INVALID_TIMER); + status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); - status_change_end(bl, SC_SATURDAYNIGHTFEVER, INVALID_TIMER); - status_change_end(bl, SC_DANCEWITHWUG, INVALID_TIMER); - status_change_end(bl, SC_LERADSDEW, INVALID_TIMER); + status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); + status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - status_change_end(bl, SC_BEYONDOFWARCRY, INVALID_TIMER); - status_change_end(bl, SC_UNLIMITEDHUMMINGVOICE, INVALID_TIMER); + status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag|SD_ANIMATION); break; @@ -4573,7 +4501,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } break; - //recursive homon skill case MH_MAGMA_FLOW: case MH_XENO_SLASHER: @@ -4589,8 +4516,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case MH_NEEDLE_OF_PARALYZE: skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; - case MH_TINDER_BREAKER: - if (unit_movepos(src, bl->x, bl->y, 1, 1)) { + case MH_TINDER_BREAKER: + if (unit_movepos(src, bl->x, bl->y, 1, 1)) { #if PACKETVER >= 20111005 clif->snap(src, bl->x, bl->y); #else @@ -4598,7 +4525,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint #endif } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,SC_CLOSECONFINE2,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start4(bl,SC_RG_CCONFINE_S,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; @@ -4651,4760 +4578,4697 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint /*========================================== * *------------------------------------------*/ -int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) +int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) { - struct map_session_data *sd, *dstsd; - struct mob_data *md, *dstmd; - struct homun_data *hd; - struct mercenary_data *mer; - struct status_data *sstatus, *tstatus; - struct status_change *tsc; - struct status_change_entry *tsce; - - int i = 0; - enum sc_type type; - - if(skill_id > 0 && !skill_lv) return 0; // celest + struct block_list *target, *src; + struct map_session_data *sd; + struct mob_data *md; + struct unit_data *ud; + struct status_change *sc = NULL; + int inf,inf2,flag = 0; - nullpo_retr(1, src); - nullpo_retr(1, bl); + src = iMap->id2bl(id); + if( src == NULL ) + { + ShowDebug("skill_castend_id: src == NULL (tid=%d, id=%d)\n", tid, id); + return 0;// not found + } - if (src->m != bl->m) - return 1; + ud = unit_bl2ud(src); + if( ud == NULL ) + { + ShowDebug("skill_castend_id: ud == NULL (tid=%d, id=%d)\n", tid, id); + return 0;// ??? + } - sd = BL_CAST(BL_PC, src); - hd = BL_CAST(BL_HOM, src); + sd = BL_CAST(BL_PC, src); md = BL_CAST(BL_MOB, src); - mer = BL_CAST(BL_MER, src); - - dstsd = BL_CAST(BL_PC, bl); - dstmd = BL_CAST(BL_MOB, bl); - if(bl->prev == NULL) - return 1; - if(status_isdead(src)) - return 1; + if( src->prev == NULL ) { + ud->skilltimer = INVALID_TIMER; + return 0; + } - if( src != bl && status_isdead(bl) ) { - /** - * Skills that may be cast on dead targets - **/ - switch( skill_id ) { - case NPC_WIDESOULDRAIN: - case PR_REDEMPTIO: - case ALL_RESURRECTION: - case WM_DEADHILLHERE: - break; - default: - return 1; + if(ud->skill_id != SA_CASTCANCEL && ud->skill_id != SO_SPELLFIST) {// otherwise handled in unit_skillcastcancel() + if( ud->skilltimer != tid ) { + ShowError("skill_castend_id: Timer mismatch %d!=%d!\n", ud->skilltimer, tid); + ud->skilltimer = INVALID_TIMER; + return 0; } - } - tstatus = status_get_status_data(bl); - sstatus = status_get_status_data(src); + if( sd && ud->skilltimer != INVALID_TIMER && (pc->checkskill(sd,SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK) ) + {// restore original walk speed + ud->skilltimer = INVALID_TIMER; + status_calc_bl(&sd->bl, SCB_SPEED); + } - //Check for undead skills that convert a no-damage skill into a damage one. [Skotlex] - switch (skill_id) { - case HLIF_HEAL: //[orn] - if (bl->type != BL_HOM) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ; - break ; - } - case AL_HEAL: - case ALL_RESURRECTION: - case PR_ASPERSIO: - /** - * Arch Bishop - **/ - case AB_RENOVATIO: - case AB_HIGHNESSHEAL: - //Apparently only player casted skills can be offensive like this. - if (sd && battle->check_undead(tstatus->race,tstatus->def_ele)) { - if (battle->check_target(src, bl, BCT_ENEMY) < 1) { - //Offensive heal does not works on non-enemies. [Skotlex] - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - return 0; - } - return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); - } - break; - case NPC_SMOKING: //Since it is a self skill, this one ends here rather than in damage_id. [Skotlex] - return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); - case MH_STEINWAND: { - struct block_list *s_src = battle->get_master(src); - short ret = 0; - if(!skill->check_unit_range(src, src->x, src->y, skill_id, skill_lv)) //prevent reiteration - ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homon - if(s_src && !skill->check_unit_range(s_src, s_src->x, s_src->y, skill_id, skill_lv)) - ret |= skill->castend_pos2(s_src,s_src->x,s_src->y,skill_id,skill_lv,tick,flag); //cast on master - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - return ret; - } - break; - default: - //Skill is actually ground placed. - if (src == bl && skill->get_unit_id(skill_id,0)) - return skill->castend_pos2(src,bl->x,bl->y,skill_id,skill_lv,tick,0); + ud->skilltimer = INVALID_TIMER; } - type = status_skill2sc(skill_id); - tsc = status_get_sc(bl); - tsce = (tsc && type != -1)?tsc->data[type]:NULL; + if (ud->skilltarget == id) + target = src; + else + target = iMap->id2bl(ud->skilltarget); - if (src!=bl && type > -1 && - (i = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL && - skill->get_inf(skill_id) != INF_SUPPORT_SKILL && - battle->attr_fix(NULL, NULL, 100, i, tstatus->def_ele, tstatus->ele_lv) <= 0) - return 1; //Skills that cause an status should be blocked if the target element blocks its element. + // Use a do so that you can break out of it when the skill fails. + do { + if(!target || target->prev==NULL) break; - iMap->freeblock_lock(); - switch(skill_id) { - case HLIF_HEAL: //[orn] - case AL_HEAL: - /** - * Arch Bishop - **/ - case AB_HIGHNESSHEAL: - { - int heal = skill->calc_heal(src, bl, (skill_id == AB_HIGHNESSHEAL)?AL_HEAL:skill_id, (skill_id == AB_HIGHNESSHEAL)?10:skill_lv, true); - int heal_get_jobexp; - //Highness Heal: starts at 1.5 boost + 0.5 for each level - if( skill_id == AB_HIGHNESSHEAL ) { - heal = heal * ( 15 + 5 * skill_lv ) / 10; - } - if( status_isimmune(bl) || - (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) || - (dstsd && pc_ismadogear(dstsd)) )//Mado is immune to heal - heal=0; + if(src->m != target->m || status_isdead(src)) break; - if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 ) - heal = heal*2; - - if( tsc && tsc->count ) - { - if( tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS) ) - { //Bounce back heal - if (--tsc->data[SC_KAITE]->val2 <= 0) - status_change_end(bl, SC_KAITE, INVALID_TIMER); - if (src == bl) - heal=0; //When you try to heal yourself under Kaite, the heal is voided. - else { - bl = src; - dstsd = sd; - } - } - else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAYNIGHTFEVER] || tsc->data[SC__BLOODYLUST]) - heal = 0; //Needed so that it actually displays 0 when healing. + switch (ud->skill_id) { + //These should become skill_castend_pos + case WE_CALLPARTNER: + if(sd) clif->callpartner(sd); + case WE_CALLPARENT: + case WE_CALLBABY: + case AM_RESURRECTHOMUN: + case PF_SPIDERWEB: + //Find a random spot to place the skill. [Skotlex] + inf2 = skill->get_splash(ud->skill_id, ud->skill_lv); + ud->skillx = target->x + inf2; + ud->skilly = target->y + inf2; + if (inf2 && !iMap->random_dir(target, &ud->skillx, &ud->skilly)) { + ud->skillx = target->x; + ud->skilly = target->y; } - clif->skill_nodamage (src, bl, skill_id, heal, 1); - if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) - heal = ~heal + 1; - heal_get_jobexp = status_heal(bl,heal,0,0); + ud->skilltimer=tid; + return skill->castend_pos(tid,tick,id,data); + case GN_WALLOFTHORN: + ud->skillx = target->x; + ud->skilly = target->y; + ud->skilltimer = tid; + return skill->castend_pos(tid,tick,id,data); + } - if(sd && dstsd && heal > 0 && sd != dstsd && battle_config.heal_exp > 0){ - heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100; - if (heal_get_jobexp <= 0) - heal_get_jobexp = 1; - pc->gainexp (sd, bl, 0, heal_get_jobexp, false); - } + if(ud->skill_id == RG_BACKSTAP) { + uint8 dir = iMap->calc_dir(src,target->x,target->y),t_dir = unit_getdir(target); + if(check_distance_bl(src, target, 0) || iMap->check_dir(dir,t_dir)) { + break; } - break; + } - case PR_REDEMPTIO: - if (sd && !(flag&1)) { - if (sd->status.party_id == 0) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - skill_area_temp[0] = 0; - party_foreachsamemap(skill->area_sub, - sd,skill->get_splash(skill_id, skill_lv), - src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, - skill->castend_nodamage_id); - if (skill_area_temp[0] == 0) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - skill_area_temp[0] = 5 - skill_area_temp[0]; // The actual penalty... - if (skill_area_temp[0] > 0 && !map[src->m].flag.noexppenalty) { //Apply penalty - sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * skill_area_temp[0] * 2/1000); //0.2% penalty per each. - sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * skill_area_temp[0] * 2/1000); - clif->updatestatus(sd,SP_BASEEXP); - clif->updatestatus(sd,SP_JOBEXP); - } - status_set_hp(src, 1, 0); - status_set_sp(src, 0, 0); + if( ud->skill_id == PR_TURNUNDEAD ) { + struct status_data *tstatus = status_get_status_data(target); + if( !battle->check_undead(tstatus->race, tstatus->def_ele) ) break; - } else if (status_isdead(bl) && flag&1) { //Revive - skill_area_temp[0]++; //Count it in, then fall-through to the Resurrection code. - skill_lv = 3; //Resurrection level 3 is used - } else //Invalid target, skip resurrection. + } + + if( ud->skill_id == RA_WUGSTRIKE ){ + if( !path_search(NULL,src->m,src->x,src->y,target->x,target->y,1,CELL_CHKNOREACH)) break; + } - case ALL_RESURRECTION: - if(sd && (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)) - { //No reviving in WoE grounds! - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if( ud->skill_id == PR_LEXDIVINA || ud->skill_id == MER_LEXDIVINA ) + { + sc = status_get_sc(target); + if( battle->check_target(src,target, BCT_ENEMY) <= 0 && (!sc || !sc->data[SC_SILENCE]) ) + { //If it's not an enemy, and not silenced, you can't use the skill on them. [Skotlex] + clif->skill_nodamage (src, target, ud->skill_id, ud->skill_lv, 0); break; } - if (!status_isdead(bl)) - break; + } + else + { // Check target validity. + inf = skill->get_inf(ud->skill_id); + inf2 = skill->get_inf2(ud->skill_id); + + if(inf&INF_ATTACK_SKILL || + (inf&INF_SELF_SKILL && inf2&INF2_NO_TARGET_SELF) //Combo skills + ) // Casted through combo. + inf = BCT_ENEMY; //Offensive skill. + else if(inf2&INF2_NO_ENEMY) + inf = BCT_NOENEMY; + else + inf = 0; + + if(inf2 & (INF2_PARTY_ONLY|INF2_GUILD_ONLY) && src != target) { - int per = 0, sper = 0; - if (tsc && tsc->data[SC_HELLPOWER]) - break; + inf |= + (inf2&INF2_PARTY_ONLY?BCT_PARTY:0)| + (inf2&INF2_GUILD_ONLY?BCT_GUILD:0); + //Remove neutral targets (but allow enemy if skill is designed to be so) + inf &= ~BCT_NEUTRAL; + } - if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0) + if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) { + clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0); + break; + } + + if( ud->skill_id >= SL_SKE && ud->skill_id <= SL_SKA && target->type == BL_MOB ) + { + if( ((TBL_MOB*)target)->class_ == MOBID_EMPERIUM ) break; + } + else if (inf && battle->check_target(src, target, inf) <= 0){ + if (sd) clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); + break; + } - switch(skill_lv){ - case 1: per=10; break; - case 2: per=30; break; - case 3: per=50; break; - case 4: per=80; break; - } - if(dstsd && dstsd->special_state.restart_full_recover) - per = sper = 100; - if (status_revive(bl, per, sper)) - { - clif->skill_nodamage(src,bl,ALL_RESURRECTION,skill_lv,1); //Both Redemptio and Res show this skill-animation. - if(sd && dstsd && battle_config.resurrection_exp > 0) - { - int exp = 0,jexp = 0; - int lv = dstsd->status.base_level - sd->status.base_level, jlv = dstsd->status.job_level - sd->status.job_level; - if(lv > 0 && pc->nextbaseexp(dstsd)) { - exp = (int)((double)dstsd->status.base_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.); - if (exp < 1) exp = 1; - } - if(jlv > 0 && pc->nextjobexp(dstsd)) { - jexp = (int)((double)dstsd->status.job_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.); - if (jexp < 1) jexp = 1; - } - if(exp > 0 || jexp > 0) - pc->gainexp (sd, bl, exp, jexp, false); - } - } + if(inf&BCT_ENEMY && (sc = status_get_sc(target)) && + sc->data[SC_FOGWALL] && + rnd() % 100 < 75) { //Fogwall makes all offensive-type targetted skills fail at 75% + if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); + break; } - break; + } - case AL_DECAGI: - case MER_DECAGI: - clif->skill_nodamage (src, bl, skill_id, skill_lv, - sc_start(bl, type, (40 + skill_lv * 2 + (status_get_lv(src) + sstatus->int_)/5), skill_lv, skill->get_time(skill_id,skill_lv))); + //Avoid doing double checks for instant-cast skills. + if (tid != INVALID_TIMER && !status_check_skilluse(src, target, ud->skill_id, 1)) break; - case AL_CRUCIS: - if (flag&1) - sc_start(bl,type, 23+skill_lv*4 +status_get_lv(src) -status_get_lv(bl), skill_lv,skill->get_time(skill_id,skill_lv)); - else { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + if(md) { + md->last_thinktime=tick +MIN_MOBTHINKTIME; + if(md->skill_idx >= 0 && md->db->skill[md->skill_idx].emotion >= 0) + clif->emotion(src, md->db->skill[md->skill_idx].emotion); + } + + if(src != target && battle_config.skill_add_range && + !check_distance_bl(src, target, skill->get_range2(src,ud->skill_id,ud->skill_lv)+battle_config.skill_add_range)) + { + if (sd) { + clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); + if(battle_config.skill_out_range_consume) //Consume items anyway. [Skotlex] + skill->consume_requirement(sd,ud->skill_id,ud->skill_lv,3); } break; + } - case PR_LEXDIVINA: - case MER_LEXDIVINA: - if( tsce ) - status_change_end(bl,type, INVALID_TIMER); + if( sd ) + { + if( !skill->check_condition_castend(sd, ud->skill_id, ud->skill_lv) ) + break; else - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); + skill->consume_requirement(sd,ud->skill_id,ud->skill_lv,1); + } +#ifdef OFFICIAL_WALKPATH + if( !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) ) + break; +#endif + if( (src->type == BL_MER || src->type == BL_HOM) && !skill->check_condition_mercenary(src, ud->skill_id, ud->skill_lv, 1) ) break; - case SA_ABRACADABRA: - { - int abra_skill_id = 0, abra_skill_lv; - do { - i = rnd() % MAX_SKILL_ABRA_DB; - abra_skill_id = skill_abra_db[i].skill_id; - } while (abra_skill_id == 0 || - skill_abra_db[i].req_lv > skill_lv || //Required lv for it to appear - rnd()%10000 >= skill_abra_db[i].per - ); - abra_skill_lv = min(skill_lv, skill->get_max(abra_skill_id)); - clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); + if (ud->state.running && ud->skill_id == TK_JUMPKICK) { + ud->state.running = 0; + status_change_end(src, SC_RUN, INVALID_TIMER); + flag = 1; + } - if( sd ) - {// player-casted - sd->state.abra_flag = 1; - sd->skillitem = abra_skill_id; - sd->skillitemlv = abra_skill_lv; - clif->item_skill(sd, abra_skill_id, abra_skill_lv); - } - else - {// mob-casted - struct unit_data *ud = unit_bl2ud(src); - int inf = skill->get_inf(abra_skill_id); - if (!ud) break; - if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { - if (src->type == BL_PET) - bl = (struct block_list*)((TBL_PET*)src)->msd; - if (!bl) bl = src; - unit_skilluse_id(src, bl->id, abra_skill_id, abra_skill_lv); - } else { //Assume offensive skills - int target_id = 0; - if (ud->target) - target_id = ud->target; - else switch (src->type) { - case BL_MOB: target_id = ((TBL_MOB*)src)->target_id; break; - case BL_PET: target_id = ((TBL_PET*)src)->target_id; break; - } - if (!target_id) - break; - if (skill->get_casttype(abra_skill_id) == CAST_GROUND) { - bl = iMap->id2bl(target_id); - if (!bl) bl = src; - unit_skilluse_pos(src, bl->x, bl->y, abra_skill_id, abra_skill_lv); - } else - unit_skilluse_id(src, target_id, abra_skill_id, abra_skill_lv); - } - } - } - break; - - case SA_COMA: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv))); - break; - case SA_FULLRECOVERY: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (status_isimmune(bl)) - break; - status_percent_heal(bl, 100, 100); - break; - case NPC_ALLHEAL: - { - int heal; - if( status_isimmune(bl) ) - break; - heal = status_percent_heal(bl, 100, 0); - clif->skill_nodamage(NULL, bl, AL_HEAL, heal, 1); - if( dstmd ) - { // Reset Damage Logs - memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog)); - dstmd->tdmg = 0; + if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH) + unit_stop_walking(src,1); + + if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] + if (sd) { //Cooldown application + int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv); + for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { // Increases/Decreases cooldown of a skill by item/card bonuses. + if (sd->skillcooldown[i].id == ud->skill_id){ + cooldown += sd->skillcooldown[i].val; + break; } } - break; - case SA_SUMMONMONSTER: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd) mob_once_spawn(sd, src->m, src->x, src->y," --ja--", -1, 1, "", SZ_SMALL, AI_NONE); - break; - case SA_LEVELUP: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd && pc->nextbaseexp(sd)) pc->gainexp(sd, NULL, pc->nextbaseexp(sd) * 10 / 100, 0, false); - break; - case SA_INSTANTDEATH: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_set_hp(bl,1,0); - break; - case SA_QUESTION: - case SA_GRAVITY: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - break; - case SA_CLASSCHANGE: - case SA_MONOCELL: - if (dstmd) + if(cooldown) + skill->blockpc_start(sd, ud->skill_id, cooldown, false); + } + if( battle_config.display_status_timers && sd ) + clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); + if( sd ) + { + switch( ud->skill_id ) { - int class_; - if ( sd && dstmd->status.mode&MD_BOSS ) - { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - class_ = skill_id==SA_MONOCELL?1002:mob_get_random_id(4, 1, 0); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - mob_class_change(dstmd,class_); - if( tsc && dstmd->status.mode&MD_BOSS ) + case GS_DESPERADO: + sd->canequip_tick = tick + skill->get_time(ud->skill_id, ud->skill_lv); + break; + case CR_GRANDCROSS: + case NPC_GRANDDARKNESS: + if( (sc = status_get_sc(src)) && sc->data[SC_NOEQUIPSHIELD] ) { - const enum sc_type scs[] = { SC_QUAGMIRE, SC_PROVOKE, SC_ROKISWEIL, SC_GRAVITATION, SC_SUITON, SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC_BLADESTOP }; - for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++) - if (tsc->data[i]) status_change_end(bl, (sc_type)i, INVALID_TIMER); - for (i = 0; i < ARRAYLENGTH(scs); i++) - if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); + const struct TimerData *timer = iTimer->get_timer(sc->data[SC_NOEQUIPSHIELD]->timer); + if( timer && timer->func == status_change_timer && DIFF_TICK(timer->tick,iTimer->gettick()+skill->get_time(ud->skill_id, ud->skill_lv)) > 0 ) + break; } - } - break; - case SA_DEATH: - if ( sd && dstmd && dstmd->status.mode&MD_BOSS ) - { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + sc_start2(src, SC_NOEQUIPSHIELD, 100, 0, 1, skill->get_time(ud->skill_id, ud->skill_lv)); break; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_kill(bl); - break; - case SA_REVERSEORCISH: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); - break; - case SA_FORTUNE: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd) pc->getzeny(sd,status_get_lv(bl)*100,LOG_TYPE_STEAL,NULL); - break; - case SA_TAMINGMONSTER: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd && dstmd) { - ARR_FIND( 0, MAX_PET_DB, i, dstmd->class_ == pet_db[i].class_ ); - if( i < MAX_PET_DB ) - pet_catch_process1(sd, dstmd->class_); - } - break; - - case CR_PROVIDENCE: - if(sd && dstsd){ //Check they are not another crusader [Skotlex] - if ((dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } - } - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - - case CG_MARIONETTE: - { - struct status_change* sc = status_get_sc(src); - - if( sd && dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex ) - {// Cannot cast on another bard/dancer-type class of the same gender as caster - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } + } + if (skill->get_state(ud->skill_id) != ST_MOVE_ENABLE) + unit_set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); - if( sc && tsc ) - { - if( !sc->data[SC_MARIONETTE] && !tsc->data[SC_MARIONETTE2] ) - { - sc_start(src,SC_MARIONETTE,100,bl->id,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_MARIONETTE2,100,src->id,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - else - if( sc->data[SC_MARIONETTE ] && sc->data[SC_MARIONETTE ]->val1 == bl->id && - tsc->data[SC_MARIONETTE2] && tsc->data[SC_MARIONETTE2]->val1 == src->id ) - { - status_change_end(src, SC_MARIONETTE, INVALID_TIMER); - status_change_end(bl, SC_MARIONETTE2, INVALID_TIMER); - } - else - { - if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if(battle_config.skill_log && battle_config.skill_log&src->type) + ShowInfo("Type %d, ID %d skill castend id [id =%d, lv=%d, target ID %d]\n", + src->type, src->id, ud->skill_id, ud->skill_lv, target->id); - iMap->freeblock_unlock(); - return 1; - } - } - } - break; + iMap->freeblock_lock(); - case RG_CLOSECONFINE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); - break; - case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris] - case SA_FROSTWEAPON: - case SA_LIGHTNINGLOADER: - case SA_SEISMICWEAPON: - if (dstsd) { - if(dstsd->status.weapon == W_FIST || - (dstsd->sc.count && !dstsd->sc.data[type] && - ( //Allow re-enchanting to lenghten time. [Skotlex] - dstsd->sc.data[SC_FIREWEAPON] || - dstsd->sc.data[SC_WATERWEAPON] || - dstsd->sc.data[SC_WINDWEAPON] || - dstsd->sc.data[SC_EARTHWEAPON] || - dstsd->sc.data[SC_SHADOWWEAPON] || - dstsd->sc.data[SC_GHOSTWEAPON] || - dstsd->sc.data[SC_ENCPOISON] - )) - ) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - break; - } - } - // 100% success rate at lv4 & 5, but lasts longer at lv5 - if(!clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,type,(60+skill_lv*10),skill_lv, skill->get_time(skill_id,skill_lv)))) { - if (sd) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - if (skill->break_equip(bl, EQP_WEAPON, 10000, BCT_PARTY) && sd && sd != dstsd) - clif->message(sd->fd, msg_txt(669)); - } - break; + // SC_MAGICPOWER needs to switch states before any damage is actually dealt + skill->toggle_magicpower(src, ud->skill_id); + if( ud->skill_id != RA_CAMOUFLAGE ) // only normal attack and auto cast skills benefit from its bonuses + status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); - case PR_ASPERSIO: - if (sd && dstmd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - break; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; + if (skill->get_casttype(ud->skill_id) == CAST_NODAMAGE) + skill->castend_nodamage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); + else + skill->castend_damage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); - case ITEM_ENCHANTARMS: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv, - skill->get_ele(skill_id,skill_lv), skill->get_time(skill_id,skill_lv))); - break; + sc = status_get_sc(src); + if(sc && sc->count) { + if(sc->data[SC_SOULLINK] && + sc->data[SC_SOULLINK]->val2 == SL_WIZARD && + sc->data[SC_SOULLINK]->val3 == ud->skill_id && + ud->skill_id != WZ_WATERBALL) + sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. - case TK_SEVENWIND: - switch(skill->get_ele(skill_id,skill_lv)) { - case ELE_EARTH : type = SC_EARTHWEAPON; break; - case ELE_WIND : type = SC_WINDWEAPON; break; - case ELE_WATER : type = SC_WATERWEAPON; break; - case ELE_FIRE : type = SC_FIREWEAPON; break; - case ELE_GHOST : type = SC_GHOSTWEAPON; break; - case ELE_DARK : type = SC_SHADOWWEAPON; break; - case ELE_HOLY : type = SC_ASPERSIO; break; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if( sc->data[SC_DANCING] && skill->get_inf2(ud->skill_id)&INF2_SONG_DANCE && sd ) + skill->blockpc_start(sd,BD_ADAPTATION,3000, false); + } - sc_start(bl,SC_SEVENWIND,100,skill_lv,skill->get_time(skill_id,skill_lv)); + if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish] + sd->skillitem = sd->skillitemlv = 0; - break; + if (ud->skilltimer == INVALID_TIMER) { + if(md) md->skill_idx = -1; + else ud->skill_id = 0; //mobs can't clear this one as it is used for skill condition 'afterskill' + ud->skill_lv = ud->skilltarget = 0; + } + iMap->freeblock_unlock(); + return 1; + } while(0); - case PR_KYRIE: - case MER_KYRIE: - clif->skill_nodamage(bl,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - //Passive Magnum, should had been casted on yourself. - case SM_MAGNUM: - case MS_MAGNUM: - skill_area_temp[1] = 0; - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); - clif->skill_nodamage (src,src,skill_id,skill_lv,1); - // Initiate 10% of your damage becomes fire element. - sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill->get_time2(skill_id, skill_lv)); - if( sd ) - skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv), false); - else if( bl->type == BL_MER ) - skill->blockmerc_start((TBL_MER*)bl, skill_id, skill->get_time(skill_id, skill_lv)); + //Skill failed. + if (ud->skill_id == MO_EXTREMITYFIST && sd && !(sc && sc->data[SC_FOGWALL])) + { //When Asura fails... (except when it fails from Fog of Wall) + //Consume SP/spheres + skill->consume_requirement(sd,ud->skill_id, ud->skill_lv,1); + status_set_sp(src, 0, 0); + sc = &sd->sc; + if (sc->count) + { //End states + status_change_end(src, SC_EXPLOSIONSPIRITS, INVALID_TIMER); + status_change_end(src, SC_BLADESTOP, INVALID_TIMER); +#ifdef RENEWAL + sc_start(src, SC_EXTREMITYFIST2, 100, ud->skill_lv, skill->get_time(ud->skill_id, ud->skill_lv)); +#endif + } + if (target && target->m == src->m) + { //Move character to target anyway. + int dir, x, y; + dir = iMap->calc_dir(src,target->x,target->y); + if( dir > 0 && dir < 4) x = -2; + else if( dir > 4 ) x = 2; + else x = 0; + if( dir > 2 && dir < 6 ) y = -2; + else if( dir == 7 || dir < 2 ) y = 2; + else y = 0; + if (unit_movepos(src, src->x+x, src->y+y, 1, 1)) + { //Display movement + animation. + clif->slide(src,src->x,src->y); + clif->skill_damage(src,target,tick,sd->battle_status.amotion,0,0,1,ud->skill_id, ud->skill_lv, 5); + } + clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); + } + } + + ud->skill_id = ud->skill_lv = ud->skilltarget = 0; + if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + ud->canact_tick = tick; + //You can't place a skill failed packet here because it would be + //sent in ALL cases, even cases where skill_check_condition fails + //which would lead to double 'skill failed' messages u.u [Skotlex] + if(sd) + sd->skillitem = sd->skillitemlv = 0; + else if(md) + md->skill_idx = -1; + return 0; +} + +/*========================================== + * + *------------------------------------------*/ +int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) +{ + struct map_session_data *sd, *dstsd; + struct mob_data *md, *dstmd; + struct homun_data *hd; + struct mercenary_data *mer; + struct status_data *sstatus, *tstatus; + struct status_change *tsc; + struct status_change_entry *tsce; + + int i = 0; + enum sc_type type; + + if(skill_id > 0 && !skill_lv) return 0; // celest + + nullpo_retr(1, src); + nullpo_retr(1, bl); + + if (src->m != bl->m) + return 1; + + sd = BL_CAST(BL_PC, src); + hd = BL_CAST(BL_HOM, src); + md = BL_CAST(BL_MOB, src); + mer = BL_CAST(BL_MER, src); + + dstsd = BL_CAST(BL_PC, bl); + dstmd = BL_CAST(BL_MOB, bl); + + if(bl->prev == NULL) + return 1; + if(status_isdead(src)) + return 1; + + if( src != bl && status_isdead(bl) ) { + /** + * Skills that may be cast on dead targets + **/ + switch( skill_id ) { + case NPC_WIDESOULDRAIN: + case PR_REDEMPTIO: + case ALL_RESURRECTION: + case WM_DEADHILLHERE: + break; + default: + return 1; + } + } + + tstatus = status_get_status_data(bl); + sstatus = status_get_status_data(src); + + //Check for undead skills that convert a no-damage skill into a damage one. [Skotlex] + switch (skill_id) { + case HLIF_HEAL: //[orn] + if (bl->type != BL_HOM) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ; + break ; + } + case AL_HEAL: + case ALL_RESURRECTION: + case PR_ASPERSIO: + /** + * Arch Bishop + **/ + case AB_RENOVATIO: + case AB_HIGHNESSHEAL: + //Apparently only player casted skills can be offensive like this. + if (sd && battle->check_undead(tstatus->race,tstatus->def_ele)) { + if (battle->check_target(src, bl, BCT_ENEMY) < 1) { + //Offensive heal does not works on non-enemies. [Skotlex] + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); + } break; + case NPC_SMOKING: //Since it is a self skill, this one ends here rather than in damage_id. [Skotlex] + return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); + case MH_STEINWAND: { + struct block_list *s_src = battle->get_master(src); + short ret = 0; + if(!skill->check_unit_range(src, src->x, src->y, skill_id, skill_lv)) //prevent reiteration + ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homon + if(s_src && !skill->check_unit_range(s_src, s_src->x, s_src->y, skill_id, skill_lv)) + ret |= skill->castend_pos2(s_src,s_src->x,s_src->y,skill_id,skill_lv,tick,flag); //cast on master + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + return ret; + } + break; + case RK_MILLENNIUMSHIELD: + case RK_CRUSHSTRIKE: + case RK_REFRESH: + case RK_GIANTGROWTH: + case RK_STONEHARDSKIN: + case RK_VITALITYACTIVATION: + case RK_STORMBLAST: + case RK_FIGHTINGSPIRIT: + case RK_ABUNDANCE: + if( sd && !pc->checkskill(sd, RK_RUNEMASTERY) ){ + if( status_change_start(&sd->bl, (sc_type)(rnd()%SC_CONFUSION), 1000, 1, 0, 0, 0, skill->get_time2(skill_id,skill_lv),8) ){ + skill->consume_requirement(sd,skill_id,skill_lv,2); + iMap->freeblock_unlock(); + return 0; + } + } + break; + default: + //Skill is actually ground placed. + if (src == bl && skill->get_unit_id(skill_id,0)) + return skill->castend_pos2(src,bl->x,bl->y,skill_id,skill_lv,tick,0); + } - case TK_JUMPKICK: - /* Check if the target is an enemy; if not, skill should fail so the character doesn't unit_movepos (exploitable) */ - if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) + type = status_skill2sc(skill_id); + tsc = status_get_sc(bl); + tsce = (tsc && type != -1)?tsc->data[type]:NULL; + + if (src!=bl && type > -1 && + (i = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL && + skill->get_inf(skill_id) != INF_SUPPORT_SKILL && + battle->attr_fix(NULL, NULL, 100, i, tstatus->def_ele, tstatus->ele_lv) <= 0) + return 1; //Skills that cause an status should be blocked if the target element blocks its element. + + iMap->freeblock_lock(); + switch(skill_id) { + case HLIF_HEAL: //[orn] + case AL_HEAL: + /** + * Arch Bishop + **/ + case AB_HIGHNESSHEAL: { - if( unit_movepos(src, bl->x, bl->y, 1, 1) ) + int heal = skill->calc_heal(src, bl, (skill_id == AB_HIGHNESSHEAL)?AL_HEAL:skill_id, (skill_id == AB_HIGHNESSHEAL)?10:skill_lv, true); + int heal_get_jobexp; + //Highness Heal: starts at 1.5 boost + 0.5 for each level + if( skill_id == AB_HIGHNESSHEAL ) { + heal = heal * ( 15 + 5 * skill_lv ) / 10; + } + if( status_isimmune(bl) || + (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) || + (dstsd && pc_ismadogear(dstsd)) )//Mado is immune to heal + heal=0; + + if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 ) + heal = heal*2; + + if( tsc && tsc->count ) { - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - clif->slide(src,bl->x,bl->y); + if( tsc->data[SC_KAITE] && !(sstatus->mode&MD_BOSS) ) + { //Bounce back heal + if (--tsc->data[SC_KAITE]->val2 <= 0) + status_change_end(bl, SC_KAITE, INVALID_TIMER); + if (src == bl) + heal=0; //When you try to heal yourself under Kaite, the heal is voided. + else { + bl = src; + dstsd = sd; + } + } + else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAY_NIGHT_FEVER] || tsc->data[SC__BLOODYLUST]) + heal = 0; //Needed so that it actually displays 0 when healing. + } + clif->skill_nodamage (src, bl, skill_id, heal, 1); + if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) + heal = ~heal + 1; + heal_get_jobexp = status_heal(bl,heal,0,0); + + if(sd && dstsd && heal > 0 && sd != dstsd && battle_config.heal_exp > 0){ + heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100; + if (heal_get_jobexp <= 0) + heal_get_jobexp = 1; + pc->gainexp (sd, bl, 0, heal_get_jobexp, false); } } - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); break; - case AL_INCAGI: - case AL_BLESSING: - case MER_INCAGI: - case MER_BLESSING: - if (dstsd != NULL && tsc->data[SC_CHANGEUNDEAD]) { - skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); + case PR_REDEMPTIO: + if (sd && !(flag&1)) { + if (sd->status.party_id == 0) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + skill_area_temp[0] = 0; + party_foreachsamemap(skill->area_sub, + sd,skill->get_splash(skill_id, skill_lv), + src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, + skill->castend_nodamage_id); + if (skill_area_temp[0] == 0) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + skill_area_temp[0] = 5 - skill_area_temp[0]; // The actual penalty... + if (skill_area_temp[0] > 0 && !map[src->m].flag.noexppenalty) { //Apply penalty + sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * skill_area_temp[0] * 2/1000); //0.2% penalty per each. + sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * skill_area_temp[0] * 2/1000); + clif->updatestatus(sd,SP_BASEEXP); + clif->updatestatus(sd,SP_JOBEXP); + } + status_set_hp(src, 1, 0); + status_set_sp(src, 0, 0); + break; + } else if (status_isdead(bl) && flag&1) { //Revive + skill_area_temp[0]++; //Count it in, then fall-through to the Resurrection code. + skill_lv = 3; //Resurrection level 3 is used + } else //Invalid target, skip resurrection. break; - } - case PR_SLOWPOISON: - case PR_IMPOSITIO: - case PR_LEXAETERNA: - case PR_SUFFRAGIUM: - case PR_BENEDICTIO: - case LK_BERSERK: - case MS_BERSERK: - case KN_AUTOCOUNTER: - case KN_TWOHANDQUICKEN: - case KN_ONEHAND: - case MER_QUICKEN: - case CR_SPEARQUICKEN: - case CR_REFLECTSHIELD: - case MS_REFLECTSHIELD: - case AS_POISONREACT: - case MC_LOUD: - case MG_ENERGYCOAT: - case MO_EXPLOSIONSPIRITS: - case MO_STEELBODY: - case MO_BLADESTOP: - case LK_AURABLADE: - case LK_PARRYING: - case MS_PARRYING: - case LK_CONCENTRATION: - case WS_CARTBOOST: - case SN_SIGHT: - case WS_MELTDOWN: - case WS_OVERTHRUSTMAX: - case ST_REJECTSWORD: - case HW_MAGICPOWER: - case PF_MEMORIZE: - case PA_SACRIFICE: - case ASC_EDP: - case PF_DOUBLECASTING: - case SG_SUN_COMFORT: - case SG_MOON_COMFORT: - case SG_STAR_COMFORT: - case NPC_HALLUCINATION: - case GS_MADNESSCANCEL: - case GS_ADJUSTMENT: - case GS_INCREASING: - case NJ_KASUMIKIRI: - case NJ_UTSUSEMI: - case NJ_NEN: - case NPC_DEFENDER: - case NPC_MAGICMIRROR: - case ST_PRESERVE: - case NPC_INVINCIBLE: - case NPC_INVINCIBLEOFF: - case RK_DEATHBOUND: - case AB_RENOVATIO: - case AB_EXPIATIO: - case AB_DUPLELIGHT: - case AB_SECRAMENT: - case NC_ACCELERATION: - case NC_HOVERING: - case NC_SHAPESHIFT: - case WL_RECOGNIZEDSPELL: - case GC_VENOMIMPRESS: - case SC_DEADLYINFECT: - case LG_EXEEDBREAK: - case LG_PRESTIGE: - case SR_CRESCENTELBOW: - case SR_LIGHTNINGWALK: - case SR_GENTLETOUCH_ENERGYGAIN: - case GN_CARTBOOST: - case KO_MEIKYOUSISUI: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - case SO_STRIKING: - if (sd) { - int bonus = 25 + 10 * skill_lv; - bonus += (pc->checkskill(sd, SA_FLAMELAUNCHER)+pc->checkskill(sd, SA_FROSTWEAPON)+pc->checkskill(sd, SA_LIGHTNINGLOADER)+pc->checkskill(sd, SA_SEISMICWEAPON))*5; - clif->skill_nodamage( src, bl, skill_id, skill_lv, - battle->check_target(src,bl,BCT_PARTY) > 0 ? - sc_start2(bl, type, 100, skill_lv, bonus, skill->get_time(skill_id,skill_lv)) : - 0 - ); + case ALL_RESURRECTION: + if(sd && (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)) + { //No reviving in WoE grounds! + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } - break; + if (!status_isdead(bl)) + break; + { + int per = 0, sper = 0; + if (tsc && tsc->data[SC_HELLPOWER]) + break; - case NPC_STOP: - if( clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)) ) ) - sc_start2(src,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)); - break; - case HP_ASSUMPTIO: - if( sd && dstmd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - else - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - case MG_SIGHT: - case MER_SIGHT: - case AL_RUWACH: - case WZ_SIGHTBLASTER: - case NPC_WIDESIGHT: - case NPC_STONESKIN: - case NPC_ANTIMAGIC: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,skill_id,skill->get_time(skill_id,skill_lv))); - break; - case HLIF_AVOID: - case HAMI_DEFENCE: - i = skill->get_time(skill_id,skill_lv); - clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,i)); // Master - clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,type,100,skill_lv,i)); // Homunc + if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0) + break; + + switch(skill_lv){ + case 1: per=10; break; + case 2: per=30; break; + case 3: per=50; break; + case 4: per=80; break; + } + if(dstsd && dstsd->special_state.restart_full_recover) + per = sper = 100; + if (status_revive(bl, per, sper)) + { + clif->skill_nodamage(src,bl,ALL_RESURRECTION,skill_lv,1); //Both Redemptio and Res show this skill-animation. + if(sd && dstsd && battle_config.resurrection_exp > 0) + { + int exp = 0,jexp = 0; + int lv = dstsd->status.base_level - sd->status.base_level, jlv = dstsd->status.job_level - sd->status.job_level; + if(lv > 0 && pc->nextbaseexp(dstsd)) { + exp = (int)((double)dstsd->status.base_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.); + if (exp < 1) exp = 1; + } + if(jlv > 0 && pc->nextjobexp(dstsd)) { + jexp = (int)((double)dstsd->status.job_exp * (double)lv * (double)battle_config.resurrection_exp / 1000000.); + if (jexp < 1) jexp = 1; + } + if(exp > 0 || jexp > 0) + pc->gainexp (sd, bl, exp, jexp, false); + } + } + } break; - case NJ_BUNSINJYUTSU: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - status_change_end(bl, SC_NEN, INVALID_TIMER); + + case AL_DECAGI: + case MER_DECAGI: + clif->skill_nodamage (src, bl, skill_id, skill_lv, + sc_start(bl, type, (40 + skill_lv * 2 + (status_get_lv(src) + sstatus->int_)/5), skill_lv, skill->get_time(skill_id,skill_lv))); break; - /* Was modified to only affect targetted char. [Skotlex] - case HP_ASSUMPTIO: + + case AL_CRUCIS: if (flag&1) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), BL_PC, - src, skill_id, skill_lv, tick, flag|BCT_ALL|1, - skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start(bl,type, 23+skill_lv*4 +status_get_lv(src) -status_get_lv(bl), skill_lv,skill->get_time(skill_id,skill_lv)); + else { + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; - */ - case SM_ENDURE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - if (sd) - skill->blockpc_start (sd, skill_id, skill->get_time2(skill_id,skill_lv), false); + + case PR_LEXDIVINA: + case MER_LEXDIVINA: + if( tsce ) + status_change_end(bl,type, INVALID_TIMER); + else + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); break; - case AS_ENCHANTPOISON: // Prevent spamming [Valaris] - if (sd && dstsd && dstsd->sc.count) { - if (dstsd->sc.data[SC_FIREWEAPON] || - dstsd->sc.data[SC_WATERWEAPON] || - dstsd->sc.data[SC_WINDWEAPON] || - dstsd->sc.data[SC_EARTHWEAPON] || - dstsd->sc.data[SC_SHADOWWEAPON] || - dstsd->sc.data[SC_GHOSTWEAPON] - // dstsd->sc.data[SC_ENCPOISON] //People say you should be able to recast to lengthen the timer. [Skotlex] - ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + case SA_ABRACADABRA: + { + int abra_skill_id = 0, abra_skill_lv; + do { + i = rnd() % MAX_SKILL_ABRA_DB; + abra_skill_id = skill_abra_db[i].skill_id; + } while (abra_skill_id == 0 || + skill_abra_db[i].req_lv > skill_lv || //Required lv for it to appear + rnd()%10000 >= skill_abra_db[i].per + ); + abra_skill_lv = min(skill_lv, skill->get_max(abra_skill_id)); + clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); + + if( sd ) + {// player-casted + sd->state.abra_flag = 1; + sd->skillitem = abra_skill_id; + sd->skillitemlv = abra_skill_lv; + clif->item_skill(sd, abra_skill_id, abra_skill_lv); + } + else + {// mob-casted + struct unit_data *ud = unit_bl2ud(src); + int inf = skill->get_inf(abra_skill_id); + if (!ud) break; + if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { + if (src->type == BL_PET) + bl = (struct block_list*)((TBL_PET*)src)->msd; + if (!bl) bl = src; + unit_skilluse_id(src, bl->id, abra_skill_id, abra_skill_lv); + } else { //Assume offensive skills + int target_id = 0; + if (ud->target) + target_id = ud->target; + else switch (src->type) { + case BL_MOB: target_id = ((TBL_MOB*)src)->target_id; break; + case BL_PET: target_id = ((TBL_PET*)src)->target_id; break; + } + if (!target_id) + break; + if (skill->get_casttype(abra_skill_id) == CAST_GROUND) { + bl = iMap->id2bl(target_id); + if (!bl) bl = src; + unit_skilluse_pos(src, bl->x, bl->y, abra_skill_id, abra_skill_lv); + } else + unit_skilluse_id(src, target_id, abra_skill_id, abra_skill_lv); + } } } - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case LK_TENSIONRELAX: + case SA_COMA: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,0,0,skill->get_time2(skill_id,skill_lv), - skill->get_time(skill_id,skill_lv))); + sc_start(bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv))); break; - - case MC_CHANGECART: + case SA_FULLRECOVERY: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (status_isimmune(bl)) + break; + status_percent_heal(bl, 100, 100); break; - - case TK_MISSION: - if (sd) { - int id; - if (sd->mission_mobid && (sd->mission_count || rnd()%100)) { //Cannot change target when already have one - clif->mission_info(sd, sd->mission_mobid, sd->mission_count); - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + case NPC_ALLHEAL: + { + int heal; + if( status_isimmune(bl) ) break; + heal = status_percent_heal(bl, 100, 0); + clif->skill_nodamage(NULL, bl, AL_HEAL, heal, 1); + if( dstmd ) + { // Reset Damage Logs + memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog)); + dstmd->tdmg = 0; } - id = mob_get_random_id(0,0xF, sd->status.base_level); - if (!id) { + } + break; + case SA_SUMMONMONSTER: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (sd) mob_once_spawn(sd, src->m, src->x, src->y," --ja--", -1, 1, "", SZ_SMALL, AI_NONE); + break; + case SA_LEVELUP: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (sd && pc->nextbaseexp(sd)) pc->gainexp(sd, NULL, pc->nextbaseexp(sd) * 10 / 100, 0, false); + break; + case SA_INSTANTDEATH: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_set_hp(bl,1,0); + break; + case SA_QUESTION: + case SA_GRAVITY: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case SA_CLASSCHANGE: + case SA_MONOCELL: + if (dstmd) + { + int class_; + if ( sd && dstmd->status.mode&MD_BOSS ) + { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - sd->mission_mobid = id; - sd->mission_count = 0; - pc_setglobalreg(sd,"TK_MISSION_ID", id); - clif->mission_info(sd, id, 0); + class_ = skill_id==SA_MONOCELL?1002:mob_get_random_id(4, 1, 0); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + mob_class_change(dstmd,class_); + if( tsc && dstmd->status.mode&MD_BOSS ) + { + const enum sc_type scs[] = { SC_QUAGMIRE, SC_PROVOKE, SC_ROKISWEIL, SC_GRAVITATION, SC_NJ_SUITON, SC_NOEQUIPWEAPON, SC_NOEQUIPSHIELD, SC_NOEQUIPARMOR, SC_NOEQUIPHELM, SC_BLADESTOP }; + for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++) + if (tsc->data[i]) status_change_end(bl, (sc_type)i, INVALID_TIMER); + for (i = 0; i < ARRAYLENGTH(scs); i++) + if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); + } } break; - - case AC_CONCENTRATION: + case SA_DEATH: + if ( sd && dstmd && dstmd->status.mode&MD_BOSS ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - iMap->foreachinrange( status_change_timer_sub, src, - skill->get_splash(skill_id, skill_lv), BL_CHAR, - src,NULL,type,tick); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_kill(bl); break; - - case SM_PROVOKE: - case SM_SELFPROVOKE: - case MER_PROVOKE: - if( (tstatus->mode&MD_BOSS) || battle->check_undead(tstatus->race,tstatus->def_ele) ) - { - iMap->freeblock_unlock(); - return 1; - } - //TODO: How much does base level affects? Dummy value of 1% per level difference used. [Skotlex] - clif->skill_nodamage(src,bl,skill_id == SM_SELFPROVOKE ? SM_PROVOKE : skill_id,skill_lv, - (i = sc_start(bl,type, skill_id == SM_SELFPROVOKE ? 100:( 50 + 3*skill_lv + status_get_lv(src) - status_get_lv(bl)), skill_lv, skill->get_time(skill_id,skill_lv)))); - if( !i ) - { - if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 0; - } - unit_skillcastcancel(bl, 2); - - if( tsc && tsc->count ) - { - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - if( tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE ) - status_change_end(bl, SC_STONE, INVALID_TIMER); - status_change_end(bl, SC_SLEEP, INVALID_TIMER); - status_change_end(bl, SC_TRICKDEAD, INVALID_TIMER); + case SA_REVERSEORCISH: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); + break; + case SA_FORTUNE: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if(sd) pc->getzeny(sd,status_get_lv(bl)*100,LOG_TYPE_STEAL,NULL); + break; + case SA_TAMINGMONSTER: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (sd && dstmd) { + ARR_FIND( 0, MAX_PET_DB, i, dstmd->class_ == pet_db[i].class_ ); + if( i < MAX_PET_DB ) + pet_catch_process1(sd, dstmd->class_); } + break; - if( dstmd ) - { - dstmd->state.provoke_flag = src->id; - mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); + case CR_PROVIDENCE: + if(sd && dstsd){ //Check they are not another crusader [Skotlex] + if ((dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; + } } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case ML_DEVOTION: - case CR_DEVOTION: - { - int count, lv; - if( !dstsd || (!sd && !mer) ) - { // Only players can be devoted - if( sd ) - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - break; - } + case CG_MARIONETTE: + { + struct status_change* sc = status_get_sc(src); - if( (lv = status_get_lv(src) - dstsd->status.base_level) < 0 ) - lv = -lv; - if( lv > battle_config.devotion_level_difference || // Level difference requeriments - (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || // Cannot Devote a player devoted from another source - (skill_id == ML_DEVOTION && (!mer || mer != dstsd->md)) || // Mercenary only can devote owner - (dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER || // Crusader Cannot be devoted - (dstsd->sc.data[SC_HELLPOWER])) // Players affected by SC_HELLPOWERR cannot be devoted. - { - if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if( sd && dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex ) + {// Cannot cast on another bard/dancer-type class of the same gender as caster + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); iMap->freeblock_unlock(); return 1; } - i = 0; - count = (sd)? min(skill_lv,5) : 1; // Mercenary only can Devote owner - if( sd ) - { // Player Devoting Player - ARR_FIND(0, count, i, sd->devotion[i] == bl->id ); - if( i == count ) + if( sc && tsc ) + { + if( !sc->data[SC_MARIONETTE_MASTER] && !tsc->data[SC_MARIONETTE] ) { - ARR_FIND(0, count, i, sd->devotion[i] == 0 ); - if( i == count ) - { // No free slots, skill Fail - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - iMap->freeblock_unlock(); - return 1; - } + sc_start(src,SC_MARIONETTE_MASTER,100,bl->id,skill->get_time(skill_id,skill_lv)); + sc_start(bl,SC_MARIONETTE,100,src->id,skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + else + if( sc->data[SC_MARIONETTE_MASTER ] && sc->data[SC_MARIONETTE_MASTER ]->val1 == bl->id && + tsc->data[SC_MARIONETTE] && tsc->data[SC_MARIONETTE]->val1 == src->id ) + { + status_change_end(src, SC_MARIONETTE_MASTER, INVALID_TIMER); + status_change_end(bl, SC_MARIONETTE, INVALID_TIMER); } + else + { + if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - sd->devotion[i] = bl->id; + iMap->freeblock_unlock(); + return 1; + } } - else - mer->devotion_flag = 1; // Mercenary Devoting Owner - - clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start4(bl, type, 100, src->id, i, skill->get_range2(src,skill_id,skill_lv),0, skill->get_time2(skill_id, skill_lv))); - clif->devotion(src, NULL); - } - break; - - case MO_CALLSPIRITS: - if(sd) { - int limit = skill_lv; - if( sd->sc.data[SC_RAISINGDRAGON] ) - limit += sd->sc.data[SC_RAISINGDRAGON]->val1; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),limit); - } - break; - - case CH_SOULCOLLECT: - if(sd) { - int limit = 5; - if( sd->sc.data[SC_RAISINGDRAGON] ) - limit += sd->sc.data[SC_RAISINGDRAGON]->val1; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - for (i = 0; i < limit; i++) - pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),limit); } break; - case MO_KITRANSLATION: - if(dstsd && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) { - pc->addspiritball(dstsd,skill->get_time(skill_id,skill_lv),5); - } + case RG_CLOSECONFINE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,type,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); break; - - case TK_TURNKICK: - case MO_BALKYOUNG: //Passive part of the attack. Splash knock-back+stun. [Skotlex] - if (skill_area_temp[1] != bl->id) { - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),-1,0); - skill->additional_effect(src,bl,skill_id,skill_lv,BF_MISC,ATK_DEF,tick); //Use Misc rather than weapon to signal passive pushback + case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris] + case SA_FROSTWEAPON: + case SA_LIGHTNINGLOADER: + case SA_SEISMICWEAPON: + if (dstsd) { + if(dstsd->status.weapon == W_FIST || + (dstsd->sc.count && !dstsd->sc.data[type] && + ( //Allow re-enchanting to lenghten time. [Skotlex] + dstsd->sc.data[SC_PROPERTYFIRE] || + dstsd->sc.data[SC_PROPERTYWATER] || + dstsd->sc.data[SC_PROPERTYWIND] || + dstsd->sc.data[SC_PROPERTYGROUND] || + dstsd->sc.data[SC_PROPERTYDARK] || + dstsd->sc.data[SC_PROPERTYTELEKINESIS] || + dstsd->sc.data[SC_ENCHANTPOISON] + )) + ) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + break; + } } - break; - - case MO_ABSORBSPIRITS: - i = 0; - if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) - { // split the if for readability, and included gunslingers in the check so that their coins cannot be removed [Reddozen] - i = dstsd->spiritball * 7; - pc->delspiritball(dstsd,dstsd->spiritball,0); - } else if (dstmd && !(tstatus->mode&MD_BOSS) && rnd() % 100 < 20) - { // check if target is a monster and not a Boss, for the 20% chance to absorb 2 SP per monster's level [Reddozen] - i = 2 * dstmd->level; - mob_target(dstmd,src,0); + // 100% success rate at lv4 & 5, but lasts longer at lv5 + if(!clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,type,(60+skill_lv*10),skill_lv, skill->get_time(skill_id,skill_lv)))) { + if (sd) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if (skill->break_equip(bl, EQP_WEAPON, 10000, BCT_PARTY) && sd && sd != dstsd) + clif->message(sd->fd, msg_txt(669)); } - if (i) status_heal(src, 0, i, 3); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i?1:0); break; - case AC_MAKINGARROW: - if(sd) { - clif->arrow_create_list(sd); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case PR_ASPERSIO: + if (sd && dstmd) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + break; } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case AM_PHARMACY: - if(sd) { - clif->skill_produce_mix_list(sd,skill_id,22); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } + case ITEM_ENCHANTARMS: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl,type,100,skill_lv, + skill->get_ele(skill_id,skill_lv), skill->get_time(skill_id,skill_lv))); break; - case SA_CREATECON: - if(sd) { - clif->elementalconverter_list(sd); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case TK_SEVENWIND: + switch(skill->get_ele(skill_id,skill_lv)) { + case ELE_EARTH : type = SC_PROPERTYGROUND; break; + case ELE_WIND : type = SC_PROPERTYWIND; break; + case ELE_WATER : type = SC_PROPERTYWATER; break; + case ELE_FIRE : type = SC_PROPERTYFIRE; break; + case ELE_GHOST : type = SC_PROPERTYTELEKINESIS; break; + case ELE_DARK : type = SC_PROPERTYDARK; break; + case ELE_HOLY : type = SC_ASPERSIO; break; } - break; - - case BS_HAMMERFALL: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,SC_STUN,(20 + 10 * skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv))); - break; - case RG_RAID: - skill_area_temp[1] = 0; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), splash_target(src), - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, - skill->castend_damage_id); - status_change_end(src, SC_HIDING, INVALID_TIMER); - break; - - case ASC_METEORASSAULT: - case GS_SPREADATTACK: - case RK_STORMBLAST: - case NC_AXETORNADO: - case GC_COUNTERSLASH: - case SR_SKYNETBLOW: - case SR_RAMPAGEBLASTER: - case SR_HOWLINGOFLION: - case KO_HAPPOKUNAI: - skill_area_temp[1] = 0; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - i = iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); - if( !i && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) ) - clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - break; + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - case NC_EMERGENCYCOOL: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_change_end(src,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER); - status_change_end(src,SC_OVERHEAT,INVALID_TIMER); - break; - case SR_WINDMILL: - case GN_CART_TORNADO: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - case SR_EARTHSHAKER: - case NC_INFRAREDSCAN: - case NPC_EARTHQUAKE: - case NPC_VAMPIRE_GIFT: - case NPC_HELLJUDGEMENT: - case NPC_PULSESTRIKE: - case LG_MOONSLASHER: - skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); - break; + sc_start2(bl,SC_TK_SEVENWIND,100,skill_lv,skill->get_ele(skill_id,skill_lv),skill->get_time(skill_id,skill_lv)); - case KN_BRANDISHSPEAR: - case ML_BRANDISH: - skill->brandishspear(src, bl, skill_id, skill_lv, tick, flag); break; - case WZ_SIGHTRASHER: - //Passive side of the attack. - status_change_end(src, SC_SIGHT, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,src, - skill->get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, - skill->castend_damage_id); + case PR_KYRIE: + case MER_KYRIE: + clif->skill_nodamage(bl,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - - case NJ_HYOUSYOURAKU: - case NJ_RAIGEKISAI: - case WZ_FROSTNOVA: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + //Passive Magnum, should had been casted on yourself. + case SM_MAGNUM: + case MS_MAGNUM: skill_area_temp[1] = 0; - iMap->foreachinrange(skill->attack_area, src, - skill->get_splash(skill_id, skill_lv), splash_target(src), - BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); - break; - - case HVAN_EXPLOSION: //[orn] - case NPC_SELFDESTRUCTION: - //Self Destruction hits everyone in range (allies+enemies) - //Except for Summoned Marine spheres on non-versus maps, where it's just enemy. - i = ((!md || md->special_state.ai == 2) && !map_flag_vs(src->m))? - BCT_ENEMY:BCT_ALL; - clif->skill_nodamage(src, src, skill_id, -1, 1); - iMap->delblock(src); //Required to prevent chain-self-destructions hitting back. - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), splash_target(src), - src, skill_id, skill_lv, tick, flag|i, - skill->castend_damage_id); - iMap->addblock(src); - status_damage(src, src, sstatus->max_hp,0,0,1); - break; - - case AL_ANGELUS: - case PR_MAGNIFICAT: - case PR_GLORIA: - case SN_WINDWALK: - case CASH_BLESSING: - case CASH_INCAGI: - case CASH_ASSUMPTIO: - if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); + clif->skill_nodamage (src,src,skill_id,skill_lv,1); + // Initiate 10% of your damage becomes fire element. + sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill->get_time2(skill_id, skill_lv)); + if( sd ) + skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv), false); + else if( bl->type == BL_MER ) + skill->blockmerc_start((TBL_MER*)bl, skill_id, skill->get_time(skill_id, skill_lv)); break; - case MER_MAGNIFICAT: - if( mer != NULL ) + + case TK_JUMPKICK: + /* Check if the target is an enemy; if not, skill should fail so the character doesn't unit_movepos (exploitable) */ + if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) { - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - if( mer->master && mer->master->status.party_id != 0 && !(flag&1) ) - party_foreachsamemap(skill->area_sub, mer->master, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); - else if( mer->master && !(flag&1) ) - clif->skill_nodamage(src, &mer->master->bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if( unit_movepos(src, bl->x, bl->y, 1, 1) ) + { + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + clif->slide(src,bl->x,bl->y); + } } + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); break; - case BS_ADRENALINE: - case BS_ADRENALINE2: - case BS_WEAPONPERFECT: - case BS_OVERTHRUST: - if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) { - clif->skill_nodamage(bl,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,(src == bl)? 1:0,skill->get_time(skill_id,skill_lv))); - } else if (sd) { - party_foreachsamemap(skill->area_sub, - sd,skill->get_splash(skill_id, skill_lv), - src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, - skill->castend_nodamage_id); + case AL_INCAGI: + case AL_BLESSING: + case MER_INCAGI: + case MER_BLESSING: + if (dstsd != NULL && tsc->data[SC_PROPERTYUNDEAD]) { + skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); + break; } + case PR_SLOWPOISON: + case PR_IMPOSITIO: + case PR_LEXAETERNA: + case PR_SUFFRAGIUM: + case PR_BENEDICTIO: + case LK_BERSERK: + case MS_BERSERK: + case KN_AUTOCOUNTER: + case KN_TWOHANDQUICKEN: + case KN_ONEHAND: + case MER_QUICKEN: + case CR_SPEARQUICKEN: + case CR_REFLECTSHIELD: + case MS_REFLECTSHIELD: + case AS_POISONREACT: + case MC_LOUD: + case MG_ENERGYCOAT: + case MO_EXPLOSIONSPIRITS: + case MO_STEELBODY: + case MO_BLADESTOP: + case LK_AURABLADE: + case LK_PARRYING: + case MS_PARRYING: + case LK_CONCENTRATION: + case WS_CARTBOOST: + case SN_SIGHT: + case WS_MELTDOWN: + case WS_OVERTHRUSTMAX: + case ST_REJECTSWORD: + case HW_MAGICPOWER: + case PF_MEMORIZE: + case PA_SACRIFICE: + case ASC_EDP: + case PF_DOUBLECASTING: + case SG_SUN_COMFORT: + case SG_MOON_COMFORT: + case SG_STAR_COMFORT: + case NPC_HALLUCINATION: + case GS_MADNESSCANCEL: + case GS_ADJUSTMENT: + case GS_INCREASING: + case NJ_KASUMIKIRI: + case NJ_UTSUSEMI: + case NJ_NEN: + case NPC_DEFENDER: + case NPC_MAGICMIRROR: + case ST_PRESERVE: + case NPC_INVINCIBLE: + case NPC_INVINCIBLEOFF: + case RK_DEATHBOUND: + case AB_RENOVATIO: + case AB_EXPIATIO: + case AB_DUPLELIGHT: + case AB_SECRAMENT: + case NC_ACCELERATION: + case NC_HOVERING: + case NC_SHAPESHIFT: + case WL_RECOGNIZEDSPELL: + case GC_VENOMIMPRESS: + case SC_DEADLYINFECT: + case LG_EXEEDBREAK: + case LG_PRESTIGE: + case SR_CRESCENTELBOW: + case SR_LIGHTNINGWALK: + case SR_GENTLETOUCH_ENERGYGAIN: + case GN_CARTBOOST: + case KO_MEIKYOUSISUI: + case ALL_FULL_THROTTLE: + case RA_UNLIMIT: + case WL_TELEKINESIS_INTENSE: + case AB_OFFERTORIUM: + case RK_GIANTGROWTH: + case RK_VITALITYACTIVATION: + case RK_ABUNDANCE: + case RK_CRUSHSTRIKE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case BS_MAXIMIZE: - case NV_TRICKDEAD: - case CR_DEFENDER: - case ML_DEFENDER: - case CR_AUTOGUARD: - case ML_AUTOGUARD: - case TK_READYSTORM: - case TK_READYDOWN: - case TK_READYTURN: - case TK_READYCOUNTER: - case TK_DODGE: - case CR_SHRINK: - case SG_FUSION: - case GS_GATLINGFEVER: - if( tsce ) - { - clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); - return 0; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - case SL_KAITE: - case SL_KAAHI: - case SL_KAIZEL: - case SL_KAUPE: + case SO_STRIKING: if (sd) { - if (!dstsd || !( - (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SOULLINKER) || - (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER || - dstsd->status.char_id == sd->status.char_id || - dstsd->status.char_id == sd->status.partner_id || - dstsd->status.char_id == sd->status.child - )) { - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,8); - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } + int bonus = 25 + 10 * skill_lv; + bonus += (pc->checkskill(sd, SA_FLAMELAUNCHER)+pc->checkskill(sd, SA_FROSTWEAPON)+pc->checkskill(sd, SA_LIGHTNINGLOADER)+pc->checkskill(sd, SA_SEISMICWEAPON))*5; + clif->skill_nodamage( src, bl, skill_id, skill_lv, + battle->check_target(src,bl,BCT_PARTY) > 0 ? + sc_start2(bl, type, 100, skill_lv, bonus, skill->get_time(skill_id,skill_lv)) : + 0 + ); } - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); break; - case SM_AUTOBERSERK: - case MER_AUTOBERSERK: - if( tsce ) - i = status_change_end(bl, type, INVALID_TIMER); + + case NPC_STOP: + if( clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)) ) ) + sc_start2(src,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)); + break; + case HP_ASSUMPTIO: + if( sd && dstmd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); else - i = sc_start(bl,type,100,skill_lv,60000); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case TF_HIDING: - case ST_CHASEWALK: - case KO_YAMIKUMO: - if (tsce) - { - clif->skill_nodamage(src,bl,skill_id,-1,status_change_end(bl, type, INVALID_TIMER)); //Hide skill-scream animation. - iMap->freeblock_unlock(); - return 0; - } else if( tsc && tsc->option&OPTION_MADOGEAR ) { - //Mado Gear cannot hide - if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 0; - } - clif->skill_nodamage(src,bl,skill_id,-1,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + case MG_SIGHT: + case MER_SIGHT: + case AL_RUWACH: + case WZ_SIGHTBLASTER: + case NPC_WIDESIGHT: + case NPC_STONESKIN: + case NPC_ANTIMAGIC: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl,type,100,skill_lv,skill_id,skill->get_time(skill_id,skill_lv))); break; - case TK_RUN: - if (tsce) + case HLIF_AVOID: + case HAMI_DEFENCE: + i = skill->get_time(skill_id,skill_lv); + clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,i)); // Master + clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,type,100,skill_lv,i)); // Homunc + break; + case NJ_BUNSINJYUTSU: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + status_change_end(bl, SC_NJ_NEN, INVALID_TIMER); + break; + /* Was modified to only affect targetted char. [Skotlex] + case HP_ASSUMPTIO: + if (flag&1) + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else { - clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); - return 0; + iMap->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv), BL_PC, + src, skill_id, skill_lv, tick, flag|BCT_ALL|1, + skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,0)); - if (sd) // If the client receives a skill-use packet inmediately before a walkok packet, it will discard the walk packet! [Skotlex] - clif->walkok(sd); // So aegis has to resend the walk ok. break; - case AS_CLOAKING: - case GC_CLOAKINGEXCEED: - case LG_FORCEOFVANGUARD: - case SC_REPRODUCE: - case SC_INVISIBILITY: - if (tsce) { - i = status_change_end(bl, type, INVALID_TIMER); - if( i ) - clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); - else if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 0; - } - case RA_CAMOUFLAGE: - i = sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - if( i ) - clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); - else if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + */ + case SM_ENDURE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if (sd) + skill->blockpc_start (sd, skill_id, skill->get_time2(skill_id,skill_lv), false); + break; + + case AS_ENCHANTPOISON: // Prevent spamming [Valaris] + if (sd && dstsd && dstsd->sc.count) { + if (dstsd->sc.data[SC_PROPERTYFIRE] || + dstsd->sc.data[SC_PROPERTYWATER] || + dstsd->sc.data[SC_PROPERTYWIND] || + dstsd->sc.data[SC_PROPERTYGROUND] || + dstsd->sc.data[SC_PROPERTYDARK] || + dstsd->sc.data[SC_PROPERTYTELEKINESIS] + // dstsd->sc.data[SC_ENCHANTPOISON] //People say you should be able to recast to lengthen the timer. [Skotlex] + ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - case BD_ADAPTATION: - if(tsc && tsc->data[SC_DANCING]){ - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_change_end(bl, SC_DANCING, INVALID_TIMER); - } + case LK_TENSIONRELAX: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,type,100,skill_lv,0,0,skill->get_time2(skill_id,skill_lv), + skill->get_time(skill_id,skill_lv))); break; - case BA_FROSTJOKER: - case DC_SCREAM: + case MC_CHANGECART: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->addtimerskill(src,tick+2000,bl->id,src->x,src->y,skill_id,skill_lv,0,flag); - - if (md) { - // custom hack to make the mob display the skill, because these skills don't show the skill use text themselves - //NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches) - char temp[70]; - snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill_db[skill_id].desc); - clif->disp_overhead(&md->bl,temp); - } break; - case BA_PANGVOICE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,50,7,skill->get_time(skill_id,skill_lv))); + case TK_MISSION: + if (sd) { + int id; + if (sd->mission_mobid && (sd->mission_count || rnd()%100)) { //Cannot change target when already have one + clif->mission_info(sd, sd->mission_mobid, sd->mission_count); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + id = mob_get_random_id(0,0xF, sd->status.base_level); + if (!id) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + sd->mission_mobid = id; + sd->mission_count = 0; + pc_setglobalreg(sd,"TK_MISSION_ID", id); + clif->mission_info(sd, id, 0); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } break; - case DC_WINKCHARM: - if( dstsd ) - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,30,7,skill->get_time2(skill_id,skill_lv))); - else - if( dstmd ) + case AC_CONCENTRATION: { - if( status_get_lv(src) > status_get_lv(bl) - && (tstatus->race == RC_DEMON || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_ANGEL) - && !(tstatus->mode&MD_BOSS) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start2(bl,type,70,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); - else - { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + iMap->foreachinrange( status_change_timer_sub, src, + skill->get_splash(skill_id, skill_lv), BL_CHAR, + src,NULL,type,tick); } break; - case TF_STEAL: - if(sd) { - if(pc->steal_item(sd,bl,skill_lv)) - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); + case SM_PROVOKE: + case SM_SELFPROVOKE: + case MER_PROVOKE: + if( (tstatus->mode&MD_BOSS) || battle->check_undead(tstatus->race,tstatus->def_ele) ) + { + iMap->freeblock_unlock(); + return 1; } - break; + //TODO: How much does base level affects? Dummy value of 1% per level difference used. [Skotlex] + clif->skill_nodamage(src,bl,skill_id == SM_SELFPROVOKE ? SM_PROVOKE : skill_id,skill_lv, + (i = sc_start(bl,type, skill_id == SM_SELFPROVOKE ? 100:( 50 + 3*skill_lv + status_get_lv(src) - status_get_lv(bl)), skill_lv, skill->get_time(skill_id,skill_lv)))); + if( !i ) + { + if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; + } + unit_skillcastcancel(bl, 2); - case RG_STEALCOIN: - if(sd) { - if(pc->steal_coin(sd,bl)) - { - dstmd->state.provoke_flag = src->id; - mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if( tsc && tsc->count ) + { + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + if( tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE ) + status_change_end(bl, SC_STONE, INVALID_TIMER); + status_change_end(bl, SC_SLEEP, INVALID_TIMER); + status_change_end(bl, SC_TRICKDEAD, INVALID_TIMER); + } - } - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if( dstmd ) + { + dstmd->state.provoke_flag = src->id; + mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); } break; - case MG_STONECURSE: + case ML_DEVOTION: + case CR_DEVOTION: { - int brate = 0; - if (tstatus->mode&MD_BOSS) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + int count, lv; + if( !dstsd || (!sd && !mer) ) + { // Only players can be devoted + if( sd ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; } - if(status_isimmune(bl) || !tsc) - break; - if (sd && sd->sc.data[SC_PETROLOGY_OPTION]) - brate = sd->sc.data[SC_PETROLOGY_OPTION]->val3; - - if (tsc->data[SC_STONE]) { - status_change_end(bl, SC_STONE, INVALID_TIMER); - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + if( (lv = status_get_lv(src) - dstsd->status.base_level) < 0 ) + lv = -lv; + if( lv > battle_config.devotion_level_difference || // Level difference requeriments + (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || // Cannot Devote a player devoted from another source + (skill_id == ML_DEVOTION && (!mer || mer != dstsd->md)) || // Mercenary only can devote owner + (dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER || // Crusader Cannot be devoted + (dstsd->sc.data[SC_HELLPOWER])) // Players affected by SC_HELLPOWERR cannot be devoted. + { + if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; } - if (sc_start4(bl,SC_STONE,(skill_lv*4+20)+brate, - skill_lv, 0, 0, skill->get_time(skill_id, skill_lv), - skill->get_time2(skill_id,skill_lv))) - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - else if(sd) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - // Level 6-10 doesn't consume a red gem if it fails [celest] - if (skill_lv > 5) - { // not to consume items - iMap->freeblock_unlock(); - return 0; + + i = 0; + count = (sd)? min(skill_lv,5) : 1; // Mercenary only can Devote owner + if( sd ) + { // Player Devoting Player + ARR_FIND(0, count, i, sd->devotion[i] == bl->id ); + if( i == count ) + { + ARR_FIND(0, count, i, sd->devotion[i] == 0 ); + if( i == count ) + { // No free slots, skill Fail + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + iMap->freeblock_unlock(); + return 1; + } } + + sd->devotion[i] = bl->id; } + else + mer->devotion_flag = 1; // Mercenary Devoting Owner + + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start4(bl, type, 100, src->id, i, skill->get_range2(src,skill_id,skill_lv),0, skill->get_time2(skill_id, skill_lv))); + clif->devotion(src, NULL); } break; - case NV_FIRSTAID: - clif->skill_nodamage(src,bl,skill_id,5,1); - status_heal(bl,5,0,0); + case MO_CALLSPIRITS: + if(sd) { + int limit = skill_lv; + if( sd->sc.data[SC_RAISINGDRAGON] ) + limit += sd->sc.data[SC_RAISINGDRAGON]->val1; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),limit); + } break; - case AL_CURE: - if(status_isimmune(bl)) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - break; + case CH_SOULCOLLECT: + if(sd) { + int limit = 5; + if( sd->sc.data[SC_RAISINGDRAGON] ) + limit += sd->sc.data[SC_RAISINGDRAGON]->val1; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + for (i = 0; i < limit; i++) + pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),limit); } - status_change_end(bl, SC_SILENCE, INVALID_TIMER); - status_change_end(bl, SC_BLIND, INVALID_TIMER); - status_change_end(bl, SC_CONFUSION, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; - case TF_DETOXIFY: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_change_end(bl, SC_POISON, INVALID_TIMER); - status_change_end(bl, SC_DPOISON, INVALID_TIMER); + case MO_KITRANSLATION: + if(dstsd && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) { + pc->addspiritball(dstsd,skill->get_time(skill_id,skill_lv),5); + } break; - case PR_STRECOVERY: - if(status_isimmune(bl)) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); - break; + case TK_TURNKICK: + case MO_BALKYOUNG: //Passive part of the attack. Splash knock-back+stun. [Skotlex] + if (skill_area_temp[1] != bl->id) { + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),-1,0); + skill->additional_effect(src,bl,skill_id,skill_lv,BF_MISC,ATK_DEF,tick); //Use Misc rather than weapon to signal passive pushback } - if (tsc && tsc->opt1) { - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_STONE, INVALID_TIMER); - status_change_end(bl, SC_SLEEP, INVALID_TIMER); - status_change_end(bl, SC_STUN, INVALID_TIMER); - status_change_end(bl, SC_WHITEIMPRISON, INVALID_TIMER); + break; + + case MO_ABSORBSPIRITS: + i = 0; + if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) + { // split the if for readability, and included gunslingers in the check so that their coins cannot be removed [Reddozen] + i = dstsd->spiritball * 7; + pc->delspiritball(dstsd,dstsd->spiritball,0); + } else if (dstmd && !(tstatus->mode&MD_BOSS) && rnd() % 100 < 20) + { // check if target is a monster and not a Boss, for the 20% chance to absorb 2 SP per monster's level [Reddozen] + i = 2 * dstmd->level; + mob_target(dstmd,src,0); } - //Is this equation really right? It looks so... special. - if( battle->check_undead(tstatus->race,tstatus->def_ele) ) { - status_change_start(bl, SC_BLIND, - 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), - 1,0,0,0, - skill->get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,0); + if (i) status_heal(src, 0, i, 3); + clif->skill_nodamage(src,bl,skill_id,skill_lv,i?1:0); + break; + + case AC_MAKINGARROW: + if(sd) { + clif->arrow_create_list(sd); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(dstmd) - mob_unlocktarget(dstmd,tick); break; - // Mercenary Supportive Skills - case MER_BENEDICTION: - status_change_end(bl, SC_CURSE, INVALID_TIMER); - status_change_end(bl, SC_BLIND, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case AM_PHARMACY: + if(sd) { + clif->skill_produce_mix_list(sd,skill_id,22); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } break; - case MER_COMPRESS: - status_change_end(bl, SC_BLEEDING, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + + case SA_CREATECON: + if(sd) { + clif->elementalconverter_list(sd); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } break; - case MER_MENTALCURE: - status_change_end(bl, SC_CONFUSION, INVALID_TIMER); + + case BS_HAMMERFALL: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,SC_STUN,(20 + 10 * skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv))); + break; + case RG_RAID: + skill_area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv), splash_target(src), + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, + skill->castend_damage_id); + status_change_end(src, SC_HIDING, INVALID_TIMER); break; - case MER_RECUPERATE: - status_change_end(bl, SC_POISON, INVALID_TIMER); - status_change_end(bl, SC_SILENCE, INVALID_TIMER); + + case ASC_METEORASSAULT: + case GS_SPREADATTACK: + case RK_STORMBLAST: + case NC_AXETORNADO: + case GC_COUNTERSLASH: + case SR_SKYNETBLOW: + case SR_RAMPAGEBLASTER: + case SR_HOWLINGOFLION: + case KO_HAPPOKUNAI: + skill_area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + i = iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); + if( !i && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) ) + clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; - case MER_REGAIN: - status_change_end(bl, SC_SLEEP, INVALID_TIMER); - status_change_end(bl, SC_STUN, INVALID_TIMER); + + case NC_EMERGENCYCOOL: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(src,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER); + status_change_end(src,SC_OVERHEAT,INVALID_TIMER); break; - case MER_TENDER: - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_STONE, INVALID_TIMER); + case SR_WINDMILL: + case GN_CART_TORNADO: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case SR_EARTHSHAKER: + case NC_INFRAREDSCAN: + case NPC_EARTHQUAKE: + case NPC_VAMPIRE_GIFT: + case NPC_HELLJUDGEMENT: + case NPC_PULSESTRIKE: + case LG_MOONSLASHER: + skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); break; - case MER_SCAPEGOAT: - if( mer && mer->master ) - { - status_heal(&mer->master->bl, mer->battle_status.hp, 0, 2); - status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1); - } + case KN_BRANDISHSPEAR: + case ML_BRANDISH: + skill->brandishspear(src, bl, skill_id, skill_lv, tick, flag); break; - case MER_ESTIMATION: - if( !mer ) - break; - sd = mer->master; - case WZ_ESTIMATION: - if( sd == NULL ) - break; - if( dstsd ) - { // Fail on Players - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) - break; // Cannot be Used on Emperium - - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - clif->skill_estimation(sd, bl); - if( skill_id == MER_ESTIMATION ) - sd = NULL; + case WZ_SIGHTRASHER: + //Passive side of the attack. + status_change_end(src, SC_SIGHT, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub,src, + skill->get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, + skill->castend_damage_id); break; - case BS_REPAIRWEAPON: - if(sd && dstsd) - clif->item_repair_list(sd,dstsd,skill_lv); + case NJ_HYOUSYOURAKU: + case NJ_RAIGEKISAI: + case WZ_FROSTNOVA: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill_area_temp[1] = 0; + iMap->foreachinrange(skill->attack_area, src, + skill->get_splash(skill_id, skill_lv), splash_target(src), + BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; - case MC_IDENTIFY: - if(sd) { - clif->item_identify_list(sd); - if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, dont consume anything, return */ - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->freeblock_unlock(); - return 1; - } - status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded - } + case HVAN_EXPLOSION: //[orn] + case NPC_SELFDESTRUCTION: + //Self Destruction hits everyone in range (allies+enemies) + //Except for Summoned Marine spheres on non-versus maps, where it's just enemy. + i = ((!md || md->special_state.ai == 2) && !map_flag_vs(src->m))? + BCT_ENEMY:BCT_ALL; + clif->skill_nodamage(src, src, skill_id, -1, 1); + iMap->delblock(src); //Required to prevent chain-self-destructions hitting back. + iMap->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv), splash_target(src), + src, skill_id, skill_lv, tick, flag|i, + skill->castend_damage_id); + iMap->addblock(src); + status_damage(src, src, sstatus->max_hp,0,0,1); break; - // Weapon Refining [Celest] - case WS_WEAPONREFINE: - if(sd) - clif->item_refine_list(sd); + case AL_ANGELUS: + case PR_MAGNIFICAT: + case PR_GLORIA: + case SN_WINDWALK: + case CASH_BLESSING: + case CASH_INCAGI: + case CASH_ASSUMPTIO: + case WM_FRIGG_SONG: + if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else if( sd ) + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - - case MC_VENDING: - if(sd) - { //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex] - if ( !pc->can_give_items(sd) ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - else { - sd->state.prevend = 1; - clif->openvendingreq(sd,2+skill_lv); - } + case MER_MAGNIFICAT: + if( mer != NULL ) + { + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if( mer->master && mer->master->status.party_id != 0 && !(flag&1) ) + party_foreachsamemap(skill->area_sub, mer->master, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + else if( mer->master && !(flag&1) ) + clif->skill_nodamage(src, &mer->master->bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } break; - case AL_TELEPORT: - if(sd) - { - if (map[bl->m].flag.noteleport && skill_lv <= 2) { - clif->skill_teleportmessage(sd,0); - break; - } - if(!battle_config.duel_allow_teleport && sd->duel_group && skill_lv <= 2) { // duel restriction [LuzZza] - char output[128]; sprintf(output, msg_txt(365), skill->get_name(AL_TELEPORT)); - clif->message(sd->fd, output); //"Duel: Can't use %s in duel." - break; - } - - if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1 ) || skill_lv == 3 ) - { - if( skill_lv == 1 ) - pc->randomwarp(sd,CLR_TELEPORT); - else - pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); - break; - } - - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if( skill_lv == 1 ) - clif->skill_warppoint(sd,skill_id,skill_lv, (unsigned short)-1,0,0,0); - else - clif->skill_warppoint(sd,skill_id,skill_lv, (unsigned short)-1,sd->status.save_point.map,0,0); - } else - unit_warp(bl,-1,-1,-1,CLR_TELEPORT); + case BS_ADRENALINE: + case BS_ADRENALINE2: + case BS_WEAPONPERFECT: + case BS_OVERTHRUST: + if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) { + clif->skill_nodamage(bl,bl,skill_id,skill_lv, + sc_start2(bl,type,100,skill_lv,(src == bl)? 1:0,skill->get_time(skill_id,skill_lv))); + } else if (sd) { + party_foreachsamemap(skill->area_sub, + sd,skill->get_splash(skill_id, skill_lv), + src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, + skill->castend_nodamage_id); + } break; - case NPC_EXPULSION: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_warp(bl,-1,-1,-1,CLR_TELEPORT); + case BS_MAXIMIZE: + case NV_TRICKDEAD: + case CR_DEFENDER: + case ML_DEFENDER: + case CR_AUTOGUARD: + case ML_AUTOGUARD: + case TK_READYSTORM: + case TK_READYDOWN: + case TK_READYTURN: + case TK_READYCOUNTER: + case TK_DODGE: + case CR_SHRINK: + case SG_FUSION: + case GS_GATLINGFEVER: + if( tsce ) + { + clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); + iMap->freeblock_unlock(); + return 0; + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - - case AL_HOLYWATER: - if(sd) { - if (skill->produce_mix(sd, skill_id, 523, 0, 0, 0, 1)) - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - else + case SL_KAITE: + case SL_KAAHI: + case SL_KAIZEL: + case SL_KAUPE: + if (sd) { + if (!dstsd || !( + (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SOULLINKER) || + (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER || + dstsd->status.char_id == sd->status.char_id || + dstsd->status.char_id == sd->status.partner_id || + dstsd->status.char_id == sd->status.child + )) { + status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,8); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - } - break; - - case TF_PICKSTONE: - if(sd) { - int eflag; - struct item item_tmp; - struct block_list tbl; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - memset(&item_tmp,0,sizeof(item_tmp)); - memset(&tbl,0,sizeof(tbl)); // [MouseJstr] - item_tmp.nameid = ITEMID_STONE; - item_tmp.identify = 1; - tbl.id = 0; - clif->takeitem(&sd->bl,&tbl); - eflag = pc->additem(sd,&item_tmp,1,LOG_TYPE_PRODUCE); - if(eflag) { - clif->additem(sd,0,0,eflag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + break; } } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); break; - case ASC_CDP: - if(sd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->produce_mix(sd, skill_id, 678, 0, 0, 0, 1); //Produce a Deadly Poison Bottle. - } + case SM_AUTOBERSERK: + case MER_AUTOBERSERK: + if( tsce ) + i = status_change_end(bl, type, INVALID_TIMER); + else + i = sc_start(bl,type,100,skill_lv,60000); + clif->skill_nodamage(src,bl,skill_id,skill_lv,i); break; - - case RG_STRIPWEAPON: - case RG_STRIPSHIELD: - case RG_STRIPARMOR: - case RG_STRIPHELM: - case ST_FULLSTRIP: - case GC_WEAPONCRUSH: - case SC_STRIPACCESSARY: { - unsigned short location = 0; - int d = 0; - - //Rate in percent - if ( skill_id == ST_FULLSTRIP ) { - i = 5 + 2*skill_lv + (sstatus->dex - tstatus->dex)/5; - } else if( skill_id == SC_STRIPACCESSARY ) { - i = 12 + 2 * skill_lv + (sstatus->dex - tstatus->dex)/5; - } else { - i = 5 + 5*skill_lv + (sstatus->dex - tstatus->dex)/5; - } - - if (i < 5) i = 5; //Minimum rate 5% - - //Duration in ms - if( skill_id == GC_WEAPONCRUSH){ - d = skill->get_time(skill_id,skill_lv); - if(bl->type == BL_PC) - d += skill_lv * 15 + (sstatus->dex - tstatus->dex); - else - d += skill_lv * 30 + (sstatus->dex - tstatus->dex) / 2; - }else - d = skill->get_time(skill_id,skill_lv) + (sstatus->dex - tstatus->dex)*500; - - if (d < 0) d = 0; //Minimum duration 0ms - - switch (skill_id) { - case RG_STRIPWEAPON: - case GC_WEAPONCRUSH: - location = EQP_WEAPON; - break; - case RG_STRIPSHIELD: - location = EQP_SHIELD; - break; - case RG_STRIPARMOR: - location = EQP_ARMOR; - break; - case RG_STRIPHELM: - location = EQP_HELM; - break; - case ST_FULLSTRIP: - location = EQP_WEAPON|EQP_SHIELD|EQP_ARMOR|EQP_HELM; - break; - case SC_STRIPACCESSARY: - location = EQP_ACC; - break; + case TF_HIDING: + case ST_CHASEWALK: + case KO_YAMIKUMO: + if (tsce) + { + clif->skill_nodamage(src,bl,skill_id,-1,status_change_end(bl, type, INVALID_TIMER)); //Hide skill-scream animation. + iMap->freeblock_unlock(); + return 0; + } else if( tsc && tsc->option&OPTION_MADOGEAR ) { + //Mado Gear cannot hide + if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; } - - //Special message when trying to use strip on FCP [Jobbie] - if( sd && skill_id == ST_FULLSTRIP && tsc && tsc->data[SC_CP_WEAPON] && tsc->data[SC_CP_HELM] && tsc->data[SC_CP_ARMOR] && tsc->data[SC_CP_SHIELD]) + clif->skill_nodamage(src,bl,skill_id,-1,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + break; + case TK_RUN: + if (tsce) { - clif->gospel_info(sd, 0x28); - break; + clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); + iMap->freeblock_unlock(); + return 0; } - - //Attempts to strip at rate i and duration d - if( (i = skill->strip_equip(bl, location, i, skill_lv, d)) || (skill_id != ST_FULLSTRIP && skill_id != GC_WEAPONCRUSH ) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); - - //Nothing stripped. - if( sd && !i ) + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,0)); + if (sd) // If the client receives a skill-use packet inmediately before a walkok packet, it will discard the walk packet! [Skotlex] + clif->walkok(sd); // So aegis has to resend the walk ok. + break; + case AS_CLOAKING: + case GC_CLOAKINGEXCEED: + case LG_FORCEOFVANGUARD: + case SC_REPRODUCE: + case SC_INVISIBILITY: + if (tsce) { + i = status_change_end(bl, type, INVALID_TIMER); + if( i ) + clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); + else if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; + } + case RA_CAMOUFLAGE: + i = sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + if( i ) + clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); + else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; - } - - case AM_BERSERKPITCHER: - case AM_POTIONPITCHER: { - int i,sp = 0; - int64 hp = 0; - if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) { - iMap->freeblock_unlock(); - return 1; - } - if( sd ) { - int x,bonus=100; - x = skill_lv%11 - 1; - i = pc->search_inventory(sd,skill_db[skill_id].itemid[x]); - if( i < 0 || skill_db[skill_id].itemid[x] <= 0 ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } - if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skill_id].amount[x]) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } - if( skill_id == AM_BERSERKPITCHER ) { - if( dstsd && dstsd->status.base_level < (unsigned int)sd->inventory_data[i]->elv ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } - } - potion_flag = 1; - potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; - potion_target = bl->id; - run_script(sd->inventory_data[i]->script,0,sd->bl.id,0); - potion_flag = potion_target = 0; - if( sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_ALCHEMIST ) - bonus += sd->status.base_level; - if( potion_per_hp > 0 || potion_per_sp > 0 ) { - hp = tstatus->max_hp * potion_per_hp / 100; - hp = hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - if( dstsd ) { - sp = dstsd->status.max_sp * potion_per_sp / 100; - sp = sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - } - } else { - if( potion_hp > 0 ) { - hp = potion_hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - hp = hp * (100 + (tstatus->vit<<1)) / 100; - if( dstsd ) - hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; - } - if( potion_sp > 0 ) { - sp = potion_sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - sp = sp * (100 + (tstatus->int_<<1)) / 100; - if( dstsd ) - sp = sp * (100 + pc->checkskill(dstsd,MG_SRECOVERY)*10) / 100; - } - } - - if (sd->itemgrouphealrate[IG_POTION]>0) { - hp += hp * sd->itemgrouphealrate[IG_POTION] / 100; - sp += sp * sd->itemgrouphealrate[IG_POTION] / 100; - } - if( (i = pc->skillheal_bonus(sd, skill_id)) ) { - hp += hp * i / 100; - sp += sp * i / 100; - } - } else { - hp = (1 + rnd()%400) * (100 + skill_lv*10) / 100; - hp = hp * (100 + (tstatus->vit<<1)) / 100; - if( dstsd ) - hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; - } - if( dstsd && (i = pc->skillheal2_bonus(dstsd, skill_id)) ) { - hp += hp * i / 100; - sp += sp * i / 100; - } - if( tsc && tsc->count ) { - if( tsc->data[SC_CRITICALWOUND] ) { - hp -= hp * tsc->data[SC_CRITICALWOUND]->val2 / 100; - sp -= sp * tsc->data[SC_CRITICALWOUND]->val2 / 100; - } - if( tsc->data[SC_DEATHHURT] ) { - hp -= hp * 20 / 100; - sp -= sp * 20 / 100; - } - if( tsc->data[SC_WATER_INSIGNIA] && tsc->data[SC_WATER_INSIGNIA]->val1 == 2 ) { - hp += hp / 10; - sp += sp / 10; - } - } + case BD_ADAPTATION: + if(tsc && tsc->data[SC_DANCING]){ clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if( hp > 0 || (skill_id == AM_POTIONPITCHER && sp <= 0) ) - clif->skill_nodamage(NULL,bl,AL_HEAL,(int)hp,1); - if( sp > 0 ) - clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); - #ifdef RENEWAL - if( tsc && tsc->data[SC_EXTREMITYFIST2] ) - sp = 0; - #endif - status_heal(bl,(int)hp,sp,0); + status_change_end(bl, SC_DANCING, INVALID_TIMER); } - break; - case AM_CP_WEAPON: - case AM_CP_SHIELD: - case AM_CP_ARMOR: - case AM_CP_HELM: - { - unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; + break; - if( sd && ( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[skill_id - AM_CP_WEAPON]) < 0 ) ) ){ - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); // Don't consume item requirements - return 0; - } + case BA_FROSTJOKER: + case DC_SCREAM: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill->addtimerskill(src,tick+2000,bl->id,src->x,src->y,skill_id,skill_lv,0,flag); - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if (md) { + // custom hack to make the mob display the skill, because these skills don't show the skill use text themselves + //NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches) + char temp[70]; + snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill_db[skill_id].desc); + clif->disp_overhead(&md->bl,temp); } break; - case AM_TWILIGHT1: - if (sd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - //Prepare 200 White Potions. - if (!skill->produce_mix(sd, skill_id, 504, 0, 0, 0, 200)) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + + case BA_PANGVOICE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,50,7,skill->get_time(skill_id,skill_lv))); + break; + + case DC_WINKCHARM: + if( dstsd ) + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,30,7,skill->get_time2(skill_id,skill_lv))); + else + if( dstmd ) + { + if( status_get_lv(src) > status_get_lv(bl) + && (tstatus->race == RC_DEMON || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_ANGEL) + && !(tstatus->mode&MD_BOSS) ) + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start2(bl,type,70,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); + else + { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } } break; - case AM_TWILIGHT2: - if (sd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - //Prepare 200 Slim White Potions. - if (!skill->produce_mix(sd, skill_id, 547, 0, 0, 0, 200)) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + + case TF_STEAL: + if(sd) { + if(pc->steal_item(sd,bl,skill_lv)) + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); } break; - case AM_TWILIGHT3: - if (sd) { - int ebottle = pc->search_inventory(sd,713); - if( ebottle >= 0 ) - ebottle = sd->status.inventory[ebottle].amount; - //check if you can produce all three, if not, then fail: - if (!skill->can_produce_mix(sd,970,-1, 100) //100 Alcohol - || !skill->can_produce_mix(sd,7136,-1, 50) //50 Acid Bottle - || !skill->can_produce_mix(sd,7135,-1, 50) //50 Flame Bottle - || ebottle < 200 //200 empty bottle are required at total. - ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + + case RG_STEALCOIN: + if(sd) { + if(pc->steal_coin(sd,bl)) + { + dstmd->state.provoke_flag = src->id; + mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->produce_mix(sd, skill_id, 970, 0, 0, 0, 100); - skill->produce_mix(sd, skill_id, 7136, 0, 0, 0, 50); - skill->produce_mix(sd, skill_id, 7135, 0, 0, 0, 50); + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - case SA_DISPELL: - if (flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1) + + case MG_STONECURSE: { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) - || (tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel. - || rnd()%100 >= 50+10*skill_lv - || ( tsc && tsc->option&OPTION_MADOGEAR ) )//Mado Gear is immune to dispell according to bug report 49 [Ind] - { - if (sd) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + int brate = 0; + if (tstatus->mode&MD_BOSS) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if(status_isimmune(bl) || !tsc || !tsc->count) + if(status_isimmune(bl) || !tsc) break; - - if( sd && dstsd && !map_flag_vs(sd->bl.m) && sd->status.guild_id == dstsd->status.guild_id ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + + if (sd && sd->sc.data[SC_PETROLOGY_OPTION]) + brate = sd->sc.data[SC_PETROLOGY_OPTION]->val3; + + if (tsc->data[SC_STONE]) { + status_change_end(bl, SC_STONE, INVALID_TIMER); + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - - for(i=0;idata[i]) - continue; - switch (i) { - case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION: - case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR: - case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD: - case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO: - case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD: - case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD: - case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD: - case SC_WATKFOOD: case SC_MATKFOOD: case SC_DANCING: - case SC_EDP: case SC_AUTOBERSERK: - case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL: - case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT: - case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED: - case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE: - case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL: - case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN: - case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN: - case SC_READYCOUNTER: case SC_DODGE: case SC_WARM: - case SC_SPEEDUP1: case SC_AUTOTRADE: case SC_CRITICALWOUND: - case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF: - case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF: - case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK: - case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS: - case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL: - case SC_INTOABYSS: case SC_SIEGFRIED: case SC_FOOD_STR_CASH: - case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: - case SC_FOOD_INT_CASH: case SC_FOOD_LUK_CASH: case SC_SEVENWIND: - case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION: - case SC_INCHEALRATE: case SC_ELECTRICSHOCKER: case SC__STRIPACCESSORY: - //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ: - //case SC_SIROMA_ICE_TEA: case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: - case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER: - case SC_STEALTHFIELD: case SC_GIANTGROWTH: case SC_MILLENNIUMSHIELD: - case SC_REFRESH: case SC_STONEHARDSKIN: case SC_VITALITYACTIVATION: - case SC_FIGHTINGSPIRIT: case SC_ABUNDANCE: case SC__SHADOWFORM: - case SC_LEADERSHIP: case SC_GLORYWOUNDS: case SC_SOULCOLD: - case SC_HAWKEYES: case SC_GUILDAURA: case SC_PUSH_CART: - case SC_RAISINGDRAGON: case SC_GT_ENERGYGAIN: case SC_GT_CHANGE: - case SC_GT_REVITALIZE: case SC_REFLECTDAMAGE: case SC_INSPIRATION: - case SC_EXEEDBREAK: case SC_FORCEOFVANGUARD: case SC_BANDING: - case SC_DUPLELIGHT: case SC_EXPIATIO: case SC_LAUDAAGNUS: - case SC_LAUDARAMUS: case SC_GATLINGFEVER: case SC_INCREASING: - case SC_ADJUSTMENT: case SC_MADNESSCANCEL: case SC_ALL_RIDING: - #ifdef RENEWAL - case SC_EXTREMITYFIST2: - #endif - continue; - /** - * bugreport:4888 these songs may only be dispelled if you're not in their song area anymore - **/ - case SC_WHISTLE: - case SC_ASSNCROS: - case SC_POEMBRAGI: - case SC_APPLEIDUN: - case SC_HUMMING: - case SC_DONTFORGETME: - case SC_FORTUNE: - case SC_SERVICE4U: - if( !tsc->data[i]->val4 ) //val4 = out-of-song-area - continue; - break; - case SC_ASSUMPTIO: - if( bl->type == BL_MOB ) - continue; - break; + if (sc_start4(bl,SC_STONE,(skill_lv*4+20)+brate, + skill_lv, 0, 0, skill->get_time(skill_id, skill_lv), + skill->get_time2(skill_id,skill_lv))) + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + else if(sd) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + // Level 6-10 doesn't consume a red gem if it fails [celest] + if (skill_lv > 5) + { // not to consume items + iMap->freeblock_unlock(); + return 0; } - if(i==SC_BERSERK || i==SC_SATURDAYNIGHTFEVER) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0. - status_change_end(bl, (sc_type)i, INVALID_TIMER); } + } + break; + + case NV_FIRSTAID: + clif->skill_nodamage(src,bl,skill_id,5,1); + status_heal(bl,5,0,0); + break; + + case AL_CURE: + if(status_isimmune(bl)) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + break; + } + status_change_end(bl, SC_SILENCE, INVALID_TIMER); + status_change_end(bl, SC_BLIND, INVALID_TIMER); + status_change_end(bl, SC_CONFUSION, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + + case TF_DETOXIFY: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(bl, SC_POISON, INVALID_TIMER); + status_change_end(bl, SC_DPOISON, INVALID_TIMER); + break; + + case PR_STRECOVERY: + if(status_isimmune(bl)) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + break; + } + if (tsc && tsc->opt1) { + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_STONE, INVALID_TIMER); + status_change_end(bl, SC_SLEEP, INVALID_TIMER); + status_change_end(bl, SC_STUN, INVALID_TIMER); + status_change_end(bl, SC_WHITEIMPRISON, INVALID_TIMER); + } + //Is this equation really right? It looks so... special. + if( battle->check_undead(tstatus->race,tstatus->def_ele) ) { + status_change_start(bl, SC_BLIND, + 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), + 1,0,0,0, + skill->get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,0); + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if(dstmd) + mob_unlocktarget(dstmd,tick); + break; + + // Mercenary Supportive Skills + case MER_BENEDICTION: + status_change_end(bl, SC_CURSE, INVALID_TIMER); + status_change_end(bl, SC_BLIND, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case MER_COMPRESS: + status_change_end(bl, SC_BLOODING, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case MER_MENTALCURE: + status_change_end(bl, SC_CONFUSION, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case MER_RECUPERATE: + status_change_end(bl, SC_POISON, INVALID_TIMER); + status_change_end(bl, SC_SILENCE, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case MER_REGAIN: + status_change_end(bl, SC_SLEEP, INVALID_TIMER); + status_change_end(bl, SC_STUN, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + case MER_TENDER: + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_STONE, INVALID_TIMER); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + + case MER_SCAPEGOAT: + if( mer && mer->master ) + { + status_heal(&mer->master->bl, mer->battle_status.hp, 0, 2); + status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1); + } + break; + + case MER_ESTIMATION: + if( !mer ) + break; + sd = mer->master; + case WZ_ESTIMATION: + if( sd == NULL ) + break; + if( dstsd ) + { // Fail on Players + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - //Affect all targets on splash area. - iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|1, - skill->castend_damage_id); + if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) + break; // Cannot be Used on Emperium + + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + clif->skill_estimation(sd, bl); + if( skill_id == MER_ESTIMATION ) + sd = NULL; + break; + + case BS_REPAIRWEAPON: + if(sd && dstsd) + clif->item_repair_list(sd,dstsd,skill_lv); + break; + + case MC_IDENTIFY: + if(sd) { + clif->item_identify_list(sd); + if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, dont consume anything, return */ + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->freeblock_unlock(); + return 1; + } + status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded + } + break; + + // Weapon Refining [Celest] + case WS_WEAPONREFINE: + if(sd){ + sd->state.prerefining = 1; + clif->item_refine_list(sd); + } break; - case TF_BACKSLIDING: //This is the correct implementation as per packet logging information. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); + case MC_VENDING: + if(sd) + { //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex] + if ( !pc->can_give_items(sd) ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + else { + sd->state.prevend = sd->state.workinprogress = 3; + clif->openvendingreq(sd,2+skill_lv); + } + } break; - case TK_HIGHJUMP: + case AL_TELEPORT: + if(sd) { - int x,y, dir = unit_getdir(src); - - //Fails on noteleport maps, except for GvG and BG maps [Skotlex] - if( map[src->m].flag.noteleport && - !(map[src->m].flag.battleground || map_flag_gvg2(src->m) ) - ) { - x = src->x; - y = src->y; - } else { - x = src->x + dirx[dir]*skill_lv*2; - y = src->y + diry[dir]*skill_lv*2; + if (map[bl->m].flag.noteleport && skill_lv <= 2) { + clif->skill_mapinfomessage(sd,0); + break; + } + if(!battle_config.duel_allow_teleport && sd->duel_group && skill_lv <= 2) { // duel restriction [LuzZza] + char output[128]; sprintf(output, msg_txt(365), skill->get_name(AL_TELEPORT)); + clif->message(sd->fd, output); //"Duel: Can't use %s in duel." + break; } - clif->skill_nodamage(src,bl,TK_HIGHJUMP,skill_lv,1); - if(!iMap->count_oncell(src->m,x,y,BL_PC|BL_NPC|BL_MOB) && iMap->getcell(src->m,x,y,CELL_CHKREACH)) { - clif->slide(src,x,y); - unit_movepos(src, x, y, 1, 0); + if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1 ) || skill_lv == 3 ) + { + if( skill_lv == 1 ) + pc->randomwarp(sd,CLR_TELEPORT); + else + pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); + break; } - } + + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if( skill_lv == 1 ) + clif->skill_warppoint(sd,skill_id,skill_lv, (unsigned short)-1,0,0,0); + else + clif->skill_warppoint(sd,skill_id,skill_lv, (unsigned short)-1,sd->status.save_point.map,0,0); + } else + unit_warp(bl,-1,-1,-1,CLR_TELEPORT); break; - case SA_CASTCANCEL: - case SO_SPELLFIST: + case NPC_EXPULSION: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_skillcastcancel(src,1); - if(sd) { - int sp = skill->get_sp(sd->skill_id_old,sd->skill_lv_old); - if( skill_id == SO_SPELLFIST ){ - sc_start4(src,type,100,skill_lv+1,skill_lv,sd->skill_id_old,sd->skill_lv_old,skill->get_time(skill_id,skill_lv)); - sd->skill_id_old = sd->skill_lv_old = 0; - break; - } - sp = sp * (90 - (skill_lv-1)*20) / 100; - if(sp < 0) sp = 0; - status_zap(src, 0, sp); - } + unit_warp(bl,-1,-1,-1,CLR_TELEPORT); break; - case SA_SPELLBREAKER: - { - int sp; - if(tsc && tsc->data[SC_MAGICROD]) { - sp = skill->get_sp(skill_id,skill_lv); - sp = sp * tsc->data[SC_MAGICROD]->val2 / 100; - if(sp < 1) sp = 1; - status_heal(bl,0,sp,2); - status_percent_damage(bl, src, 0, -20, false); //20% max SP damage. - } else { - struct unit_data *ud = unit_bl2ud(bl); - int bl_skill_id=0,bl_skill_lv=0,hp = 0; - if (!ud || ud->skilltimer == INVALID_TIMER) - break; //Nothing to cancel. - bl_skill_id = ud->skill_id; - bl_skill_lv = ud->skill_lv; - if (tstatus->mode & MD_BOSS) - { //Only 10% success chance against bosses. [Skotlex] - if (rnd()%100 < 90) - { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - } else if (!dstsd || map_flag_vs(bl->m)) //HP damage only on pvp-maps when against players. - hp = tstatus->max_hp/50; //Recover 2% HP [Skotlex] + case AL_HOLYWATER: + if(sd) { + if (skill->produce_mix(sd, skill_id, 523, 0, 0, 0, 1)) clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_skillcastcancel(bl,0); - sp = skill->get_sp(bl_skill_id,bl_skill_lv); - status_zap(bl, hp, sp); - - if (hp && skill_lv >= 5) - hp>>=1; //Recover half damaged HP at level 5 [Skotlex] - else - hp = 0; - - if (sp) //Recover some of the SP used - sp = sp*(25*(skill_lv-1))/100; - - if(hp || sp) - status_heal(src, hp, sp, 2); - } + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - case SA_MAGICROD: - clif->skill_nodamage(src,src,SA_MAGICROD,skill_lv,1); - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - break; - case SA_AUTOSPELL: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd) - clif->autospell(sd,skill_lv); - else { - int maxlv=1,spellid=0; - static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT }; - if(skill_lv >= 10) { - spellid = MG_FROSTDIVER; - // if (tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SA_SAGE) - // maxlv = 10; - // else - maxlv = skill_lv - 9; - } - else if(skill_lv >=8) { - spellid = MG_FIREBALL; - maxlv = skill_lv - 7; - } - else if(skill_lv >=5) { - spellid = MG_SOULSTRIKE; - maxlv = skill_lv - 4; - } - else if(skill_lv >=2) { - int i = rnd()%3; - spellid = spellarray[i]; - maxlv = skill_lv - 1; - } - else if(skill_lv > 0) { - spellid = MG_NAPALMBEAT; - maxlv = 3; + + case TF_PICKSTONE: + if(sd) { + int eflag; + struct item item_tmp; + struct block_list tbl; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + memset(&item_tmp,0,sizeof(item_tmp)); + memset(&tbl,0,sizeof(tbl)); // [MouseJstr] + item_tmp.nameid = ITEMID_STONE; + item_tmp.identify = 1; + tbl.id = 0; + clif->takeitem(&sd->bl,&tbl); + eflag = pc->additem(sd,&item_tmp,1,LOG_TYPE_PRODUCE); + if(eflag) { + clif->additem(sd,0,0,eflag); + iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } - if(spellid > 0) - sc_start4(src,SC_AUTOSPELL,100,skill_lv,spellid,maxlv,0, - skill->get_time(SA_AUTOSPELL,skill_lv)); } break; - - case BS_GREED: - if(sd){ + case ASC_CDP: + if(sd) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->greed,bl, - skill->get_splash(skill_id, skill_lv),BL_ITEM,bl); + skill->produce_mix(sd, skill_id, 678, 0, 0, 0, 1); //Produce a Deadly Poison Bottle. } break; - case SA_ELEMENTWATER: - case SA_ELEMENTFIRE: - case SA_ELEMENTGROUND: - case SA_ELEMENTWIND: - if(sd && !dstmd) //Only works on monsters. + case RG_STRIPWEAPON: + case RG_STRIPSHIELD: + case RG_STRIPARMOR: + case RG_STRIPHELM: + case ST_FULLSTRIP: + case GC_WEAPONCRUSH: + case SC_STRIPACCESSARY: { + unsigned short location = 0; + int d = 0; + + //Rate in percent + if ( skill_id == ST_FULLSTRIP ) { + i = 5 + 2*skill_lv + (sstatus->dex - tstatus->dex)/5; + } else if( skill_id == SC_STRIPACCESSARY ) { + i = 12 + 2 * skill_lv + (sstatus->dex - tstatus->dex)/5; + } else { + i = 5 + 5*skill_lv + (sstatus->dex - tstatus->dex)/5; + } + + if (i < 5) i = 5; //Minimum rate 5% + + //Duration in ms + if( skill_id == GC_WEAPONCRUSH){ + d = skill->get_time(skill_id,skill_lv); + if(bl->type == BL_PC) + d += skill_lv * 15 + (sstatus->dex - tstatus->dex); + else + d += skill_lv * 30 + (sstatus->dex - tstatus->dex) / 2; + }else + d = skill->get_time(skill_id,skill_lv) + (sstatus->dex - tstatus->dex)*500; + + if (d < 0) d = 0; //Minimum duration 0ms + + switch (skill_id) { + case RG_STRIPWEAPON: + case GC_WEAPONCRUSH: + location = EQP_WEAPON; break; - if(tstatus->mode&MD_BOSS) + case RG_STRIPSHIELD: + location = EQP_SHIELD; break; - case NPC_ATTRICHANGE: - case NPC_CHANGEWATER: - case NPC_CHANGEGROUND: - case NPC_CHANGEFIRE: - case NPC_CHANGEWIND: - case NPC_CHANGEPOISON: - case NPC_CHANGEHOLY: - case NPC_CHANGEDARKNESS: - case NPC_CHANGETELEKINESIS: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), - skill->get_time(skill_id, skill_lv))); - break; - case NPC_CHANGEUNDEAD: - //This skill should fail if target is wearing bathory/evil druid card [Brainstorm] - //TO-DO This is ugly, fix it - if(tstatus->def_ele==ELE_UNDEAD || tstatus->def_ele==ELE_DARK) break; - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), - skill->get_time(skill_id, skill_lv))); - break; - - case NPC_PROVOCATION: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (md) mob_unlocktarget(md, tick); - break; + case RG_STRIPARMOR: + location = EQP_ARMOR; + break; + case RG_STRIPHELM: + location = EQP_HELM; + break; + case ST_FULLSTRIP: + location = EQP_WEAPON|EQP_SHIELD|EQP_ARMOR|EQP_HELM; + break; + case SC_STRIPACCESSARY: + location = EQP_ACC; + break; + } - case NPC_KEEPING: - case NPC_BARRIER: + //Special message when trying to use strip on FCP [Jobbie] + if( sd && skill_id == ST_FULLSTRIP && tsc && tsc->data[SC_PROTECTWEAPON] && tsc->data[SC_PROTECTHELM] && tsc->data[SC_PROTECTARMOR] && tsc->data[SC_PROTECTSHIELD]) { - int skill_time = skill->get_time(skill_id,skill_lv); - struct unit_data *ud = unit_bl2ud(bl); - if (clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill_time)) - && ud) { //Disable attacking/acting/moving for skill's duration. - ud->attackabletime = - ud->canact_tick = - ud->canmove_tick = tick + skill_time; - } + clif->gospel_info(sd, 0x28); + break; } - break; - case NPC_REBIRTH: - if( md && md->state.rebirth ) - break; // only works once - sc_start(bl,type,100,skill_lv,-1); - break; + //Attempts to strip at rate i and duration d + if( (i = skill->strip_equip(bl, location, i, skill_lv, d)) || (skill_id != ST_FULLSTRIP && skill_id != GC_WEAPONCRUSH ) ) + clif->skill_nodamage(src,bl,skill_id,skill_lv,i); - case NPC_DARKBLESSING: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,(50+skill_lv*5),skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv))); + //Nothing stripped. + if( sd && !i ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; + } - case NPC_LICK: - status_zap(bl, 0, 100); - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,(skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv))); - break; + case AM_BERSERKPITCHER: + case AM_POTIONPITCHER: { + int i,sp = 0; + int64 hp = 0; + if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) { + iMap->freeblock_unlock(); + return 1; + } + if( sd ) { + int x,bonus=100; + x = skill_lv%11 - 1; + i = pc->search_inventory(sd,skill_db[skill_id].itemid[x]); + if( i < 0 || skill_db[skill_id].itemid[x] <= 0 ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; + } + if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skill_id].amount[x]) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; + } + if( skill_id == AM_BERSERKPITCHER ) { + if( dstsd && dstsd->status.base_level < (unsigned int)sd->inventory_data[i]->elv ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; + } + } + potion_flag = 1; + potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; + potion_target = bl->id; + run_script(sd->inventory_data[i]->script,0,sd->bl.id,0); + potion_flag = potion_target = 0; + if( sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ALCHEMIST ) + bonus += sd->status.base_level; + if( potion_per_hp > 0 || potion_per_sp > 0 ) { + hp = tstatus->max_hp * potion_per_hp / 100; + hp = hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + if( dstsd ) { + sp = dstsd->status.max_sp * potion_per_sp / 100; + sp = sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + } + } else { + if( potion_hp > 0 ) { + hp = potion_hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + hp = hp * (100 + (tstatus->vit<<1)) / 100; + if( dstsd ) + hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( potion_sp > 0 ) { + sp = potion_sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + sp = sp * (100 + (tstatus->int_<<1)) / 100; + if( dstsd ) + sp = sp * (100 + pc->checkskill(dstsd,MG_SRECOVERY)*10) / 100; + } + } - case NPC_SUICIDE: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_kill(src); //When suiciding, neither exp nor drops is given. - break; + if (sd->itemgrouphealrate[IG_POTION]>0) { + hp += hp * sd->itemgrouphealrate[IG_POTION] / 100; + sp += sp * sd->itemgrouphealrate[IG_POTION] / 100; + } - case NPC_SUMMONSLAVE: - case NPC_SUMMONMONSTER: - if(md && md->skill_idx >= 0) - mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv,skill_id); + if( (i = pc->skillheal_bonus(sd, skill_id)) ) { + hp += hp * i / 100; + sp += sp * i / 100; + } + } else { + hp = (1 + rnd()%400) * (100 + skill_lv*10) / 100; + hp = hp * (100 + (tstatus->vit<<1)) / 100; + if( dstsd ) + hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( dstsd && (i = pc->skillheal2_bonus(dstsd, skill_id)) ) { + hp += hp * i / 100; + sp += sp * i / 100; + } + if( tsc && tsc->count ) { + if( tsc->data[SC_CRITICALWOUND] ) { + hp -= hp * tsc->data[SC_CRITICALWOUND]->val2 / 100; + sp -= sp * tsc->data[SC_CRITICALWOUND]->val2 / 100; + } + if( tsc->data[SC_DEATHHURT] ) { + hp -= hp * 20 / 100; + sp -= sp * 20 / 100; + } + if( tsc->data[SC_WATER_INSIGNIA] && tsc->data[SC_WATER_INSIGNIA]->val1 == 2 ) { + hp += hp / 10; + sp += sp / 10; + } + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if( hp > 0 || (skill_id == AM_POTIONPITCHER && sp <= 0) ) + clif->skill_nodamage(NULL,bl,AL_HEAL,(int)hp,1); + if( sp > 0 ) + clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); + #ifdef RENEWAL + if( tsc && tsc->data[SC_EXTREMITYFIST2] ) + sp = 0; + #endif + status_heal(bl,(int)hp,sp,0); + } break; + case AM_CP_WEAPON: + case AM_CP_SHIELD: + case AM_CP_ARMOR: + case AM_CP_HELM: + { + unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; - case NPC_CALLSLAVE: - mob_warpslave(src,MOB_SLAVEDISTANCE); - break; + if( sd && ( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[skill_id - AM_CP_WEAPON]) < 0 ) ) ){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); // Don't consume item requirements + return 0; + } - case NPC_RANDOMMOVE: - if (md) { - md->next_walktime = tick - 1; - mob_randomwalk(md,tick); + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } break; - - case NPC_SPEEDUP: - { - // or does it increase casting rate? just a guess xD - int i = SC_ASPDPOTION0 + skill_lv - 1; - if (i > SC_ASPDPOTION3) - i = SC_ASPDPOTION3; - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,(sc_type)i,100,skill_lv,skill_lv * 60000)); + case AM_TWILIGHT1: + if (sd) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + //Prepare 200 White Potions. + if (!skill->produce_mix(sd, skill_id, 504, 0, 0, 0, 200)) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - - case NPC_REVENGE: - // not really needed... but adding here anyway ^^ - if (md && md->master_id > 0) { - struct block_list *mbl, *tbl; - if ((mbl = iMap->id2bl(md->master_id)) == NULL || - (tbl = battle->get_targeted(mbl)) == NULL) + case AM_TWILIGHT2: + if (sd) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + //Prepare 200 Slim White Potions. + if (!skill->produce_mix(sd, skill_id, 547, 0, 0, 0, 200)) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } + break; + case AM_TWILIGHT3: + if (sd) { + int ebottle = pc->search_inventory(sd,713); + if( ebottle >= 0 ) + ebottle = sd->status.inventory[ebottle].amount; + //check if you can produce all three, if not, then fail: + if (!skill->can_produce_mix(sd,970,-1, 100) //100 Alcohol + || !skill->can_produce_mix(sd,7136,-1, 50) //50 Acid Bottle + || !skill->can_produce_mix(sd,7135,-1, 50) //50 Flame Bottle + || ebottle < 200 //200 empty bottle are required at total. + ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; - md->state.provoke_flag = tbl->id; - mob_target(md, tbl, sstatus->rhw.range); + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill->produce_mix(sd, skill_id, 970, 0, 0, 0, 100); + skill->produce_mix(sd, skill_id, 7136, 0, 0, 0, 50); + skill->produce_mix(sd, skill_id, 7135, 0, 0, 0, 50); } break; - - case NPC_RUN: + case SA_DISPELL: + if (flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1) { - const int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}}; - uint8 dir = (bl == src)?unit_getdir(src):iMap->calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away. - unit_stop_attack(src); - //Run skillv tiles overriding the can-move check. - if (unit_walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md) - md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the ai. + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) + || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel. + || rnd()%100 >= 50+10*skill_lv ) + { + if (sd) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + if(status_isimmune(bl) || !tsc || !tsc->count) + break; + + if( sd && dstsd && !map_flag_vs(sd->bl.m) && sd->status.guild_id == dstsd->status.guild_id ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + + for(i = 0; i < SC_MAX; i++) + { + if ( !tsc->data[i] ) + continue; + if( SC_COMMON_MAX < i ){ + if ( status_get_sc_type(i)&SC_NO_DISPELL ) + continue; + } + switch (i) { + /** + * bugreport:4888 these songs may only be dispelled if you're not in their song area anymore + **/ + case SC_WHISTLE: + case SC_ASSNCROS: + case SC_POEMBRAGI: + case SC_APPLEIDUN: + case SC_HUMMING: + case SC_DONTFORGETME: + case SC_FORTUNE: + case SC_SERVICEFORYOU: + if( tsc->data[i]->val4 ) //val4 = out-of-song-area + continue; + break; + case SC_ASSUMPTIO: + if( bl->type == BL_MOB ) + continue; + break; + case SC_BERSERK: + case SC_SATURDAY_NIGHT_FEVER: + tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0. + break; + } + status_change_end(bl, (sc_type)i, INVALID_TIMER); + } + break; } + //Affect all targets on splash area. + iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, + src, skill_id, skill_lv, tick, flag|1, + skill->castend_damage_id); break; - case NPC_TRANSFORMATION: - case NPC_METAMORPHOSIS: - if(md && md->skill_idx >= 0) { - int class_ = mob_random_class (md->db->skill[md->skill_idx].val,0); - if (skill_lv > 1) //Multiply the rest of mobs. [Skotlex] - mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv-1,skill_id); - if (class_) mob_class_change(md, class_); - } + case TF_BACKSLIDING: //This is the correct implementation as per packet logging information. [Skotlex] + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); break; - case NPC_EMOTION_ON: - case NPC_EMOTION: - //val[0] is the emotion to use. - //NPC_EMOTION & NPC_EMOTION_ON can change a mob's mode 'permanently' [Skotlex] - //val[1] 'sets' the mode - //val[2] adds to the current mode - //val[3] removes from the current mode - //val[4] if set, asks to delete the previous mode change. - if(md && md->skill_idx >= 0 && tsc) { - clif->emotion(bl, md->db->skill[md->skill_idx].val[0]); - if(md->db->skill[md->skill_idx].val[4] && tsce) - status_change_end(bl, type, INVALID_TIMER); + case TK_HIGHJUMP: + { + int x,y, dir = unit_getdir(src); - //If mode gets set by NPC_EMOTION then the target should be reset [Playtester] - if(skill_id == NPC_EMOTION && md->db->skill[md->skill_idx].val[1]) - mob_unlocktarget(md,tick); - - if(md->db->skill[md->skill_idx].val[1] || md->db->skill[md->skill_idx].val[2]) - sc_start4(src, type, 100, skill_lv, - md->db->skill[md->skill_idx].val[1], - md->db->skill[md->skill_idx].val[2], - md->db->skill[md->skill_idx].val[3], - skill->get_time(skill_id, skill_lv)); + //Fails on noteleport maps, except for GvG and BG maps [Skotlex] + if( map[src->m].flag.noteleport && + !(map[src->m].flag.battleground || map_flag_gvg2(src->m) ) + ) { + x = src->x; + y = src->y; + } else { + x = src->x + dirx[dir]*skill_lv*2; + y = src->y + diry[dir]*skill_lv*2; + } + + clif->skill_nodamage(src,bl,TK_HIGHJUMP,skill_lv,1); + if(!iMap->count_oncell(src->m,x,y,BL_PC|BL_NPC|BL_MOB) && iMap->getcell(src->m,x,y,CELL_CHKREACH)) { + clif->slide(src,x,y); + unit_movepos(src, x, y, 1, 0); + } } break; - case NPC_POWERUP: - sc_start(bl,SC_INCATKRATE,100,200,skill->get_time(skill_id, skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); + case SA_CASTCANCEL: + case SO_SPELLFIST: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + unit_skillcastcancel(src,1); + if(sd) { + int sp = skill->get_sp(sd->skill_id_old,sd->skill_lv_old); + if( skill_id == SO_SPELLFIST ){ + sc_start4(src,type,100,skill_lv+1,skill_lv,sd->skill_id_old,sd->skill_lv_old,skill->get_time(skill_id,skill_lv)); + sd->skill_id_old = sd->skill_lv_old = 0; + break; + } + sp = sp * (90 - (skill_lv-1)*20) / 100; + if(sp < 0) sp = 0; + status_zap(src, 0, sp); + } break; + case SA_SPELLBREAKER: + { + int sp; + if(tsc && tsc->data[SC_MAGICROD]) { + sp = skill->get_sp(skill_id,skill_lv); + sp = sp * tsc->data[SC_MAGICROD]->val2 / 100; + if(sp < 1) sp = 1; + status_heal(bl,0,sp,2); + status_percent_damage(bl, src, 0, -20, false); //20% max SP damage. + } else { + struct unit_data *ud = unit_bl2ud(bl); + int bl_skill_id=0,bl_skill_lv=0,hp = 0; + if (!ud || ud->skilltimer == INVALID_TIMER) + break; //Nothing to cancel. + bl_skill_id = ud->skill_id; + bl_skill_lv = ud->skill_lv; + if (tstatus->mode & MD_BOSS) + { //Only 10% success chance against bosses. [Skotlex] + if (rnd()%100 < 90) + { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + } else if (!dstsd || map_flag_vs(bl->m)) //HP damage only on pvp-maps when against players. + hp = tstatus->max_hp/50; //Recover 2% HP [Skotlex] - case NPC_AGIUP: - sc_start(bl,SC_SPEEDUP1,100,skill_lv,skill->get_time(skill_id, skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); - break; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + unit_skillcastcancel(bl,0); + sp = skill->get_sp(bl_skill_id,bl_skill_lv); + status_zap(bl, hp, sp); - case NPC_INVISIBLE: - //Have val4 passed as 6 is for "infinite cloak" (do not end on attack/skill use). - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,0,0,6,skill->get_time(skill_id,skill_lv))); - break; + if (hp && skill_lv >= 5) + hp>>=1; //Recover half damaged HP at level 5 [Skotlex] + else + hp = 0; - case NPC_SIEGEMODE: - // not sure what it does - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - break; + if (sp) //Recover some of the SP used + sp = sp*(25*(skill_lv-1))/100; - case WE_MALE: - { - int hp_rate=(!skill_lv)? 0:skill_db[skill_id].hp_rate[skill_lv-1]; - int gain_hp= tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it costed the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status_heal(bl, gain_hp, 0, 0),1); + if(hp || sp) + status_heal(src, hp, sp, 2); + } } break; - case WE_FEMALE: - { - int sp_rate=(!skill_lv)? 0:skill_db[skill_id].sp_rate[skill_lv-1]; - int gain_sp=tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it costed the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status_heal(bl, 0, gain_sp, 0),1); - } + case SA_MAGICROD: + clif->skill_nodamage(src,src,SA_MAGICROD,skill_lv,1); + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; - - // parent-baby skills - case WE_BABY: - if(sd){ - struct map_session_data *f_sd = pc->get_father(sd); - struct map_session_data *m_sd = pc->get_mother(sd); - // if neither was found - if(!f_sd && !m_sd){ - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 0; + case SA_AUTOSPELL: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if(sd) + clif->autospell(sd,skill_lv); + else { + int maxlv=1,spellid=0; + static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT }; + if(skill_lv >= 10) { + spellid = MG_FROSTDIVER; + // if (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SA_SAGE) + // maxlv = 10; + // else + maxlv = skill_lv - 9; } - status_change_start(bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),8); - if (f_sd) sc_start(&f_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - if (m_sd) sc_start(&m_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - } - break; - - case PF_HPCONVERSION: - { - int hp, sp; - hp = sstatus->max_hp/10; - sp = hp * 10 * skill_lv / 100; - if (!status_charge(src,hp,0)) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + else if(skill_lv >=8) { + spellid = MG_FIREBALL; + maxlv = skill_lv - 7; } - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - status_heal(bl,0,sp,2); + else if(skill_lv >=5) { + spellid = MG_SOULSTRIKE; + maxlv = skill_lv - 4; + } + else if(skill_lv >=2) { + int i = rnd()%3; + spellid = spellarray[i]; + maxlv = skill_lv - 1; + } + else if(skill_lv > 0) { + spellid = MG_NAPALMBEAT; + maxlv = 3; + } + if(spellid > 0) + sc_start4(src,SC_AUTOSPELL,100,skill_lv,spellid,maxlv,0, + skill->get_time(SA_AUTOSPELL,skill_lv)); } break; - case MA_REMOVETRAP: - case HT_REMOVETRAP: - { - struct skill_unit* su; - struct skill_unit_group* sg; - su = BL_CAST(BL_SKILL, bl); - - // Mercenaries can remove any trap - // Players can only remove their own traps or traps on Vs maps. - if( su && (sg = su->group) && (src->type == BL_MER || sg->src_id == src->id || map_flag_vs(bl->m)) && (skill->get_inf2(sg->skill_id)&INF2_TRAP) ) - { - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) - { // prevent picking up expired traps - if( battle_config.skill_removetrap_type ) - { // get back all items used to deploy the trap - for( i = 0; i < 10; i++ ) - { - if( skill_db[su->group->skill_id].itemid[i] > 0 ) - { - int flag; - struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = skill_db[su->group->skill_id].itemid[i]; - item_tmp.identify = 1; - if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,skill_db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) ) - { - clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,skill_db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); - } - } - } - } - else - { // get back 1 trap - struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = su->group->item_id?su->group->item_id:ITEMID_TRAP; - item_tmp.identify = 1; - if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) ) - { - clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); - } - } - } - skill->delunit(su); - }else if(sd) - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - + case BS_GREED: + if(sd){ + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->greed,bl, + skill->get_splash(skill_id, skill_lv),BL_ITEM,bl); } break; - case HT_SPRINGTRAP: + + case SA_ELEMENTWATER: + case SA_ELEMENTFIRE: + case SA_ELEMENTGROUND: + case SA_ELEMENTWIND: + if(sd && !dstmd) //Only works on monsters. + break; + if(tstatus->mode&MD_BOSS) + break; + case NPC_ATTRICHANGE: + case NPC_CHANGEWATER: + case NPC_CHANGEGROUND: + case NPC_CHANGEFIRE: + case NPC_CHANGEWIND: + case NPC_CHANGEPOISON: + case NPC_CHANGEHOLY: + case NPC_CHANGEDARKNESS: + case NPC_CHANGETELEKINESIS: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), + skill->get_time(skill_id, skill_lv))); + break; + case NPC_CHANGEUNDEAD: + //This skill should fail if target is wearing bathory/evil druid card [Brainstorm] + //TO-DO This is ugly, fix it + if(tstatus->def_ele==ELE_UNDEAD || tstatus->def_ele==ELE_DARK) break; + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), + skill->get_time(skill_id, skill_lv))); + break; + + case NPC_PROVOCATION: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (md) mob_unlocktarget(md, tick); + break; + + case NPC_KEEPING: + case NPC_BARRIER: { - struct skill_unit *su=NULL; - if((bl->type==BL_SKILL) && (su=(struct skill_unit *)bl) && (su->group) ){ - switch(su->group->unit_id){ - case UNT_ANKLESNARE: // ankle snare - if (su->group->val2 != 0) - // if it is already trapping something don't spring it, - // remove trap should be used instead - break; - // otherwise fallthrough to below - case UNT_BLASTMINE: - case UNT_SKIDTRAP: - case UNT_LANDMINE: - case UNT_SHOCKWAVE: - case UNT_SANDMAN: - case UNT_FLASHER: - case UNT_FREEZINGTRAP: - case UNT_CLAYMORETRAP: - case UNT_TALKIEBOX: - su->group->unit_id = UNT_USED_TRAPS; - clif->changetraplook(bl, UNT_USED_TRAPS); - su->group->limit=DIFF_TICK(tick+1500,su->group->tick); - su->limit=DIFF_TICK(tick+1500,su->group->tick); - } + int skill_time = skill->get_time(skill_id,skill_lv); + struct unit_data *ud = unit_bl2ud(bl); + if (clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill_time)) + && ud) { //Disable attacking/acting/moving for skill's duration. + ud->attackabletime = + ud->canact_tick = + ud->canmove_tick = tick + skill_time; } } break; - case BD_ENCORE: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd) - unit_skilluse_id(src,src->id,sd->skill_id_dance,sd->skill_lv_dance); + + case NPC_REBIRTH: + if( md && md->state.rebirth ) + break; // only works once + sc_start(bl,type,100,skill_lv,-1); break; - case AS_SPLASHER: - if(tstatus->mode&MD_BOSS - /** - * Renewal dropped the 3/4 hp requirement - **/ - #ifndef RENEWAL - || tstatus-> hp > tstatus->max_hp*3/4 - #endif - ) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 1; - } + case NPC_DARKBLESSING: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,skill_id,src->id,skill->get_time(skill_id,skill_lv),1000)); - #ifndef RENEWAL - if (sd) skill->blockpc_start (sd, skill_id, skill->get_time(skill_id, skill_lv)+3000, false); - #endif + sc_start2(bl,type,(50+skill_lv*5),skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv))); break; - case PF_MINDBREAKER: - { - if(tstatus->mode&MD_BOSS || battle->check_undead(tstatus->race,tstatus->def_ele) ) { - iMap->freeblock_unlock(); - return 1; - } - - if (tsce) - { //HelloKitty2 (?) explained that this silently fails when target is - //already inflicted. [Skotlex] - iMap->freeblock_unlock(); - return 1; - } + case NPC_LICK: + status_zap(bl, 0, 100); + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,(skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv))); + break; - //Has a 55% + skill_lv*5% success chance. - if (!clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,55+5*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)))) - { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return 0; - } + case NPC_SUICIDE: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_kill(src); //When suiciding, neither exp nor drops is given. + break; - unit_skillcastcancel(bl,0); + case NPC_SUMMONSLAVE: + case NPC_SUMMONMONSTER: + if(md && md->skill_idx >= 0) + mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv,skill_id); + break; - if(tsc && tsc->count){ - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - if(tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE) - status_change_end(bl, SC_STONE, INVALID_TIMER); - status_change_end(bl, SC_SLEEP, INVALID_TIMER); - } + case NPC_CALLSLAVE: + mob_warpslave(src,MOB_SLAVEDISTANCE); + break; - if(dstmd) - mob_target(dstmd,src,skill->get_range2(src,skill_id,skill_lv)); + case NPC_RANDOMMOVE: + if (md) { + md->next_walktime = tick - 1; + mob_randomwalk(md,tick); } break; - case PF_SOULCHANGE: + case NPC_SPEEDUP: { - unsigned int sp1 = 0, sp2 = 0; - if (dstmd) { - if (dstmd->state.soul_change_flag) { - if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - dstmd->state.soul_change_flag = 1; - sp2 = sstatus->max_sp * 3 /100; - status_heal(src, 0, sp2, 2); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - break; - } - sp1 = sstatus->sp; - sp2 = tstatus->sp; - #ifdef RENEWAL - sp1 = sp1 / 2; - sp2 = sp2 / 2; - if( tsc && tsc->data[SC_EXTREMITYFIST2] ) - sp1 = tstatus->sp; - #endif - status_set_sp(src, sp2, 3); - status_set_sp(bl, sp1, 3); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + // or does it increase casting rate? just a guess xD + int i = SC_ATTHASTE_POTION1 + skill_lv - 1; + if (i > SC_ATTHASTE_INFINITY) + i = SC_ATTHASTE_INFINITY; + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,(sc_type)i,100,skill_lv,skill_lv * 60000)); } break; - // Slim Pitcher - case CR_SLIMPITCHER: - // Updated to block Slim Pitcher from working on barricades and guardian stones. - if( dstmd && (dstmd->class_ == MOBID_EMPERIUM || (dstmd->class_ >= MOBID_BARRICADE1 && dstmd->class_ <= MOBID_GUARIDAN_STONE2)) ) - break; - if (potion_hp || potion_sp) { - int hp = potion_hp, sp = potion_sp; - hp = hp * (100 + (tstatus->vit<<1))/100; - sp = sp * (100 + (tstatus->int_<<1))/100; - if (dstsd) { - if (hp) - hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10 + pc->skillheal2_bonus(dstsd, skill_id))/100; - if (sp) - sp = sp * (100 + pc->checkskill(dstsd,MG_SRECOVERY)*10 + pc->skillheal2_bonus(dstsd, skill_id))/100; - } - if( tsc && tsc->count ) { - if (tsc->data[SC_CRITICALWOUND]) { - hp -= hp * tsc->data[SC_CRITICALWOUND]->val2 / 100; - sp -= sp * tsc->data[SC_CRITICALWOUND]->val2 / 100; - } - if (tsc->data[SC_DEATHHURT]) { - hp -= hp * 20 / 100; - sp -= sp * 20 / 100; - } - if( tsc->data[SC_WATER_INSIGNIA] && tsc->data[SC_WATER_INSIGNIA]->val1 == 2) { - hp += hp / 10; - sp += sp / 10; - } - } - if(hp > 0) - clif->skill_nodamage(NULL,bl,AL_HEAL,hp,1); - if(sp > 0) - clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); - status_heal(bl,hp,sp,0); + case NPC_REVENGE: + // not really needed... but adding here anyway ^^ + if (md && md->master_id > 0) { + struct block_list *mbl, *tbl; + if ((mbl = iMap->id2bl(md->master_id)) == NULL || + (tbl = battle->get_targeted(mbl)) == NULL) + break; + md->state.provoke_flag = tbl->id; + mob_target(md, tbl, sstatus->rhw.range); } break; - // Full Chemical Protection - case CR_FULLPROTECTION: - { - unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; - int i, s = 0, skilltime = skill->get_time(skill_id,skill_lv); - for (i=0 ; i<4; i++) { - if( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[i]) < 0 ) ) - continue; - sc_start(bl,(sc_type)(SC_CP_WEAPON + i),100,skill_lv,skilltime); - s++; - } - if( sd && !s ){ - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); // Don't consume item requirements - return 0; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case NPC_RUN: + { + const int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}}; + uint8 dir = (bl == src)?unit_getdir(src):iMap->calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away. + unit_stop_attack(src); + //Run skillv tiles overriding the can-move check. + if (unit_walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md) + md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the ai. } break; - case RG_CLEANER: //AppleGirl - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - break; - - case CG_LONGINGFREEDOM: - { - if (tsc && !tsce && (tsce=tsc->data[SC_DANCING]) && tsce->val4 - && (tsce->val1&0xFFFF) != CG_MOONLIT) //Can't use Longing for Freedom while under Moonlight Petals. [Skotlex] - { - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - } + case NPC_TRANSFORMATION: + case NPC_METAMORPHOSIS: + if(md && md->skill_idx >= 0) { + int class_ = mob_random_class (md->db->skill[md->skill_idx].val,0); + if (skill_lv > 1) //Multiply the rest of mobs. [Skotlex] + mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv-1,skill_id); + if (class_) mob_class_change(md, class_); } break; - case CG_TAROTCARD: - { - int eff, count = -1; - if( rnd() % 100 > skill_lv * 8 || (dstmd && ((dstmd->guardian_data && dstmd->class_ == MOBID_EMPERIUM) || mob_is_battleground(dstmd))) ) - { - if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + case NPC_EMOTION_ON: + case NPC_EMOTION: + //val[0] is the emotion to use. + //NPC_EMOTION & NPC_EMOTION_ON can change a mob's mode 'permanently' [Skotlex] + //val[1] 'sets' the mode + //val[2] adds to the current mode + //val[3] removes from the current mode + //val[4] if set, asks to delete the previous mode change. + if(md && md->skill_idx >= 0 && tsc) { + clif->emotion(bl, md->db->skill[md->skill_idx].val[0]); + if(md->db->skill[md->skill_idx].val[4] && tsce) + status_change_end(bl, type, INVALID_TIMER); - iMap->freeblock_unlock(); - return 0; - } - status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded [Inkfish] - do { - eff = rnd() % 14; - clif->specialeffect(bl, 523 + eff, AREA); - switch (eff) - { - case 0: // heals SP to 0 - status_percent_damage(src, bl, 0, 100, false); - break; - case 1: // matk halved - sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - break; - case 2: // all buffs removed - status_change_clear_buffs(bl,1); - break; - case 3: // 1000 damage, random armor destroyed - { - status_fix_damage(src, bl, 1000, 0); - clif->damage(src,bl,tick,0,0,1000,0,0,0); - if( !status_isdead(bl) ) { - int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_SHOES, EQP_GARMENT }; - skill->break_equip(bl, where[rnd()%5], 10000, BCT_ENEMY); - } - } - break; - case 4: // atk halved - sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - break; - case 5: // 2000HP heal, random teleported - status_heal(src, 2000, 0, 0); - if( !map_flag_vs(bl->m) ) - unit_warp(bl, -1,-1,-1, CLR_TELEPORT); - break; - case 6: // random 2 other effects - if (count == -1) - count = 3; - else - count++; //Should not retrigger this one. - break; - case 7: // stop freeze or stoned - { - enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONE }; - sc_start(bl,sc[rnd()%3],100,skill_lv,skill->get_time2(skill_id,skill_lv)); - } - break; - case 8: // curse coma and poison - sc_start(bl,SC_COMA,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_POISON,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - break; - case 9: // confusion - sc_start(bl,SC_CONFUSION,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - break; - case 10: // 6666 damage, atk matk halved, cursed - status_fix_damage(src, bl, 6666, 0); - clif->damage(src,bl,tick,0,0,6666,0,0,0); - sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_CURSE,skill_lv,100,skill->get_time2(skill_id,skill_lv)); - break; - case 11: // 4444 damage - status_fix_damage(src, bl, 4444, 0); - clif->damage(src,bl,tick,0,0,4444,0,0,0); - break; - case 12: // stun - sc_start(bl,SC_STUN,100,skill_lv,5000); - break; - case 13: // atk,matk,hit,flee,def reduced - sc_start(bl,SC_INCATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCMATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCHITRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCFLEERATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCDEFRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - break; - default: - break; - } - } while ((--count) > 0); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + //If mode gets set by NPC_EMOTION then the target should be reset [Playtester] + if(skill_id == NPC_EMOTION && md->db->skill[md->skill_idx].val[1]) + mob_unlocktarget(md,tick); + + if(md->db->skill[md->skill_idx].val[1] || md->db->skill[md->skill_idx].val[2]) + sc_start4(src, type, 100, skill_lv, + md->db->skill[md->skill_idx].val[1], + md->db->skill[md->skill_idx].val[2], + md->db->skill[md->skill_idx].val[3], + skill->get_time(skill_id, skill_lv)); } break; - case SL_ALCHEMIST: - case SL_ASSASIN: - case SL_BARDDANCER: - case SL_BLACKSMITH: - case SL_CRUSADER: - case SL_HUNTER: - case SL_KNIGHT: - case SL_MONK: - case SL_PRIEST: - case SL_ROGUE: - case SL_SAGE: - case SL_SOULLINKER: - case SL_STAR: - case SL_SUPERNOVICE: - case SL_WIZARD: - //NOTE: here, 'type' has the value of the associated MAPID, not of the SC_SPIRIT constant. - if (sd && !(dstsd && (dstsd->class_&MAPID_UPPERMASK) == type)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - if (skill_id == SL_SUPERNOVICE && dstsd && dstsd->die_counter && !(rnd()%100)) - { //Erase death count 1% of the casts - dstsd->die_counter = 0; - pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0); - clif->specialeffect(bl, 0x152, AREA); - //SC_SPIRIT invokes status_calc_pc for us. - } + case NPC_POWERUP: + sc_start(bl,SC_INCATKRATE,100,200,skill->get_time(skill_id, skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,SC_SPIRIT,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); - sc_start(src,SC_SMA,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); break; - case SL_HIGH: - if (sd && !(dstsd && (dstsd->class_&JOBL_UPPER) && !(dstsd->class_&JOBL_2) && dstsd->status.base_level < 70)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } + + case NPC_AGIUP: + sc_start(bl,SC_MOVHASTE_INFINITY,100,skill_lv,skill->get_time(skill_id, skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); - sc_start(src,SC_SMA,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); break; - case SL_SWOO: - if (tsce) { - if(sd) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,10000,8); - status_change_end(bl, SC_SWOO, INVALID_TIMER); - break; - } - case SL_SKA: // [marquis007] - case SL_SKE: - if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,10); - break; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - if (skill_id == SL_SKE) - sc_start(src,SC_SMA,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + case NPC_INVISIBLE: + //Have val4 passed as 6 is for "infinite cloak" (do not end on attack/skill use). + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,type,100,skill_lv,0,0,6,skill->get_time(skill_id,skill_lv))); break; - // New guild skills [Celest] - case GD_BATTLEORDER: - if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); - } else if (status_get_guild_id(src)) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); - if (sd) - guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); + case NPC_SIEGEMODE: + // not sure what it does + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + + case WE_MALE: + { + int hp_rate=(!skill_lv)? 0:skill_db[skill_id].hp_rate[skill_lv-1]; + int gain_hp= tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it costed the caster. [Skotlex] + clif->skill_nodamage(src,bl,skill_id,status_heal(bl, gain_hp, 0, 0),1); } break; - case GD_REGENERATION: - if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); - } else if (status_get_guild_id(src)) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); - if (sd) - guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); + case WE_FEMALE: + { + int sp_rate=(!skill_lv)? 0:skill_db[skill_id].sp_rate[skill_lv-1]; + int gain_sp=tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it costed the caster. [Skotlex] + clif->skill_nodamage(src,bl,skill_id,status_heal(bl, 0, gain_sp, 0),1); } break; - case GD_RESTORE: - if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) - clif->skill_nodamage(src,bl,AL_HEAL,status_percent_heal(bl,90,90),1); - } else if (status_get_guild_id(src)) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); - if (sd) - guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); + + // parent-baby skills + case WE_BABY: + if(sd){ + struct map_session_data *f_sd = pc->get_father(sd); + struct map_session_data *m_sd = pc->get_mother(sd); + // if neither was found + if(!f_sd && !m_sd){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; + } + status_change_start(bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),8); + if (f_sd) sc_start(&f_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + if (m_sd) sc_start(&m_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); } break; - case GD_EMERGENCYCALL: + + case PF_HPCONVERSION: { - int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0}; - int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0}; - int j = 0; - struct guild *g; - // i don't know if it actually summons in a circle, but oh well. ;P - g = sd?sd->state.gmaster_flag:guild->search(status_get_guild_id(src)); - if (!g) + int hp, sp; + hp = sstatus->max_hp/10; + sp = hp * 10 * skill_lv / 100; + if (!status_charge(src,hp,0)) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - for(i = 0; i < g->max_member; i++, j++) { - if (j>8) j=0; - if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) { - if (map[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m)) - continue; - if(iMap->getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) - dx[j] = dy[j] = 0; - pc->setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN); - } } - if (sd) - guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_heal(bl,0,sp,2); } break; - case SG_FEEL: - //AuronX reported you CAN memorize the same map as all three. [Skotlex] - if (sd) { - if(!sd->feel_map[skill_lv-1].index) - clif->feel_req(sd->fd,sd, skill_lv); - else - clif->feel_info(sd, skill_lv-1, 1); + case MA_REMOVETRAP: + case HT_REMOVETRAP: + { + struct skill_unit* su; + struct skill_unit_group* sg; + su = BL_CAST(BL_SKILL, bl); + + // Mercenaries can remove any trap + // Players can only remove their own traps or traps on Vs maps. + if( su && (sg = su->group) && (src->type == BL_MER || sg->src_id == src->id || map_flag_vs(bl->m)) && (skill->get_inf2(sg->skill_id)&INF2_TRAP) ) + { + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) + { // prevent picking up expired traps + if( battle_config.skill_removetrap_type ) + { // get back all items used to deploy the trap + for( i = 0; i < 10; i++ ) + { + if( skill_db[su->group->skill_id].itemid[i] > 0 ) + { + int flag; + struct item item_tmp; + memset(&item_tmp,0,sizeof(item_tmp)); + item_tmp.nameid = skill_db[su->group->skill_id].itemid[i]; + item_tmp.identify = 1; + if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,skill_db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) ) + { + clif->additem(sd,0,0,flag); + iMap->addflooritem(&item_tmp,skill_db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } + } + } + } + else + { // get back 1 trap + struct item item_tmp; + memset(&item_tmp,0,sizeof(item_tmp)); + item_tmp.nameid = su->group->item_id?su->group->item_id:ITEMID_TRAP; + item_tmp.identify = 1; + if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) ) + { + clif->additem(sd,0,0,flag); + iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } + } + } + skill->delunit(su); + }else if(sd) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + } break; - - case SG_HATE: - if (sd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (!pc->set_hate_mob(sd, skill_lv-1, bl)) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + case HT_SPRINGTRAP: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + { + struct skill_unit *su=NULL; + if((bl->type==BL_SKILL) && (su=(struct skill_unit *)bl) && (su->group) ){ + switch(su->group->unit_id){ + case UNT_ANKLESNARE: // ankle snare + if (su->group->val2 != 0) + // if it is already trapping something don't spring it, + // remove trap should be used instead + break; + // otherwise fallthrough to below + case UNT_BLASTMINE: + case UNT_SKIDTRAP: + case UNT_LANDMINE: + case UNT_SHOCKWAVE: + case UNT_SANDMAN: + case UNT_FLASHER: + case UNT_FREEZINGTRAP: + case UNT_CLAYMORETRAP: + case UNT_TALKIEBOX: + su->group->unit_id = UNT_USED_TRAPS; + clif->changetraplook(bl, UNT_USED_TRAPS); + su->group->limit=DIFF_TICK(tick+1500,su->group->tick); + su->limit=DIFF_TICK(tick+1500,su->group->tick); + } + } } break; + case BD_ENCORE: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if(sd) + unit_skilluse_id(src,src->id,sd->skill_id_dance,sd->skill_lv_dance); + break; - case GS_GLITTERING: - if(sd) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(rnd()%100 < (20+10*skill_lv)) - pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),10); - else if(sd->spiritball > 0) - pc->delspiritball(sd,1,0); + case AS_SPLASHER: + if(tstatus->mode&MD_BOSS + /** + * Renewal dropped the 3/4 hp requirement + **/ + #ifndef RENEWAL + || tstatus-> hp > tstatus->max_hp*3/4 + #endif + ) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 1; } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,type,100,skill_lv,skill_id,src->id,skill->get_time(skill_id,skill_lv),1000)); + #ifndef RENEWAL + if (sd) skill->blockpc_start (sd, skill_id, skill->get_time(skill_id, skill_lv)+3000, false); + #endif break; - case GS_CRACKER: - /* per official standards, this skill works on players and mobs. */ - if (sd && (dstsd || dstmd)) + case PF_MINDBREAKER: { - i =65 -5*distance_bl(src,bl); //Base rate - if (i < 30) i = 30; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - sc_start(bl,SC_STUN, i,skill_lv,skill->get_time2(skill_id,skill_lv)); - } - break; + if(tstatus->mode&MD_BOSS || battle->check_undead(tstatus->race,tstatus->def_ele) ) { + iMap->freeblock_unlock(); + return 1; + } - case AM_CALLHOMUN: //[orn] - if (sd && homun->call(sd)) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + if (tsce) + { //HelloKitty2 (?) explained that this silently fails when target is + //already inflicted. [Skotlex] + iMap->freeblock_unlock(); + return 1; + } - case AM_REST: - if (sd) { - if (homun->vaporize(sd,1)) - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + //Has a 55% + skill_lv*5% success chance. + if (!clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,55+5*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)))) + { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; + } + + unit_skillcastcancel(bl,0); + + if(tsc && tsc->count){ + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + if(tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE) + status_change_end(bl, SC_STONE, INVALID_TIMER); + status_change_end(bl, SC_SLEEP, INVALID_TIMER); + } + + if(dstmd) + mob_target(dstmd,src,skill->get_range2(src,skill_id,skill_lv)); } break; - case HAMI_CASTLE: //[orn] - if(rnd()%100 < 20*skill_lv && src != bl) + case PF_SOULCHANGE: { - int x,y; - x = src->x; - y = src->y; - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); - - if (unit_movepos(src,bl->x,bl->y,0,0)) { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homunc - clif->slide(src,bl->x,bl->y) ; - if (unit_movepos(bl,x,y,0,0)) - { - clif->skill_nodamage(bl,bl,skill_id,skill_lv,1); // Master - clif->slide(bl,x,y) ; + unsigned int sp1 = 0, sp2 = 0; + if (dstmd) { + if (dstmd->state.soul_change_flag) { + if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } + dstmd->state.soul_change_flag = 1; + sp2 = sstatus->max_sp * 3 /100; + status_heal(src, 0, sp2, 2); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + break; + } + sp1 = sstatus->sp; + sp2 = tstatus->sp; + #ifdef RENEWAL + sp1 = sp1 / 2; + sp2 = sp2 / 2; + if( tsc && tsc->data[SC_EXTREMITYFIST2] ) + sp1 = tstatus->sp; + #endif + status_set_sp(src, sp2, 3); + status_set_sp(bl, sp1, 3); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; - //TODO: Shouldn't also players and the like switch targets? - iMap->foreachinrange(skill->chastle_mob_changetarget,src, - AREA_SIZE, BL_MOB, bl, src); + // Slim Pitcher + case CR_SLIMPITCHER: + // Updated to block Slim Pitcher from working on barricades and guardian stones. + if( dstmd && (dstmd->class_ == MOBID_EMPERIUM || (dstmd->class_ >= MOBID_BARRICADE1 && dstmd->class_ <= MOBID_GUARIDAN_STONE2)) ) + break; + if (potion_hp || potion_sp) { + int hp = potion_hp, sp = potion_sp; + hp = hp * (100 + (tstatus->vit<<1))/100; + sp = sp * (100 + (tstatus->int_<<1))/100; + if (dstsd) { + if (hp) + hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10 + pc->skillheal2_bonus(dstsd, skill_id))/100; + if (sp) + sp = sp * (100 + pc->checkskill(dstsd,MG_SRECOVERY)*10 + pc->skillheal2_bonus(dstsd, skill_id))/100; + } + if( tsc && tsc->count ) { + if (tsc->data[SC_CRITICALWOUND]) { + hp -= hp * tsc->data[SC_CRITICALWOUND]->val2 / 100; + sp -= sp * tsc->data[SC_CRITICALWOUND]->val2 / 100; + } + if (tsc->data[SC_DEATHHURT]) { + hp -= hp * 20 / 100; + sp -= sp * 20 / 100; + } + if( tsc->data[SC_WATER_INSIGNIA] && tsc->data[SC_WATER_INSIGNIA]->val1 == 2) { + hp += hp / 10; + sp += sp / 10; + } } + if(hp > 0) + clif->skill_nodamage(NULL,bl,AL_HEAL,hp,1); + if(sp > 0) + clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); + status_heal(bl,hp,sp,0); } - // Failed - else if (hd && hd->master) - clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_LEVEL, 0); - else if (sd) - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; - case HVAN_CHAOTIC: //[orn] + // Full Chemical Protection + case CR_FULLPROTECTION: { - static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}}; - int r = rnd()%100; - i = (skill_lv-1)%5; - if(rget_master(src); - else //Enemy - bl = iMap->id2bl(battle->get_target(src)); + unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; + int i, s = 0, skilltime = skill->get_time(skill_id,skill_lv); - if (!bl) bl = src; - i = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true); - //Eh? why double skill packet? - clif->skill_nodamage(src,bl,AL_HEAL,i,1); - clif->skill_nodamage(src,bl,skill_id,i,1); - status_heal(bl, i, 0, 0); + for (i=0 ; i<4; i++) { + if( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[i]) < 0 ) ) + continue; + sc_start(bl,(sc_type)(SC_PROTECTWEAPON + i),100,skill_lv,skilltime); + s++; + } + if( sd && !s ){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); // Don't consume item requirements + return 0; + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - //Homun single-target support skills [orn] - case HAMI_BLOODLUST: - case HFLI_FLEET: - case HFLI_SPEED: - case HLIF_CHANGE: - case MH_ANGRIFFS_MODUS: - case MH_GOLDENE_FERSE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); + + case RG_CLEANER: //AppleGirl + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; - case NPC_DRAGONFEAR: - if (flag&1) { - const enum sc_type sc[] = { SC_STUN, SC_SILENCE, SC_CONFUSION, SC_BLEEDING }; - int j; - j = i = rnd()%ARRAYLENGTH(sc); - while ( !sc_start2(bl,sc[i],100,skill_lv,src->id,skill->get_time2(skill_id,i+1)) ) { - i++; - if ( i == ARRAYLENGTH(sc) ) - i = 0; - if (i == j) - break; + case CG_LONGINGFREEDOM: + { + if (tsc && !tsce && (tsce=tsc->data[SC_DANCING]) && tsce->val4 + && (tsce->val1&0xFFFF) != CG_MOONLIT) //Can't use Longing for Freedom while under Moonlight Petals. [Skotlex] + { + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } - break; - } - case NPC_WIDEBLEEDING: - case NPC_WIDECONFUSE: - case NPC_WIDECURSE: - case NPC_WIDEFREEZE: - case NPC_WIDESLEEP: - case NPC_WIDESILENCE: - case NPC_WIDESTONE: - case NPC_WIDESTUN: - case NPC_SLOWCAST: - case NPC_WIDEHELLDIGNITY: - if (flag&1) - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); - else { - skill_area_temp[2] = 0; //For SD_PREAMBLE - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); - } - break; - case NPC_WIDESOULDRAIN: - if (flag&1) - status_percent_damage(src,bl,0,((skill_lv-1)%5+1)*20,false); - else { - skill_area_temp[2] = 0; //For SD_PREAMBLE - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); } break; - case ALL_PARTYFLEE: - if( sd && !(flag&1) ) + + case CG_TAROTCARD: { - if( !sd->status.party_id ) + int eff, count = -1; + if( tsc && tsc->data[type] ){ + iMap->freeblock_unlock(); + return 0; + } + if( rnd() % 100 > skill_lv * 8 || (dstmd && ((dstmd->guardian_data && dstmd->class_ == MOBID_EMPERIUM) || mob_is_battleground(dstmd))) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + + iMap->freeblock_unlock(); + return 0; } - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded [Inkfish] + do { + eff = rnd() % 14; + if( eff == 5 ) + clif->specialeffect(src, 528, AREA); + else + clif->specialeffect(bl, 523 + eff, AREA); + switch (eff) + { + case 0: // heals SP to 0 + status_percent_damage(src, bl, 0, 100, false); + break; + case 1: // matk halved + sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + break; + case 2: // all buffs removed + status_change_clear_buffs(bl,1); + break; + case 3: // 1000 damage, random armor destroyed + { + status_fix_damage(src, bl, 1000, 0); + clif->damage(src,bl,tick,0,0,1000,0,0,0); + if( !status_isdead(bl) ) { + int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_SHOES, EQP_GARMENT }; + skill->break_equip(bl, where[rnd()%5], 10000, BCT_ENEMY); + } + } + break; + case 4: // atk halved + sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + break; + case 5: // 2000HP heal, random teleported + status_heal(src, 2000, 0, 0); + if( !map_flag_vs(bl->m) ) + unit_warp(bl, -1,-1,-1, CLR_TELEPORT); + break; + case 6: // random 2 other effects + if (count == -1) + count = 3; + else + count++; //Should not retrigger this one. + break; + case 7: // stop freeze or stoned + { + enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONE }; + sc_start(bl,sc[rnd()%3],100,skill_lv,skill->get_time2(skill_id,skill_lv)); + } + break; + case 8: // curse coma and poison + sc_start(bl,SC_COMA,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_POISON,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + break; + case 9: // confusion + sc_start(bl,SC_CONFUSION,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + break; + case 10: // 6666 damage, atk matk halved, cursed + status_fix_damage(src, bl, 6666, 0); + clif->damage(src,bl,tick,0,0,6666,0,0,0); + sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_CURSE,skill_lv,100,skill->get_time2(skill_id,skill_lv)); + break; + case 11: // 4444 damage + status_fix_damage(src, bl, 4444, 0); + clif->damage(src,bl,tick,0,0,4444,0,0,0); + break; + case 12: // stun + sc_start(bl,SC_STUN,100,skill_lv,5000); + break; + case 13: // atk,matk,hit,flee,def reduced + sc_start(bl,SC_INCATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_INCMATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_INCHITRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_INCFLEERATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,SC_INCDEFRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + break; + default: + break; + } + } while ((--count) > 0); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } - else - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - break; - case NPC_TALK: - case ALL_WEWISH: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; - case ALL_BUYING_STORE: - if( sd ) - {// players only, skill allows 5 buying slots - clif->skill_nodamage(src, bl, skill_id, skill_lv, buyingstore->setup(sd, MAX_BUYINGSTORE_SLOTS)); + + case SL_ALCHEMIST: + case SL_ASSASIN: + case SL_BARDDANCER: + case SL_BLACKSMITH: + case SL_CRUSADER: + case SL_HUNTER: + case SL_KNIGHT: + case SL_MONK: + case SL_PRIEST: + case SL_ROGUE: + case SL_SAGE: + case SL_SOULLINKER: + case SL_STAR: + case SL_SUPERNOVICE: + case SL_WIZARD: + //NOTE: here, 'type' has the value of the associated MAPID, not of the SC_SOULLINK constant. + if (sd && !(dstsd && (dstsd->class_&MAPID_UPPERMASK) == type)) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } + if (skill_id == SL_SUPERNOVICE && dstsd && dstsd->die_counter && !(rnd()%100)) + { //Erase death count 1% of the casts + dstsd->die_counter = 0; + pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0); + clif->specialeffect(bl, 0x152, AREA); + //SC_SOULLINK invokes status_calc_pc for us. + } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,SC_SOULLINK,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; - case RK_ENCHANTBLADE: - clif->skill_nodamage(src,bl,skill_id,skill_lv,// formula not confirmed - sc_start2(bl,type,100,skill_lv,100+20*skill_lv/*+sstatus->int_/2+status_get_lv(bl)/10*/,skill->get_time(skill_id,skill_lv))); - break; - case RK_DRAGONHOWLING: - if( flag&1) - sc_start(bl,type,50 + 6 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - skill_area_temp[2] = 0; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id,skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); + case SL_HIGH: + if (sd && !(dstsd && (dstsd->class_&JOBL_UPPER) && !(dstsd->class_&JOBL_2) && dstsd->status.base_level < 70)) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(bl,type,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; - case RK_IGNITIONBREAK: - case LG_EARTHDRIVE: - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - i = skill->get_splash(skill_id,skill_lv); - if( skill_id == LG_EARTHDRIVE ) { - int dummy = 1; - iMap->foreachinarea(skill->cell_overlap, src->m, src->x-i, src->y-i, src->x+i, src->y+i, BL_SKILL, LG_EARTHDRIVE, &dummy, src); - } - iMap->foreachinrange(skill->area_sub, bl,i,BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - break; - case RK_STONEHARDSKIN: - if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 4 ) - { - int heal = sstatus->hp / 4; // 25% HP - if( status_charge(bl,heal,0) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start2(bl,type,100,skill_lv,heal,skill->get_time(skill_id,skill_lv))); - else + + case SL_SWOO: + if (tsce) { + if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,10000,8); + status_change_end(bl, SC_SWOO, INVALID_TIMER); + break; } - break; - case RK_REFRESH: - if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 8 ) - { - int heal = status_get_max_hp(bl) * 25 / 100; - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - status_heal(bl,heal,0,1); - status_change_clear_buffs(bl,4); + case SL_SKA: // [marquis007] + case SL_SKE: + if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,10); + break; } + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if (skill_id == SL_SKE) + sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; - case RK_MILLENNIUMSHIELD: - if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 9 ) - { - short shields = (rnd()%100<50) ? 4 : ((rnd()%100<80) ? 3 : 2); - sc_start4(bl,type,100,skill_lv,shields,1000,0,skill->get_time(skill_id,skill_lv)); - clif->millenniumshield(sd,shields); - clif->skill_nodamage(src,bl,skill_id,1,1); + // New guild skills [Celest] + case GD_BATTLEORDER: + if(flag&1) { + if (status_get_guild_id(src) == status_get_guild_id(bl)) + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); + } else if (status_get_guild_id(src)) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); + if (sd) + guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } break; - - case RK_GIANTGROWTH: - case RK_VITALITYACTIVATION: - case RK_ABUNDANCE: - case RK_CRUSHSTRIKE: - if( sd ) - { - int lv = 1; // RK_GIANTGROWTH - if( skill_id == RK_VITALITYACTIVATION ) - lv = 2; - else if( skill_id == RK_ABUNDANCE ) - lv = 6; - else if( skill_id == RK_CRUSHSTRIKE ) - lv = 7; - if( pc->checkskill(sd,RK_RUNEMASTERY) >= lv ) - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + case GD_REGENERATION: + if(flag&1) { + if (status_get_guild_id(src) == status_get_guild_id(bl)) + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); + } else if (status_get_guild_id(src)) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); + if (sd) + guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } break; - - case RK_FIGHTINGSPIRIT: - if( flag&1 ) { - if( src == bl ) - sc_start2(bl,type,100,skill_area_temp[5],10*(sd?pc->checkskill(sd,RK_RUNEMASTERY):10),skill->get_time(skill_id,skill_lv)); - else - sc_start(bl,type,100,skill_area_temp[5]/4,skill->get_time(skill_id,skill_lv)); - } else if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 5 ) { - if( sd->status.party_id ) { - i = party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,BCT_PARTY,skill->area_sub_count); - skill_area_temp[5] = 7 * i; // ATK - party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); - } else - sc_start2(bl,type,100,7,5,skill->get_time(skill_id,skill_lv)); + case GD_RESTORE: + if(flag&1) { + if (status_get_guild_id(src) == status_get_guild_id(bl)) + clif->skill_nodamage(src,bl,AL_HEAL,status_percent_heal(bl,90,90),1); + } else if (status_get_guild_id(src)) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); + if (sd) + guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } - clif->skill_nodamage(src,bl,skill_id,1,1); break; - /** - * Guilotine Cross - **/ - case GC_ROLLINGCUTTER: + case GD_EMERGENCYCALL: { - short count = 1; - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill->castend_damage_id); - if( tsc && tsc->data[SC_ROLLINGCUTTER] ) - { // Every time the skill is casted the status change is reseted adding a counter. - count += (short)tsc->data[SC_ROLLINGCUTTER]->val1; - if( count > 10 ) - count = 10; // Max coounter - status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); + int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0}; + int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0}; + int j = 0; + struct guild *g; + // i don't know if it actually summons in a circle, but oh well. ;P + g = sd?sd->state.gmaster_flag:guild->search(status_get_guild_id(src)); + if (!g) + break; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + for(i = 0; i < g->max_member; i++, j++) { + if (j>8) j=0; + if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) { + if (map[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m)) + continue; + if(iMap->getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) + dx[j] = dy[j] = 0; + pc->setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN); + } } - sc_start(bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage(src,src,skill_id,skill_lv,1); + if (sd) + guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } break; - case GC_WEAPONBLOCKING: - if( tsc && tsc->data[SC_WEAPONBLOCKING] ) - status_change_end(bl, SC_WEAPONBLOCKING, INVALID_TIMER); - else - sc_start(bl,SC_WEAPONBLOCKING,100,skill_lv,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - break; - - case GC_CREATENEWPOISON: - if( sd ) - { - clif->skill_produce_mix_list(sd,skill_id,25); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + case SG_FEEL: + //AuronX reported you CAN memorize the same map as all three. [Skotlex] + if (sd) { + if(!sd->feel_map[skill_lv-1].index) + clif->feel_req(sd->fd,sd, skill_lv); + else + clif->feel_info(sd, skill_lv-1, 1); } break; - case GC_POISONINGWEAPON: - if( sd ) { - clif->poison_list(sd,skill_lv); + case SG_HATE: + if (sd) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if (!pc->set_hate_mob(sd, skill_lv-1, bl)) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - case GC_ANTIDOTE: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if( tsc ) - { - status_change_end(bl, SC_PARALYSE, INVALID_TIMER); - status_change_end(bl, SC_PYREXIA, INVALID_TIMER); - status_change_end(bl, SC_DEATHHURT, INVALID_TIMER); - status_change_end(bl, SC_LEECHESEND, INVALID_TIMER); - status_change_end(bl, SC_VENOMBLEED, INVALID_TIMER); - status_change_end(bl, SC_MAGICMUSHROOM, INVALID_TIMER); - status_change_end(bl, SC_TOXIN, INVALID_TIMER); - status_change_end(bl, SC_OBLIVIONCURSE, INVALID_TIMER); - } - break; - - case GC_PHANTOMMENACE: - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - break; - - case GC_HALLUCINATIONWALK: - { - int heal = status_get_max_hp(bl) / 10; - if( status_get_hp(bl) < heal ) { // if you haven't enough HP skill fails. - if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); - break; - } - if( !status_charge(bl,heal,0) ) - { - if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); - break; - } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - } - break; - /** - * Arch Bishop - **/ - case AB_ANCILLA: - if( sd ) { + case GS_GLITTERING: + if(sd) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1); + if(rnd()%100 < (20+10*skill_lv)) + pc->addspiritball(sd,skill->get_time(skill_id,skill_lv),10); + else if(sd->spiritball > 0) + pc->delspiritball(sd,1,0); } break; - case AB_CLEMENTIA: - case AB_CANTO: + case GS_CRACKER: + /* per official standards, this skill works on players and mobs. */ + if (sd && (dstsd || dstmd)) { - int bless_lv = pc->checkskill(sd,AL_BLESSING) + (sd->status.job_level / 10); - int agi_lv = pc->checkskill(sd,AL_INCAGI) + (sd->status.job_level / 10); - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100, - (skill_id == AB_CLEMENTIA)? bless_lv : (skill_id == AB_CANTO)? agi_lv : skill_lv, skill->get_time(skill_id,skill_lv))); - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + i =65 -5*distance_bl(src,bl); //Base rate + if (i < 30) i = 30; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start(bl,SC_STUN, i,skill_lv,skill->get_time2(skill_id,skill_lv)); } break; - case AB_PRAEFATIO: - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start4(bl, type, 100, skill_lv, 0, 0, 1, skill->get_time(skill_id, skill_lv))); - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + case AM_CALLHOMUN: //[orn] + if (sd && homun->call(sd)) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; - - case AB_CHEAL: - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) { - if( sd && tstatus && !battle->check_undead(tstatus->race, tstatus->def_ele) ) { - i = skill->calc_heal(src, bl, AL_HEAL, pc->checkskill(sd, AL_HEAL), true); - - if( (dstsd && pc_ismadogear(dstsd)) || status_isimmune(bl)) - i = 0; // Should heal by 0 or won't do anything?? in iRO it breaks the healing to members.. [malufett] - - clif->skill_nodamage(bl, bl, skill_id, i, 1); - if( tsc && tsc->data[SC_AKAITSUKI] && i ) - i = ~i + 1; - status_heal(bl, i, 0, 0); - } + + case AM_REST: + if (sd) { + if (homun->vaporize(sd,1)) + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case AB_ORATIO: - if( flag&1 ) - sc_start(bl, type, 40 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); - else + case HAMI_CASTLE: //[orn] + if(rnd()%100 < 20*skill_lv && src != bl) { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + int x,y; + x = src->x; + y = src->y; + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); + + if (unit_movepos(src,bl->x,bl->y,0,0)) { + clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homunc + clif->slide(src,bl->x,bl->y) ; + if (unit_movepos(bl,x,y,0,0)) + { + clif->skill_nodamage(bl,bl,skill_id,skill_lv,1); // Master + clif->slide(bl,x,y) ; + } + + //TODO: Shouldn't also players and the like switch targets? + iMap->foreachinrange(skill->chastle_mob_changetarget,src, + AREA_SIZE, BL_MOB, bl, src); + } } + // Failed + else if (hd && hd->master) + clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_LEVEL, 0); + else if (sd) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; + case HVAN_CHAOTIC: //[orn] + { + static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}}; + int r = rnd()%100; + i = (skill_lv-1)%5; + if(rget_master(src); + else //Enemy + bl = iMap->id2bl(battle->get_target(src)); - case AB_LAUDAAGNUS: - if( flag&1 || sd == NULL ) { - if( tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] || tsc->data[SC_BLIND] || - tsc->data[SC_BURNING] || tsc->data[SC_FREEZING] || tsc->data[SC_CRYSTALIZE])) { - // Success Chance: (40 + 10 * Skill Level) % - if( rnd()%100 > 40+10*skill_lv ) break; - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_STONE, INVALID_TIMER); - status_change_end(bl, SC_BLIND, INVALID_TIMER); - status_change_end(bl, SC_BURNING, INVALID_TIMER); - status_change_end(bl, SC_FREEZING, INVALID_TIMER); - status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); - }else //Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets - clif->skill_nodamage(bl, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); - } else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), - src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + if (!bl) bl = src; + i = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true); + //Eh? why double skill packet? + clif->skill_nodamage(src,bl,AL_HEAL,i,1); + clif->skill_nodamage(src,bl,skill_id,i,1); + status_heal(bl, i, 0, 0); + } break; - - case AB_LAUDARAMUS: - if( flag&1 || sd == NULL ) { - if( tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || tsc->data[SC_MANDRAGORA] || tsc->data[SC_SILENCE]) ){ - // Success Chance: (40 + 10 * Skill Level) % - if( rnd()%100 > 40+10*skill_lv ) break; - status_change_end(bl, SC_SLEEP, INVALID_TIMER); - status_change_end(bl, SC_STUN, INVALID_TIMER); - status_change_end(bl, SC_MANDRAGORA, INVALID_TIMER); - status_change_end(bl, SC_SILENCE, INVALID_TIMER); - }else // Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets - clif->skill_nodamage(bl, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); - } else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), - src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + //Homun single-target support skills [orn] + case HAMI_BLOODLUST: + case HFLI_FLEET: + case HFLI_SPEED: + case HLIF_CHANGE: + case MH_ANGRIFFS_MODUS: + case MH_GOLDENE_FERSE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); break; - case AB_CLEARANCE: - if( flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1 ) - { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 30 + 10 * skill_lv) - { - if (sd) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - if(status_isimmune(bl) || !tsc || !tsc->count) - break; - for(i=0;idata[i]) - continue; - switch (i) { - case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION: - case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR: - case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD: - case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO: - case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD: - case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD: - case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD: - case SC_WATKFOOD: case SC_MATKFOOD: case SC_DANCING: - case SC_SPIRIT: case SC_AUTOBERSERK: - case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL: - case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT: - case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED: - case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE: - case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL: - case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN: - case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN: - case SC_READYCOUNTER:case SC_DODGE: case SC_WARM: - case SC_SPEEDUP1: case SC_AUTOTRADE: case SC_CRITICALWOUND: - case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF: - case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF: - case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK: - case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS: - case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL: - case SC_INTOABYSS: case SC_SIEGFRIED: case SC_WHISTLE: - case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN: - case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE: - case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH: - case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH: - case SC_FOOD_LUK_CASH: case SC_ELECTRICSHOCKER: case SC_BITE: - case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY: - case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY: - case SC__WEAKNESS: //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: - case SC_MAGNETICFIELD://case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA: - //case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES: - case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: - case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: - case SC_LEADERSHIP: case SC_GLORYWOUNDS: case SC_SOULCOLD: - case SC_HAWKEYES: case SC_GUILDAURA: case SC_PUSH_CART: - case SC_PARTYFLEE: case SC_GT_REVITALIZE: - case SC_RAISINGDRAGON: case SC_GT_ENERGYGAIN: case SC_GT_CHANGE: - #ifdef RENEWAL - case SC_EXTREMITYFIST2: - #endif - continue; - case SC_ASSUMPTIO: - if( bl->type == BL_MOB ) - continue; + case NPC_DRAGONFEAR: + if (flag&1) { + const enum sc_type sc[] = { SC_STUN, SC_SILENCE, SC_CONFUSION, SC_BLOODING }; + int j; + j = i = rnd()%ARRAYLENGTH(sc); + while ( !sc_start2(bl,sc[i],100,skill_lv,src->id,skill->get_time2(skill_id,i+1)) ) { + i++; + if ( i == ARRAYLENGTH(sc) ) + i = 0; + if (i == j) break; - } - if(i==SC_BERSERK || i==SC_SATURDAYNIGHTFEVER) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0. - status_change_end(bl,(sc_type)i,INVALID_TIMER); } break; } - iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, src, skill_id, skill_lv, tick, flag|1, skill->castend_damage_id); - break; - - case AB_SILENTIUM: - // Should the level of Lex Divina be equivalent to the level of Silentium or should the highest level learned be used? [LimitLine] - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, PR_LEXDIVINA, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + case NPC_WIDEBLEEDING: + case NPC_WIDECONFUSE: + case NPC_WIDECURSE: + case NPC_WIDEFREEZE: + case NPC_WIDESLEEP: + case NPC_WIDESILENCE: + case NPC_WIDESTONE: + case NPC_WIDESTUN: + case NPC_SLOWCAST: + case NPC_WIDEHELLDIGNITY: + if (flag&1) + sc_start2(bl,type,100,skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + else { + skill_area_temp[2] = 0; //For SD_PREAMBLE + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); + } break; - /** - * Warlock - **/ - case WL_STASIS: - if( flag&1 ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + case NPC_WIDESOULDRAIN: + if (flag&1) + status_percent_damage(src,bl,0,((skill_lv-1)%5+1)*20,false); + else { + skill_area_temp[2] = 0; //For SD_PREAMBLE + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); } break; - - case WL_WHITEIMPRISON: - if( (src == bl || battle->check_target(src, bl, BCT_ENEMY) > 0 ) && !is_boss(bl) )// Should not work with bosses. + case ALL_PARTYFLEE: + if( sd && !(flag&1) ) { - int rate = ( sd? sd->status.job_level : 50 ) / 4; - - if( src == bl ) rate = 100; // Success Chance: On self, 100% - else if(bl->type == BL_PC) rate += 20 + 10 * skill_lv; // On Players, (20 + 10 * Skill Level) % - else rate += 40 + 10 * skill_lv; // On Monsters, (40 + 10 * Skill Level) % - - if( sd ) - skill->blockpc_start(sd,skill_id,4000, false); - - if( !(tsc && tsc->data[type]) ){ - i = sc_start2(bl,type,rate,skill_lv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill->get_time(skill_id,skill_lv):skill->get_time2(skill_id, skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); - if( !i ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if( !sd->status.party_id ) + { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } - }else - if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + } + else + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; - - case WL_FROSTMISTY: + case NPC_TALK: + case ALL_WEWISH: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); break; - - case WL_JACKFROST: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinshootrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + case ALL_BUYING_STORE: + if( sd ) + {// players only, skill allows 5 buying slots + clif->skill_nodamage(src, bl, skill_id, skill_lv, buyingstore->setup(sd, MAX_BUYINGSTORE_SLOTS)); + } break; - - case WL_MARSHOFABYSS: - // Should marsh of abyss still apply half reduction to players after the 28/10 patch? [LimitLine] - clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start4(bl, type, 100, skill_lv, status_get_int(src), sd ? sd->status.job_level : 50, 0, - skill->get_time(skill_id, skill_lv))); + case RK_ENCHANTBLADE: + clif->skill_nodamage(src,bl,skill_id,skill_lv,// formula not confirmed + sc_start2(bl,type,100,skill_lv,100+20*skill_lv/*+sstatus->int_/2+status_get_lv(bl)/10*/,skill->get_time(skill_id,skill_lv))); break; - - case WL_SIENNAEXECRATE: - if( status_isimmune(bl) || !tsc ) - break; - - if( flag&1 ) { - if( bl->id == skill_area_temp[1] ) - break; // Already work on this target - - if( tsc && tsc->data[SC_STONE] ) - status_change_end(bl,SC_STONE,INVALID_TIMER); - else - status_change_start(bl,SC_STONE,10000,skill_lv,0,0,1000,skill->get_time(skill_id, skill_lv),2); - } else { - int rate = 40 + 8 * skill_lv + ( sd? sd->status.job_level : 50 ) / 4; - // IroWiki says Rate should be reduced by target stats, but currently unknown - if( rnd()%100 < rate ) { // Success on First Target - if( !tsc->data[SC_STONE] ) - rate = status_change_start(bl,SC_STONE,10000,skill_lv,0,0,1000,skill->get_time(skill_id, skill_lv),2); - else { - rate = 1; - status_change_end(bl,SC_STONE,INVALID_TIMER); - } - - if( rate ) { - skill_area_temp[1] = bl->id; - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); - } - // Doesn't send failure packet if it fails on defense. + case RK_DRAGONHOWLING: + if( flag&1) + sc_start(bl,type,50 + 6 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + else + { + skill_area_temp[2] = 0; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id,skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); + } + break; + case RK_IGNITIONBREAK: + case LG_EARTHDRIVE: + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + i = skill->get_splash(skill_id,skill_lv); + if( skill_id == LG_EARTHDRIVE ) { + int dummy = 1; + iMap->foreachinarea(skill->cell_overlap, src->m, src->x-i, src->y-i, src->x+i, src->y+i, BL_SKILL, LG_EARTHDRIVE, &dummy, src); } - else if( sd ) // Failure on Rate + iMap->foreachinrange(skill->area_sub, bl,i,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + break; + case RK_STONEHARDSKIN: + if( sd ) + { + int heal = sstatus->hp / 4; // 25% HP + if( status_charge(bl,heal,0) ) + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start2(bl,type,100,skill_lv,heal,skill->get_time(skill_id,skill_lv))); + else clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - - case WL_SUMMONFB: - case WL_SUMMONBL: - case WL_SUMMONWB: - case WL_SUMMONSTONE: + case RK_REFRESH: { - short element = 0, sctype = 0, pos = -1; - struct status_change *sc = status_get_sc(src); - if( !sc ) break; - - for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ ) - { - if( !sctype && !sc->data[i] ) - sctype = i; // Take the free SC - if( sc->data[i] ) - pos = max(sc->data[i]->val2,pos); - } - - if( !sctype ) - { - if( sd ) // No free slots to put SC - clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); - break; - } - - pos++; // Used in val2 for SC. Indicates the order of this ball - switch( skill_id ) { // Set val1. The SC element for this ball - case WL_SUMMONFB: element = WLS_FIRE; break; - case WL_SUMMONBL: element = WLS_WIND; break; - case WL_SUMMONWB: element = WLS_WATER; break; - case WL_SUMMONSTONE: element = WLS_STONE; break; - } - - sc_start4(src,sctype,100,element,pos,skill_lv,0,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,0,0); + int heal = status_get_max_hp(bl) * 25 / 100; + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + status_heal(bl,heal,0,1); + status_change_clear_buffs(bl,4); } break; - case WL_READING_SB: - if( sd ) { - struct status_change *sc = status_get_sc(bl); - - for( i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) - if( sc && !sc->data[i] ) - break; - if( i == SC_MAXSPELLBOOK ) { - clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0); - break; - } - - sc_start(bl, SC_STOP, 100, skill_lv, INVALID_TIMER); //Can't move while selecting a spellbook. - clif->spellbook_list(sd); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + case RK_MILLENNIUMSHIELD: + if( sd ){ + short shields = (rnd()%100<50) ? 4 : ((rnd()%100<80) ? 3 : 2); + sc_start4(bl,type,100,skill_lv,shields,1000,0,skill->get_time(skill_id,skill_lv)); + clif->millenniumshield(sd,shields); + clif->skill_nodamage(src,bl,skill_id,1,1); } break; - /** - * Ranger - **/ - case RA_FEARBREEZE: - clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); - break; - case RA_WUGMASTERY: - if( sd ) { - if( !pc_iswug(sd) ) - pc->setoption(sd,sd->sc.option|OPTION_WUG); + case RK_FIGHTINGSPIRIT: + if( flag&1 ) { + if( src == bl ) + sc_start2(bl,type,100,skill_area_temp[5],10*(sd?pc->checkskill(sd,RK_RUNEMASTERY):10),skill->get_time(skill_id,skill_lv)); else - pc->setoption(sd,sd->sc.option&~OPTION_WUG); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start(bl,type,100,skill_area_temp[5]/4,skill->get_time(skill_id,skill_lv)); + } else if( sd ) { + if( sd->status.party_id ) { + i = party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,BCT_PARTY,skill->area_sub_count); + skill_area_temp[5] = 7 * i; // ATK + party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + } else + sc_start2(bl,type,100,7,5,skill->get_time(skill_id,skill_lv)); } + clif->skill_nodamage(src,bl,skill_id,1,1); break; - - case RA_WUGRIDER: - if( sd ) { - if( !pc_isridingwug(sd) && pc_iswug(sd) ) { - pc->setoption(sd,sd->sc.option&~OPTION_WUG); - pc->setoption(sd,sd->sc.option|OPTION_WUGRIDER); - } else if( pc_isridingwug(sd) ) { - pc->setoption(sd,sd->sc.option&~OPTION_WUGRIDER); - pc->setoption(sd,sd->sc.option|OPTION_WUG); + /** + * Guilotine Cross + **/ + case GC_ROLLINGCUTTER: + { + short count = 1; + skill_area_temp[2] = 0; + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill->castend_damage_id); + if( tsc && tsc->data[SC_ROLLINGCUTTER] ) + { // Every time the skill is casted the status change is reseted adding a counter. + count += (short)tsc->data[SC_ROLLINGCUTTER]->val1; + if( count > 10 ) + count = 10; // Max coounter + status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - break; - - case RA_WUGDASH: - if( tsce ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); - return 0; - } - if( sd && pc_isridingwug(sd) ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,1)); - clif->walkok(sd); + sc_start(bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage(src,src,skill_id,skill_lv,1); } break; - case RA_SENSITIVEKEEN: + case GC_WEAPONBLOCKING: + if( tsc && tsc->data[SC_WEAPONBLOCKING] ) + status_change_end(bl, SC_WEAPONBLOCKING, INVALID_TIMER); + else + sc_start(bl,SC_WEAPONBLOCKING,100,skill_lv,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); break; - /** - * Mechanic - **/ - case NC_F_SIDESLIDE: - case NC_B_SIDESLIDE: + + case GC_CREATENEWPOISON: + if( sd ) { - uint8 dir = (skill_id == NC_F_SIDESLIDE) ? (unit_getdir(src)+4)%8 : unit_getdir(src); - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),dir,0x1); - clif->slide(src,src->x,src->y); - clif->fixpos(src); //Aegis sent this packet - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + clif->skill_produce_mix_list(sd,skill_id,25); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; - case NC_SELFDESTRUCTION: + case GC_POISONINGWEAPON: if( sd ) { - if( pc_ismadogear(sd) ) - pc->setmadogear(sd, 0); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); - status_set_sp(src, 0, 0); + clif->poison_list(sd,skill_lv); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - case NC_ANALYZE: - clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(bl,type, 30 + 12 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv))); - if( sd ) pc->overheat(sd,1); - break; - - case NC_MAGNETICFIELD: - if( (i = sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) ) + case GC_ANTIDOTE: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if( tsc ) { - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);; - clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,6); - if (sd) pc->overheat(sd,1); + status_change_end(bl, SC_PARALYSE, INVALID_TIMER); + status_change_end(bl, SC_PYREXIA, INVALID_TIMER); + status_change_end(bl, SC_DEATHHURT, INVALID_TIMER); + status_change_end(bl, SC_LEECHESEND, INVALID_TIMER); + status_change_end(bl, SC_VENOMBLEED, INVALID_TIMER); + status_change_end(bl, SC_MAGICMUSHROOM, INVALID_TIMER); + status_change_end(bl, SC_TOXIN, INVALID_TIMER); + status_change_end(bl, SC_OBLIVIONCURSE, INVALID_TIMER); } - clif->skill_nodamage(src,src,skill_id,skill_lv,i); break; - case NC_REPAIR: - if( sd ) + case GC_PHANTOMMENACE: + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + break; + + case GC_HALLUCINATIONWALK: { - int heal; - if( dstsd && pc_ismadogear(dstsd) ) + int heal = status_get_max_hp(bl) / 10; + if( status_get_hp(bl) < heal ) { // if you haven't enough HP skill fails. + if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); + break; + } + if( !status_charge(bl,heal,0) ) { - heal = dstsd->status.max_hp * (3+3*skill_lv) / 100; - status_heal(bl,heal,0,2); - } else { - heal = sd->status.max_hp * (3+3*skill_lv) / 100; - status_heal(src,heal,0,2); + if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); + break; } - - clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - clif->skill_nodamage(src, bl, skill_id, skill_lv, heal); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + } + break; + /** + * Arch Bishop + **/ + case AB_ANCILLA: + if( sd ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill->produce_mix(sd, skill_id, ITEMID_ANCILLA, 0, 0, 0, 1); } break; - case NC_DISJOINT: + case AB_CLEMENTIA: + case AB_CANTO: { - if( bl->type != BL_MOB ) break; - md = iMap->id2md(bl->id); - if( md && md->class_ >= MOBID_SILVERSNIPER && md->class_ <= MOBID_MAGICDECOY_WIND ) - status_kill(bl); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + int bless_lv = pc->checkskill(sd,AL_BLESSING) + (sd->status.job_level / 10); + int agi_lv = pc->checkskill(sd,AL_INCAGI) + (sd->status.job_level / 10); + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100, + (skill_id == AB_CLEMENTIA)? bless_lv : (skill_id == AB_CANTO)? agi_lv : skill_lv, skill->get_time(skill_id,skill_lv))); + else if( sd ) + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } break; - case SC_AUTOSHADOWSPELL: - if( sd ) { - int idx1 = skill->get_index(sd->reproduceskill_id), idx2 = skill->get_index(sd->cloneskill_id); - if( sd->status.skill[idx1].id || sd->status.skill[idx2].id ) { - sc_start(src,SC_STOP,100,skill_lv,-1);// The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] - clif->autoshadowspell_list(sd); - clif->skill_nodamage(src,bl,skill_id,1,1); - } - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_IMITATION_SKILL_NONE,0); - } + + case AB_PRAEFATIO: + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start4(bl, type, 100, skill_lv, 0, 0, 1, skill->get_time(skill_id, skill_lv))); + else if( sd ) + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case SC_SHADOWFORM: - if( sd && dstsd && src != bl && !dstsd->shadowform_id ) { - if( clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,type,100,skill_lv,bl->id,4+skill_lv,0,skill->get_time(skill_id, skill_lv))) ) - dstsd->shadowform_id = src->id; + case AB_CHEAL: + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) { + if( sd && tstatus && !battle->check_undead(tstatus->race, tstatus->def_ele) ) { + i = skill->calc_heal(src, bl, AL_HEAL, pc->checkskill(sd, AL_HEAL), true); + + if( (dstsd && pc_ismadogear(dstsd)) || status_isimmune(bl)) + i = 0; // Should heal by 0 or won't do anything?? in iRO it breaks the healing to members.. [malufett] + + clif->skill_nodamage(bl, bl, skill_id, i, 1); + if( tsc && tsc->data[SC_AKAITSUKI] && i ) + i = ~i + 1; + status_heal(bl, i, 0, 0); + } } else if( sd ) - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case SC_BODYPAINT: - if( flag&1 ) { - if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || - tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || - tsc->data[SC__INVISIBILITY]) ) { - status_change_end(bl, SC_HIDING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CHASEWALK, INVALID_TIMER); - status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_BLIND,53 + 2 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); - } - } else { - clif->skill_nodamage(src, bl, skill_id, 0, 1); - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, + case AB_ORATIO: + if( flag&1 ) + sc_start(bl, type, 40 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + else + { + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; - case SC_ENERVATION: - case SC_GROOMY: - case SC_LAZINESS: - case SC_UNLUCKY: - case SC_WEAKNESS: - if( !(tsc && tsc->data[type]) ) { - //((rand(myDEX / 12, myDEX / 4) + myJobLevel + 10 * skLevel) + myLevel / 10) - (targetLevel / 10 + targetLUK / 10 + (targetMaxWeight - targetWeight) / 1000 + rand(targetAGI / 6, targetAGI / 3)) - int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 - - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); - rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); - clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv))); + case AB_LAUDAAGNUS: + if( flag&1 || sd == NULL ) { + if( tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] || tsc->data[SC_BLIND] || + tsc->data[SC_BURNING] || tsc->data[SC_FROSTMISTY] || tsc->data[SC_CRYSTALIZE])) { + // Success Chance: (40 + 10 * Skill Level) % + if( rnd()%100 > 40+10*skill_lv ) break; + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_STONE, INVALID_TIMER); + status_change_end(bl, SC_BLIND, INVALID_TIMER); + status_change_end(bl, SC_BURNING, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); + status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); + }else //Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets + clif->skill_nodamage(bl, bl, skill_id, skill_lv, + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); } else if( sd ) - clif->skill_fail(sd,skill_id,0,0); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), + src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case SC_IGNORANCE: - if( !(tsc && tsc->data[type]) ) { - int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 - - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); - rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); - if (clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)))) { - int sp = 200 * skill_lv; - if( dstmd ) sp = dstmd->level * 2; - if( status_zap(bl,0,sp) ) - status_heal(src,0,sp/2,3); - } - else if( sd ) clif->skill_fail(sd,skill_id,0,0); + case AB_LAUDARAMUS: + if( flag&1 || sd == NULL ) { + if( tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || tsc->data[SC_MANDRAGORA] || tsc->data[SC_SILENCE]) ){ + // Success Chance: (40 + 10 * Skill Level) % + if( rnd()%100 > 40+10*skill_lv ) break; + status_change_end(bl, SC_SLEEP, INVALID_TIMER); + status_change_end(bl, SC_STUN, INVALID_TIMER); + status_change_end(bl, SC_MANDRAGORA, INVALID_TIMER); + status_change_end(bl, SC_SILENCE, INVALID_TIMER); + }else // Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets + clif->skill_nodamage(bl, bl, skill_id, skill_lv, + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); } else if( sd ) - clif->skill_fail(sd,skill_id,0,0); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), + src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case LG_TRAMPLE: - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - iMap->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); + case AB_CLEARANCE: + if( flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1 ) + { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 30 + 10 * skill_lv) + { + if (sd) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + if(status_isimmune(bl) || !tsc || !tsc->count) + break; + for(i = 0; i < SC_MAX; i++) + { + if( SC_COMMON_MAX > i ){ + if ( !tsc->data[i] || !status_get_sc_type(i) ) + continue; + if ( status_get_sc_type(i)&SC_NO_CLEARANCE ) + continue; + } + switch (i) { + case SC_ASSUMPTIO: + if( bl->type == BL_MOB ) + continue; + break; + case SC_BERSERK: + case SC_SATURDAY_NIGHT_FEVER: + tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0. + break; + } + status_change_end(bl,(sc_type)i,INVALID_TIMER); + } + break; + } + iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, src, skill_id, skill_lv, tick, flag|1, skill->castend_damage_id); break; - case LG_REFLECTDAMAGE: - if( tsc && tsc->data[type] ) - status_change_end(bl,type,INVALID_TIMER); - else + case AB_SILENTIUM: + // Should the level of Lex Divina be equivalent to the level of Silentium or should the highest level learned be used? [LimitLine] + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, PR_LEXDIVINA, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + /** + * Warlock + **/ + case WL_STASIS: + if( flag&1 ) sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + else + { + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + } break; - case LG_SHIELDSPELL: - if( flag&1 ) { - int duration = (sd) ? sd->bonus.shieldmdef * 2000 : 10000; - sc_start(bl,SC_SILENCE,100,skill_lv,duration); - } else if( sd ) { - int opt = skill_lv; - int rate = rnd()%100; - int val, brate; - switch( skill_lv ) { - case 1: - { - struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; - if( !shield_data || shield_data->type != IT_ARMOR ) { // No shield? - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - break; - } - brate = shield_data->def * 10; - if( rate < 50 ) - opt = 1; - else if( rate < 75 ) - opt = 2; - else - opt = 3; + case WL_WHITEIMPRISON: + if( (src == bl || battle->check_target(src, bl, BCT_ENEMY) > 0 ) && !is_boss(bl) )// Should not work with bosses. + { + int rate = ( sd? sd->status.job_level : 50 ) / 4; - switch( opt ) { - case 1: - sc_start(bl,SC_SHIELDSPELL_DEF,100,opt,-1); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - status_change_end(bl,SC_SHIELDSPELL_DEF,INVALID_TIMER); - break; - case 2: - val = shield_data->def / 10; // % Reflected damage. - sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 1000); - break; - case 3: - val = shield_data->def; // Attack increase. - sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 3000); - break; - } - } - break; + if( src == bl ) rate = 100; // Success Chance: On self, 100% + else if(bl->type == BL_PC) rate += 20 + 10 * skill_lv; // On Players, (20 + 10 * Skill Level) % + else rate += 40 + 10 * skill_lv; // On Monsters, (40 + 10 * Skill Level) % - case 2: - brate = sd->bonus.shieldmdef * 20; - if( rate < 30 ) - opt = 1; - else if( rate < 60 ) - opt = 2; - else - opt = 3; - switch( opt ) { - case 1: - sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|2,skill->castend_damage_id); - status_change_end(bl,SC_SHIELDSPELL_MDEF,INVALID_TIMER); - break; - case 2: - sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); - break; - case 3: - if( sc_start(bl,SC_SHIELDSPELL_MDEF,brate,opt,sd->bonus.shieldmdef * 30000) ) - clif->skill_nodamage(src,bl,PR_MAGNIFICAT,skill_lv, - sc_start(bl,SC_MAGNIFICAT,100,1,sd->bonus.shieldmdef * 30000)); - break; - } - break; + if( sd ) + skill->blockpc_start(sd,skill_id,4000, false); - case 3: - { - struct item *it = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; - if( !it ) { // No shield? - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - brate = it->refine * 5; - if( rate < 25 ) - opt = 1; - else if( rate < 50 ) - opt = 2; - else - opt = 3; - switch( opt ) { - case 1: - val = 105 * it->refine / 10; - sc_start2(bl,SC_SHIELDSPELL_REF,brate,opt,val,skill->get_time(skill_id,skill_lv)); - break; - case 2: case 3: - if( rate < brate ) - { - val = sstatus->max_hp * (11 + it->refine) / 100; - status_heal(bl, val, 0, 3); - } - break; - /*case 3: - // Full protection. I need confirm what effect should be here. Moved to case 2 to until we got it. - break;*/ - } - } - break; + if( !(tsc && tsc->data[type]) ){ + i = sc_start2(bl,type,rate,skill_lv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill->get_time(skill_id,skill_lv):skill->get_time2(skill_id, skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,i); + if( sd && !i ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } + }else + if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0); break; - case LG_PIETY: - if( flag&1 ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else { - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } + case WL_FROSTMISTY: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); break; - case LG_INSPIRATION: - if( sd && !map[sd->bl.m].flag.noexppenalty && sd->status.base_level != MAX_LEVEL ) { - sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * 1 / 100); // 1% penalty. - sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * 1 / 100); - clif->updatestatus(sd,SP_BASEEXP); - clif->updatestatus(sd,SP_JOBEXP); - } - clif->skill_nodamage(bl,src,skill_id,skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); - break; - case SR_CURSEDCIRCLE: - if( flag&1 ) { - if( is_boss(bl) ) break; - if( sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id, skill_lv))) { - if( bl->type == BL_MOB ) - mob_unlocktarget((TBL_MOB*)bl,iTimer->gettick()); - unit_stop_attack(bl); - clif->bladestop(src, bl->id, 1); - iMap->freeblock_unlock(); - return 1; - } - } else { - int count = 0; - clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - count = iMap->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors - BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - if( sd ) pc->delspiritball(sd, count, 0); - clif->skill_nodamage(src, src, skill_id, skill_lv, - sc_start2(src, SC_CURSEDCIRCLE_ATKER, 100, skill_lv, count, skill->get_time(skill_id,skill_lv))); - } + case WL_JACKFROST: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->foreachinshootrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); break; - case SR_RAISINGDRAGON: - if( sd ) { - short max = 5 + skill_lv; - sc_start(bl, SC_EXPLOSIONSPIRITS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - for( i = 0; i < max; i++ ) // Don't call more than max available spheres. - pc->addspiritball(sd, skill->get_time(skill_id, skill_lv), max); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv))); - } + case WL_MARSHOFABYSS: + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; - case SR_ASSIMILATEPOWER: + case WL_SIENNAEXECRATE: if( flag&1 ) { - i = 0; - if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) - { - i = dstsd->spiritball; //1%sp per spiritball. - pc->delspiritball(dstsd, dstsd->spiritball, 0); - } - if( i ) status_percent_heal(src, 0, i); - clif->skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0); + if( status_isimmune(bl) || !tsc ) + break; + if( tsc && tsc->data[SC_STONE] ) + status_change_end(bl,SC_STONE,INVALID_TIMER); + else + status_change_start(bl,SC_STONE,10000,skill_lv,0,0,500,skill->get_time(skill_id, skill_lv),2); } else { - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id); + int rate = 45 + 5 * skill_lv; + if( rnd()%100 < rate ){ + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + iMap->foreachinrange(skill_area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_nodamage_id); + }else if( sd ) // Failure on Rate + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - case SR_POWERVELOCITY: - if( !dstsd ) - break; - if( sd && dstsd->spiritball <= 5 ) { - for(i = 0; i <= 5; i++) { - pc->addspiritball(dstsd, skill->get_time(MO_CALLSPIRITS, pc->checkskill(sd,MO_CALLSPIRITS)), i); - pc->delspiritball(sd, sd->spiritball, 0); + case WL_SUMMONFB: + case WL_SUMMONBL: + case WL_SUMMONWB: + case WL_SUMMONSTONE: + for( i = SC_SUMMON1; i <= SC_SUMMON5; i++ ){ + if( tsc && !tsc->data[i] ){ // officially it doesn't work like a stack + int ele = WLS_FIRE + (skill_id - WL_SUMMONFB) - (skill_id == WL_SUMMONSTONE ? 4 : 0); + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(bl, (sc_type)i, 100, ele, skill->get_time(skill_id, skill_lv))); + break; } } - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); break; - case SR_GENTLETOUCH_CURE: - { - int heal; + case WL_READING_SB: + if( sd ) { + struct status_change *sc = status_get_sc(bl); - if( status_isimmune(bl) ) - { - clif->skill_nodamage(src,bl,skill_id,skill_lv,0); + for( i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) + if( sc && !sc->data[i] ) + break; + if( i == SC_SPELLBOOK7 ) { + clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0); break; } - heal = 120 * skill_lv + status_get_max_hp(bl) * (2 + skill_lv) / 100; - status_heal(bl, heal, 0, 0); + sc_start(bl, SC_STOP, 100, skill_lv, INVALID_TIMER); //Can't move while selecting a spellbook. + clif->spellbook_list(sd); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + break; + /** + * Ranger + **/ + case RA_FEARBREEZE: + clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + break; - if( (tsc && tsc->opt1) && (rnd()%100 < ((skill_lv * 5) + (status_get_dex(src) + status_get_lv(src)) / 4) - (1 + (rnd() % 10))) ) - { - status_change_end(bl, SC_STONE, INVALID_TIMER); - status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_STUN, INVALID_TIMER); - status_change_end(bl, SC_POISON, INVALID_TIMER); - status_change_end(bl, SC_SILENCE, INVALID_TIMER); - status_change_end(bl, SC_BLIND, INVALID_TIMER); - status_change_end(bl, SC_HALLUCINATION, INVALID_TIMER); - status_change_end(bl, SC_BURNING, INVALID_TIMER); - status_change_end(bl, SC_FREEZING, INVALID_TIMER); - } + case RA_WUGMASTERY: + if( sd ) { + if( !pc_iswug(sd) ) + pc->setoption(sd,sd->sc.option|OPTION_WUG); + else + pc->setoption(sd,sd->sc.option&~OPTION_WUG); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; + case RA_WUGRIDER: + if( sd ) { + if( !pc_isridingwug(sd) && pc_iswug(sd) ) { + pc->setoption(sd,sd->sc.option&~OPTION_WUG); + pc->setoption(sd,sd->sc.option|OPTION_WUGRIDER); + } else if( pc_isridingwug(sd) ) { + pc->setoption(sd,sd->sc.option&~OPTION_WUGRIDER); + pc->setoption(sd,sd->sc.option|OPTION_WUG); + } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - case SR_GENTLETOUCH_CHANGE: - case SR_GENTLETOUCH_REVITALIZE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); + + case RA_WUGDASH: + if( tsce ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); + iMap->freeblock_unlock(); + return 0; + } + if( sd && pc_isridingwug(sd) ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,1)); + clif->walkok(sd); + } break; - case WA_SWING_DANCE: - case WA_MOONLIT_SERENADE: - if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else if( sd ) { // Only shows effects on caster. + + case RA_SENSITIVEKEEN: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); + break; + /** + * Mechanic + **/ + case NC_F_SIDESLIDE: + case NC_B_SIDESLIDE: + { + uint8 dir = (skill_id == NC_F_SIDESLIDE) ? (unit_getdir(src)+4)%8 : unit_getdir(src); + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),dir,0); + clif->slide(src,src->x,src->y); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } break; - case WA_SYMPHONY_OF_LOVER: - case MI_RUSH_WINDMILL: - case MI_ECHOSONG: - if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - sc_start4(bl,type,100,skill_lv,6*skill_lv,(sd?pc->checkskill(sd,WM_LESSON):0),(sd?sd->status.job_level:0),skill->get_time(skill_id,skill_lv)); - else if( sd ) { // Only shows effects on caster. - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + case NC_SELFDESTRUCTION: + if( sd ) { + if( pc_ismadogear(sd) ) + pc->setmadogear(sd, 0); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); + status_set_sp(src, 0, 0); } break; - case MI_HARMONIZE: - if( src != bl ) - clif->skill_nodamage(src, src, skill_id, skill_lv, sc_start(src, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); + case NC_ANALYZE: + clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(bl,type, 30 + 12 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv))); + if( sd ) pc->overheat(sd,1); break; - case WM_DEADHILLHERE: - if( bl->type == BL_PC ) { - if( !status_isdead(bl) ) - break; + case NC_MAGNETICFIELD: + if( (i = sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) ) + { + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill->castend_damage_id);; + clif->skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,6); + if (sd) pc->overheat(sd,1); + } + clif->skill_nodamage(src,src,skill_id,skill_lv,i); + break; - if( rnd()%100 < 88 + 2 * skill_lv ) { - int heal = tstatus->sp; - if( heal <= 0 ) - heal = 1; - tstatus->hp = heal; - tstatus->sp -= tstatus->sp * ( 120 - 20 * skill_lv ) / 100; - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - pc->revive((TBL_PC*)bl,heal,0); - clif->resurrection(bl,1); + case NC_REPAIR: + if( sd ) + { + int heal; + if( dstsd && pc_ismadogear(dstsd) ) + { + heal = dstsd->status.max_hp * (3+3*skill_lv) / 100; + status_heal(bl,heal,0,2); + } else { + heal = sd->status.max_hp * (3+3*skill_lv) / 100; + status_heal(src,heal,0,2); + } + + clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + clif->skill_nodamage(src, bl, skill_id, skill_lv, heal); + } + break; + + case NC_DISJOINT: + { + if( bl->type != BL_MOB ) break; + md = iMap->id2md(bl->id); + if( md && md->class_ >= MOBID_SILVERSNIPER && md->class_ <= MOBID_MAGICDECOY_WIND ) + status_kill(bl); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + break; + case SC_AUTOSHADOWSPELL: + if( sd ) { + int idx1 = skill->get_index(sd->reproduceskill_id), idx2 = skill->get_index(sd->cloneskill_id); + if( sd->status.skill[idx1].id || sd->status.skill[idx2].id ) { + sc_start(src,SC_STOP,100,skill_lv,-1);// The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] + clif->autoshadowspell_list(sd); + clif->skill_nodamage(src,bl,skill_id,1,1); } + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL_IMITATION_SKILL_NONE,0); } break; - case WM_SIRCLEOFNATURE: - flag |= BCT_SELF|BCT_PARTY|BCT_GUILD; - case WM_VOICEOFSIREN: - if( skill_id != WM_SIRCLEOFNATURE ) - flag &= ~BCT_SELF; + case SC_SHADOWFORM: + if( sd && dstsd && src != bl && !dstsd->shadowform_id ) { + if( clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,type,100,skill_lv,bl->id,4+skill_lv,0,skill->get_time(skill_id, skill_lv))) ) + dstsd->shadowform_id = src->id; + } + else if( sd ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + + case SC_BODYPAINT: if( flag&1 ) { - sc_start2(bl,type,(skill_id==WM_VOICEOFSIREN)?20+10*skill_lv:100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv)); + if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || + tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || + tsc->data[SC__INVISIBILITY]) ) { + status_change_end(bl, SC_HIDING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CHASEWALK, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); + + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(bl,SC_BLIND,53 + 2 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + } } else { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + clif->skill_nodamage(src, bl, skill_id, 0, 1); + iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); } break; - case WM_GLOOMYDAY: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if( dstsd && ( pc->checkskill(dstsd,KN_BRANDISHSPEAR) || pc->checkskill(dstsd,LK_SPIRALPIERCE) || - pc->checkskill(dstsd,CR_SHIELDCHARGE) || pc->checkskill(dstsd,CR_SHIELDBOOMERANG) || - pc->checkskill(dstsd,PA_SHIELDCHAIN) || pc->checkskill(dstsd,LG_SHIELDPRESS) ) ) - { - sc_start(bl,SC_GLOOMYDAY_SK,100,skill_lv,skill->get_time(skill_id,skill_lv)); - break; - } - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + case SC_ENERVATION: + case SC_GROOMY: + case SC_LAZINESS: + case SC_UNLUCKY: + case SC_WEAKNESS: + if( !(tsc && tsc->data[type]) ) { + //((rand(myDEX / 12, myDEX / 4) + myJobLevel + 10 * skLevel) + myLevel / 10) - (targetLevel / 10 + targetLUK / 10 + (targetMaxWeight - targetWeight) / 1000 + rand(targetAGI / 6, targetAGI / 3)) + int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 + - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); + rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); + clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv))); + } else if( sd ) + clif->skill_fail(sd,skill_id,0,0); break; - case WM_SATURDAY_NIGHT_FEVER: - if( flag&1 ) { // Affect to all targets arround the caster and caster too. - if( !(tsc && tsc->data[type]) ) - sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); - } else if( flag&2 ) { - if( src->id != bl->id && battle->check_target(src,bl,BCT_ENEMY) > 0 ) - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); - } else if( sd ) { - short chance = sstatus->int_/6 + sd->status.job_level/5 + skill_lv*4; - if( !sd->status.party_id || (rnd()%100 > chance)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_HELPER,0); - break; + case SC_IGNORANCE: + if( !(tsc && tsc->data[type]) ) { + int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 + - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); + rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); + if (clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)))) { + int sp = 200 * skill_lv; + if( dstmd ) sp = dstmd->level * 2; + if( status_zap(bl,0,sp) ) + status_heal(src,0,sp/2,3); } - if( iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id,skill_lv), - BL_PC, src, skill_id, skill_lv, tick, BCT_ENEMY, skill->area_sub_count) > 7 ) - flag |= 2; - else - flag |= 1; - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF, skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(src,SC_STOP,100,skill_lv,skill->get_time2(skill_id,skill_lv))); - if( flag&2 ) // Dealed here to prevent conflicts - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); - } + else if( sd ) clif->skill_fail(sd,skill_id,0,0); + } else if( sd ) + clif->skill_fail(sd,skill_id,0,0); break; - case WM_SONG_OF_MANA: - case WM_DANCE_WITH_WUG: - case WM_LERADS_DEW: - if( flag&1 ) { // These affect to to all party members near the caster. - struct status_change *sc = status_get_sc(src); - if( sc && sc->data[type] ) { - sc_start2(bl,type,100,skill_lv,sc->data[type]->val2,skill->get_time(skill_id,skill_lv)); - } - } else if( sd ) { - short lv = (short)skill_lv; - int count = skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1); - if( sc_start2(bl,type,100,skill_lv,count,skill->get_time(skill_id,skill_lv)) ) - party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + case LG_TRAMPLE: + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + iMap->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); + break; - } + case LG_REFLECTDAMAGE: + if( tsc && tsc->data[type] ) + status_change_end(bl,type,INVALID_TIMER); + else + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; - case WM_MELODYOFSINK: - case WM_BEYOND_OF_WARCRY: - case WM_UNLIMITED_HUMMING_VOICE: + case LG_SHIELDSPELL: if( flag&1 ) { - sc_start2(bl,type,100,skill_lv,skill_area_temp[0],skill->get_time(skill_id,skill_lv)); - } else { // These affect to all targets arround the caster. - short lv = (short)skill_lv; - skill_area_temp[0] = (sd) ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1) : 50; // 50% chance in non BL_PC (clones). - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - break; + int duration = (sd) ? sd->bonus.shieldmdef * 2000 : 10000; + sc_start(bl,SC_SILENCE,100,skill_lv,duration); + } else if( sd ) { + int opt = skill_lv; + int rate = rnd()%100; + int val, brate; + switch( skill_lv ) { + case 1: + { + struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; + if( !shield_data || shield_data->type != IT_ARMOR ) { // No shield? + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + brate = shield_data->def * 10; + if( rate < 50 ) + opt = 1; + else if( rate < 75 ) + opt = 2; + else + opt = 3; - case WM_RANDOMIZESPELL: { - int improv_skill_id = 0, improv_skill_lv; - do { - i = rnd() % MAX_SKILL_IMPROVISE_DB; - improv_skill_id = skill_improvise_db[i].skill_id; - } while( improv_skill_id == 0 || rnd()%10000 >= skill_improvise_db[i].per ); - improv_skill_lv = 4 + skill_lv; - clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); + switch( opt ) { + case 1: + sc_start(bl,SC_SHIELDSPELL_DEF,100,opt,-1); + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + if( rate < brate ) + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + status_change_end(bl,SC_SHIELDSPELL_DEF,INVALID_TIMER); + break; + case 2: + val = shield_data->def / 10; // % Reflected damage. + sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 1000); + break; + case 3: + val = shield_data->def; // Attack increase. + sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 3000); + break; + } + } + break; - if( sd ) { - sd->state.abra_flag = 2; - sd->skillitem = improv_skill_id; - sd->skillitemlv = improv_skill_lv; - clif->item_skill(sd, improv_skill_id, improv_skill_lv); - } else { - struct unit_data *ud = unit_bl2ud(src); - int inf = skill->get_inf(improv_skill_id); - if (!ud) break; - if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { - if (src->type == BL_PET) - bl = (struct block_list*)((TBL_PET*)src)->msd; - if (!bl) bl = src; - unit_skilluse_id(src, bl->id, improv_skill_id, improv_skill_lv); - } else { - int target_id = 0; - if (ud->target) - target_id = ud->target; - else switch (src->type) { - case BL_MOB: target_id = ((TBL_MOB*)src)->target_id; break; - case BL_PET: target_id = ((TBL_PET*)src)->target_id; break; + case 2: + brate = sd->bonus.shieldmdef * 20; + if( rate < 30 ) + opt = 1; + else if( rate < 60 ) + opt = 2; + else + opt = 3; + switch( opt ) { + case 1: + sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + if( rate < brate ) + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|2,skill->castend_damage_id); + status_change_end(bl,SC_SHIELDSPELL_MDEF,INVALID_TIMER); + break; + case 2: + sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + if( rate < brate ) + iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); + break; + case 3: + if( sc_start(bl,SC_SHIELDSPELL_MDEF,brate,opt,sd->bonus.shieldmdef * 30000) ) + clif->skill_nodamage(src,bl,PR_MAGNIFICAT,skill_lv, + sc_start(bl,SC_MAGNIFICAT,100,1,sd->bonus.shieldmdef * 30000)); + break; + } + break; + + case 3: + { + struct item *it = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; + if( !it ) { // No shield? + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + brate = it->refine * 5; + if( rate < 25 ) + opt = 1; + else if( rate < 50 ) + opt = 2; + else + opt = 3; + switch( opt ) { + case 1: + val = 105 * it->refine / 10; + sc_start2(bl,SC_SHIELDSPELL_REF,brate,opt,val,skill->get_time(skill_id,skill_lv)); + break; + case 2: case 3: + if( rate < brate ) + { + val = sstatus->max_hp * (11 + it->refine) / 100; + status_heal(bl, val, 0, 3); + } + break; + /*case 3: + // Full protection. I need confirm what effect should be here. Moved to case 2 to until we got it. + break;*/ } - if (!target_id) - break; - if (skill->get_casttype(improv_skill_id) == CAST_GROUND) { - bl = iMap->id2bl(target_id); - if (!bl) bl = src; - unit_skilluse_pos(src, bl->x, bl->y, improv_skill_id, improv_skill_lv); - } else - unit_skilluse_id(src, target_id, improv_skill_id, improv_skill_lv); } + break; } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - - case RETURN_TO_ELDICASTES: - case ALL_GUARDIAN_RECALL: - if( sd ) - { - short x, y; // Destiny position. - unsigned short mapindex; - - if( skill_id == RETURN_TO_ELDICASTES) - { - x = 198; - y = 187; - mapindex = mapindex_name2id(MAP_DICASTES); - } - else + case LG_PIETY: + if( flag&1 ) + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else { + skill_area_temp[2] = 0; + iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; + case LG_KINGS_GRACE: + if( flag&1 ){ + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + for(i=0; idata[i]) + continue; + switch(i){ + case SC_POISON: case SC_BLIND: + case SC_FREEZE: case SC_STONE: + case SC_STUN: case SC_SLEEP: + case SC_BLOODING: case SC_CURSE: + case SC_CONFUSION: case SC_ILLUSION: + case SC_SILENCE: case SC_BURNING: + case SC_CRYSTALIZE: case SC_FROSTMISTY: + case SC_DEEP_SLEEP: case SC_FEAR: + case SC_MANDRAGORA: + status_change_end(bl, (sc_type)i, INVALID_TIMER); + } } - - if(!mapindex) - { //Given map not found? - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + }else { + skill_area_temp[2] = 0; + if( !map_flag_vs(src->m) && !map_flag_gvg(src->m) ) + flag |= BCT_GUILD; + iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; + case LG_INSPIRATION: + if( sd && !map[sd->bl.m].flag.noexppenalty && sd->status.base_level != MAX_LEVEL ) { + sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * 1 / 100); // 1% penalty. + sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * 1 / 100); + clif->updatestatus(sd,SP_BASEEXP); + clif->updatestatus(sd,SP_JOBEXP); + } + clif->skill_nodamage(bl,src,skill_id,skill_lv, + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + break; + case SR_CURSEDCIRCLE: + if( flag&1 ) { + if( is_boss(bl) ) break; + if( sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id, skill_lv))) { + if( bl->type == BL_MOB ) + mob_unlocktarget((TBL_MOB*)bl,iTimer->gettick()); + unit_stop_attack(bl); + clif->bladestop(src, bl->id, 1); iMap->freeblock_unlock(); - return 0; + return 1; } - pc->setpos(sd, mapindex, x, y, CLR_TELEPORT); + } else { + int count = 0; + clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + count = iMap->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors + BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + if( sd ) pc->delspiritball(sd, count, 0); + clif->skill_nodamage(src, src, skill_id, skill_lv, + sc_start2(src, SC_CURSEDCIRCLE_ATKER, 100, skill_lv, count, skill->get_time(skill_id,skill_lv))); } break; - case GM_SANDMAN: - if( tsc ) { - if( tsc->opt1 == OPT1_SLEEP ) - tsc->opt1 = 0; - else - tsc->opt1 = OPT1_SLEEP; - clif->changeoption(bl); - clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); + case SR_RAISINGDRAGON: + if( sd ) { + short max = 5 + skill_lv; + sc_start(bl, SC_EXPLOSIONSPIRITS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + for( i = 0; i < max; i++ ) // Don't call more than max available spheres. + pc->addspiritball(sd, skill->get_time(skill_id, skill_lv), max); + clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv))); } break; - case SO_ARRULLO: - { - // [(15 + 5 * Skill Level) + ( Caster�s INT / 5 ) + ( Caster�s Job Level / 5 ) - ( Target�s INT / 6 ) - ( Target�s LUK / 10 )] % - int rate = (15 + 5 * skill_lv) + status_get_int(src)/5 + (sd ? sd->status.job_level : 0); - rate -= status_get_int(bl)/6 - status_get_luk(bl)/10; - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - sc_start2(bl, type, rate, skill_lv, 1, skill->get_time(skill_id, skill_lv)); + case SR_ASSIMILATEPOWER: + if( flag&1 ) { + i = 0; + if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) + { + i = dstsd->spiritball; //1%sp per spiritball. + pc->delspiritball(dstsd, dstsd->spiritball, 0); + } + if( i ) status_percent_heal(src, 0, i); + clif->skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0); + } else { + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id); } break; - case WM_LULLABY_DEEPSLEEP: - if( flag&1 ){ - //[(Skill Level x 4) + (Voice Lessons Skill Level x 2) + (Caster�s Base Level / 15) + (Caster�s Job Level / 5)] % - int rate = (4 * skill_lv) + ( (sd) ? pc->checkskill(sd,WM_LESSON)*2 + sd->status.job_level/5 : 0 ) + status_get_lv(src) / 15; - if( bl != src ) - sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)); - }else { - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ALL|1, skill->castend_nodamage_id); + case SR_POWERVELOCITY: + if( !dstsd ) + break; + if( sd && dstsd->spiritball <= 5 ) { + for(i = 0; i <= 5; i++) { + pc->addspiritball(dstsd, skill->get_time(MO_CALLSPIRITS, pc->checkskill(sd,MO_CALLSPIRITS)), i); + pc->delspiritball(sd, sd->spiritball, 0); + } } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); break; - case SO_SUMMON_AGNI: - case SO_SUMMON_AQUA: - case SO_SUMMON_VENTUS: - case SO_SUMMON_TERA: - if( sd ) { - int elemental_class = skill->get_elemental_type(skill_id,skill_lv); - - // Remove previous elemental fisrt. - if( sd->ed ) - elemental_delete(sd->ed,0); + case SR_GENTLETOUCH_CURE: + { + int heal; - // Summoning the new one. - if( !elemental_create(sd,elemental_class,skill->get_time(skill_id,skill_lv)) ) { - clif->skill_fail(sd,skill_id,0,0); + if( status_isimmune(bl) ) + { + clif->skill_nodamage(src,bl,skill_id,skill_lv,0); break; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - break; - - case SO_EL_CONTROL: - if( sd ) { - int mode = EL_MODE_PASSIVE; // Standard mode. - if( !sd->ed ) break; + heal = 120 * skill_lv + status_get_max_hp(bl) * (2 + skill_lv) / 100; + status_heal(bl, heal, 0, 0); - if( skill_lv == 4 ) {// At level 4 delete elementals. - elemental_delete(sd->ed, 0); - break; - } - switch( skill_lv ) {// Select mode bassed on skill level used. - case 2: mode = EL_MODE_ASSIST; break; - case 3: mode = EL_MODE_AGGRESSIVE; break; - } - if( !elemental_change_mode(sd->ed,mode) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + if( (tsc && tsc->opt1) && (rnd()%100 < ((skill_lv * 5) + (status_get_dex(src) + status_get_lv(src)) / 4) - (1 + (rnd() % 10))) ) + { + status_change_end(bl, SC_STONE, INVALID_TIMER); + status_change_end(bl, SC_FREEZE, INVALID_TIMER); + status_change_end(bl, SC_STUN, INVALID_TIMER); + status_change_end(bl, SC_POISON, INVALID_TIMER); + status_change_end(bl, SC_SILENCE, INVALID_TIMER); + status_change_end(bl, SC_BLIND, INVALID_TIMER); + status_change_end(bl, SC_ILLUSION, INVALID_TIMER); + status_change_end(bl, SC_BURNING, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - break; - case SO_EL_ACTION: - if( sd ) { - int duration = 3000; - if( !sd->ed ) break; - sd->skill_id_old = skill_id; - elemental_action(sd->ed, bl, tick); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - switch(sd->ed->db->class_){ - case 2115:case 2124: - case 2118:case 2121: - duration = 6000; - break; - case 2116:case 2119: - case 2122:case 2125: - duration = 9000; - break; - } - skill->blockpc_start(sd, skill_id, duration, false); } break; - - case SO_EL_CURE: - if( sd ) { - struct elemental_data *ed = sd->ed; - int s_hp = sd->battle_status.hp * 10 / 100, s_sp = sd->battle_status.sp * 10 / 100; - int e_hp, e_sp; - - if( !ed ) break; - if( !status_charge(&sd->bl,s_hp,s_sp) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - e_hp = ed->battle_status.max_hp * 10 / 100; - e_sp = ed->battle_status.max_sp * 10 / 100; - status_heal(&ed->bl,e_hp,e_sp,3); - clif->skill_nodamage(src,&ed->bl,skill_id,skill_lv,1); - } + case SR_GENTLETOUCH_CHANGE: + case SR_GENTLETOUCH_REVITALIZE: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); break; - - case GN_CHANGEMATERIAL: - case SO_EL_ANALYSIS: - if( sd ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - clif->skill_itemlistwindow(sd,skill_id,skill_lv); - } + case SR_FLASHCOMBO: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + for(i = SR_FLASHCOMBO_ATK_STEP1; i <= SR_FLASHCOMBO_ATK_STEP4; i++) + skill->addtimerskill(src, tick + 600 * (i - SR_FLASHCOMBO_ATK_STEP1), bl->id, 0, 0, i, skill_lv, BF_WEAPON, flag|SD_LEVEL); break; - - case GN_BLOOD_SUCKER: - { - struct status_change *sc = status_get_sc(src); - - if( sc && sc->bs_counter < skill->get_maxcount( skill_id , skill_lv) ) { - if( tsc && tsc->data[type] ){ - (sc->bs_counter)--; - status_change_end(src, type, INVALID_TIMER); // the first one cancels and the last one will take effect resetting the timer - } - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); - (sc->bs_counter)++; - } else if( sd ) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - break; - } + case WA_SWING_DANCE: + case WA_MOONLIT_SERENADE: + if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else if( sd ) { // Only shows effects on caster. + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } break; - case GN_MANDRAGORA: - if( flag&1 ) { - if ( clif->skill_nodamage(bl, src, skill_id, skill_lv, - sc_start(bl, type, 25 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv))) ) - status_zap(bl, 0, status_get_max_sp(bl) * (25 + 5 * skill_lv) / 100); - } else - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + case WA_SYMPHONY_OF_LOVER: + case MI_RUSH_WINDMILL: + case MI_ECHOSONG: + if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) + sc_start4(bl,type,100,skill_lv,6*skill_lv,(sd?pc->checkskill(sd,WM_LESSON):0),(sd?sd->status.job_level:0),skill->get_time(skill_id,skill_lv)); + else if( sd ) { // Only shows effects on caster. + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + } break; - case GN_SLINGITEM: - if( sd ) { - short ammo_id; - i = sd->equip_index[EQI_AMMO]; - if( i <= 0 ) - break; // No ammo. - ammo_id = sd->inventory_data[i]->nameid; - if( ammo_id <= 0 ) + case MI_HARMONIZE: + if( src != bl ) + clif->skill_nodamage(src, src, skill_id, skill_lv, sc_start(src, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); + break; + + case WM_DEADHILLHERE: + if( bl->type == BL_PC ) { + if( !status_isdead(bl) ) break; - sd->itemid = ammo_id; - if( itemdb_is_GNbomb(ammo_id) ) { - if(battle->check_target(src,bl,BCT_ENEMY) > 0) {// Only attack if the target is an enemy. - if( ammo_id == 13263 ) - iMap->foreachincell(skill->area_sub,bl->m,bl->x,bl->y,BL_CHAR,src,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - else - skill->attack(BF_WEAPON,src,src,bl,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag); - } else //Otherwise, it fails, shows animation and removes items. - clif->skill_fail(sd,GN_SLINGITEM_RANGEMELEEATK,0xa,0); - } else if( itemdb_is_GNthrowable(ammo_id) ){ - struct script_code *script = sd->inventory_data[i]->script; - if( !script ) - break; - if( dstsd ) - run_script(script,0,dstsd->bl.id,fake_nd->bl.id); - else - run_script(script,0,src->id,0); + + if( rnd()%100 < 88 + 2 * skill_lv ) { + int heal = tstatus->sp; + if( heal <= 0 ) + heal = 1; + tstatus->hp = heal; + tstatus->sp -= tstatus->sp * ( 120 - 20 * skill_lv ) / 100; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + pc->revive((TBL_PC*)bl,heal,0); + clif->resurrection(bl,1); } } - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1);// This packet is received twice actually, I think it is to show the animation. break; - case GN_MIX_COOKING: - case GN_MAKEBOMB: - case GN_S_PHARMACY: - if( sd ) { - int qty = 1; - sd->skill_id_old = skill_id; - sd->skill_lv_old = skill_lv; - if( skill_id != GN_S_PHARMACY && skill_lv > 1 ) - qty = 10; - clif->cooking_list(sd,(skill_id - GN_MIX_COOKING) + 27,skill_id,qty,skill_id==GN_MAKEBOMB?5:6); + case WM_SIRCLEOFNATURE: + flag |= BCT_SELF|BCT_PARTY|BCT_GUILD; + case WM_VOICEOFSIREN: + if( skill_id != WM_SIRCLEOFNATURE ) + flag &= ~BCT_SELF; + if( flag&1 ) { + sc_start2(bl,type,(skill_id==WM_VOICEOFSIREN)?20+10*skill_lv:100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv)); + } else { + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - case EL_CIRCLE_OF_FIRE: - case EL_PYROTECHNIC: - case EL_HEATER: - case EL_TROPIC: - case EL_AQUAPLAY: - case EL_COOLER: - case EL_CHILLY_AIR: - case EL_GUST: - case EL_BLAST: - case EL_WILD_STORM: - case EL_PETROLOGY: - case EL_CURSED_SOIL: - case EL_UPHEAVAL: - case EL_FIRE_CLOAK: - case EL_WATER_DROP: - case EL_WIND_CURTAIN: - case EL_SOLID_SKIN: - case EL_STONE_SHIELD: - case EL_WIND_STEP: { - struct elemental_data *ele = BL_CAST(BL_ELEM, src); - if( ele ) { - sc_type type2 = type-1; - struct status_change *sc = status_get_sc(&ele->bl); - if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { - elemental_clean_single_effect(ele, skill_id); - } else { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - clif->skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( skill_id == EL_WIND_STEP ) // There aren't teleport, just push the master away. - skill->blown(src,bl,(rnd()%skill->get_blewcount(skill_id,skill_lv))+1,rand()%8,0); - sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - } + case WM_GLOOMYDAY: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + if( dstsd && ( pc->checkskill(dstsd,KN_BRANDISHSPEAR) || pc->checkskill(dstsd,LK_SPIRALPIERCE) || + pc->checkskill(dstsd,CR_SHIELDCHARGE) || pc->checkskill(dstsd,CR_SHIELDBOOMERANG) || + pc->checkskill(dstsd,PA_SHIELDCHAIN) || pc->checkskill(dstsd,LG_SHIELDPRESS) ) ) + { + sc_start(bl,SC_GLOOMYDAY_SK,100,skill_lv,skill->get_time(skill_id,skill_lv)); + break; } - } + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; - case EL_FIRE_MANTLE: - case EL_WATER_BARRIER: - case EL_ZEPHYR: - case EL_POWER_OF_GAIA: - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - skill->unitsetting(src,skill_id,skill_lv,bl->x,bl->y,0); + case WM_SATURDAY_NIGHT_FEVER: + if( flag&1 ) { // Affect to all targets arround the caster and caster too. + if( !(tsc && tsc->data[type]) ) + sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); + } else if( flag&2 ) { + if( src->id != bl->id && battle->check_target(src,bl,BCT_ENEMY) > 0 ) + status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); + } else if( sd ) { + short chance = sstatus->int_/6 + sd->status.job_level/5 + skill_lv*4; + if( !sd->status.party_id || (rnd()%100 > chance)) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_HELPER,0); + break; + } + if( iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id,skill_lv), + BL_PC, src, skill_id, skill_lv, tick, BCT_ENEMY, skill->area_sub_count) > 7 ) + flag |= 2; + else + flag |= 1; + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF, skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(src,SC_STOP,100,skill_lv,skill->get_time2(skill_id,skill_lv))); + if( flag&2 ) // Dealed here to prevent conflicts + status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); + } break; - case EL_WATER_SCREEN: { - struct elemental_data *ele = BL_CAST(BL_ELEM, src); - if( ele ) { - struct status_change *sc = status_get_sc(&ele->bl); - sc_type type2 = type-1; - - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { - elemental_clean_single_effect(ele, skill_id); - } else { - // This not heals at the end. - clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,type,100,src->id,skill->get_time(skill_id,skill_lv)); - } + case WM_SONG_OF_MANA: + case WM_DANCE_WITH_WUG: + case WM_LERADS_DEW: + if( flag&1 ) { // These affect to to all party members near the caster. + struct status_change *sc = status_get_sc(src); + if( sc && sc->data[type] ) { + sc_start2(bl,type,100,skill_lv,sc->data[type]->val2,skill->get_time(skill_id,skill_lv)); } + } else if( sd ) { + short lv = (short)skill_lv; + int count = skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1); + if( sc_start2(bl,type,100,skill_lv,count,skill->get_time(skill_id,skill_lv)) ) + party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } break; - case KO_KAHU_ENTEN: - case KO_HYOUHU_HUBUKI: - case KO_KAZEHU_SEIRAN: - case KO_DOHU_KOUKAI: - if(sd) { - int ttype = skill->get_ele(skill_id, skill_lv); - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - pc->add_talisman(sd, skill->get_time(skill_id, skill_lv), 10, ttype); + case WM_MELODYOFSINK: + case WM_BEYOND_OF_WARCRY: + case WM_UNLIMITED_HUMMING_VOICE: + if( flag&1 ) { + sc_start2(bl,type,100,skill_lv,skill_area_temp[0],skill->get_time(skill_id,skill_lv)); + } else { // These affect to all targets arround the caster. + short lv = (short)skill_lv; + skill_area_temp[0] = (sd) ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1) : 50; // 50% chance in non BL_PC (clones). + iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - case KO_ZANZOU: - if(sd){ - struct mob_data *md; + case WM_RANDOMIZESPELL: { + int improv_skill_id = 0, improv_skill_lv; + do { + i = rnd() % MAX_SKILL_IMPROVISE_DB; + improv_skill_id = skill_improvise_db[i].skill_id; + } while( improv_skill_id == 0 || rnd()%10000 >= skill_improvise_db[i].per ); + improv_skill_lv = 4 + skill_lv; + clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); - md = mob_once_spawn_sub(src, src->m, src->x, src->y, status_get_name(src), 2308, "", SZ_SMALL, AI_NONE); - if( md ) - { - md->master_id = src->id; - md->special_state.ai = AI_ZANZOU; - if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn( md ); - pc->setinvincibletimer(sd,500);// unlock target lock - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); + if( sd ) { + sd->state.abra_flag = 2; + sd->skillitem = improv_skill_id; + sd->skillitemlv = improv_skill_lv; + clif->item_skill(sd, improv_skill_id, improv_skill_lv); + } else { + struct unit_data *ud = unit_bl2ud(src); + int inf = skill->get_inf(improv_skill_id); + if (!ud) break; + if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { + if (src->type == BL_PET) + bl = (struct block_list*)((TBL_PET*)src)->msd; + if (!bl) bl = src; + unit_skilluse_id(src, bl->id, improv_skill_id, improv_skill_lv); + } else { + int target_id = 0; + if (ud->target) + target_id = ud->target; + else switch (src->type) { + case BL_MOB: target_id = ((TBL_MOB*)src)->target_id; break; + case BL_PET: target_id = ((TBL_PET*)src)->target_id; break; + } + if (!target_id) + break; + if (skill->get_casttype(improv_skill_id) == CAST_GROUND) { + bl = iMap->id2bl(target_id); + if (!bl) bl = src; + unit_skilluse_pos(src, bl->x, bl->y, improv_skill_id, improv_skill_lv); + } else + unit_skilluse_id(src, target_id, improv_skill_id, improv_skill_lv); + } } } break; - case KO_KYOUGAKU: - if( dstsd && tsc && !tsc->data[type] && rand()%100 < tstatus->int_/2 ){ - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - }else if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - - case KO_JYUSATSU: - if( dstsd && tsc && !tsc->data[type] && - rand()%100 < ((45+5*skill_lv) + skill_lv*5 - status_get_int(bl)/2) ){//[(Base chance of success) + (Skill Level x 5) - (int / 2)]%. - clif->skill_nodamage(src,bl,skill_id,skill_lv, - status_change_start(bl,type,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),1)); - status_zap(bl, tstatus->max_hp*skill_lv*5/100 , 0); - if( status_get_lv(bl) <= status_get_lv(src) ) - status_change_start(bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); - }else if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - case KO_GENWAKU: - if ( !map_flag_gvg(src->m) && ( dstsd || dstmd ) && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { - int x = src->x, y = src->y; + case RETURN_TO_ELDICASTES: + case ALL_GUARDIAN_RECALL: + if( sd ) + { + short x, y; // Destiny position. + unsigned short mapindex; - if( sd && rnd()%100 > ((45+5*skill_lv) - status_get_int(bl)/10) ){//[(Base chance of success) - (Intelligence Objectives / 10)]%. - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + if( skill_id == RETURN_TO_ELDICASTES) + { + x = 198; + y = 187; + mapindex = mapindex_name2id(MAP_DICASTES); + } + else + { + x = 44; + y = 151; + mapindex = mapindex_name2id(MAP_MORA); } - if (unit_movepos(src,bl->x,bl->y,0,0)) { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - clif->slide(src,bl->x,bl->y) ; - sc_start(src,SC_CONFUSION,80,skill_lv,skill->get_time(skill_id,skill_lv)); - if (unit_movepos(bl,x,y,0,0)) - { - clif->skill_damage(bl,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, -1, 6); - if( bl->type == BL_PC && pc_issit((TBL_PC*)bl)) - clif->sitting(bl); //Avoid sitting sync problem - clif->slide(bl,x,y) ; - sc_start(bl,SC_CONFUSION,80,skill_lv,skill->get_time(skill_id,skill_lv)); - } + if(!mapindex) + { //Given map not found? + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + iMap->freeblock_unlock(); + return 0; } + pc->setpos(sd, mapindex, x, y, CLR_TELEPORT); } break; - case OB_AKAITSUKI: - case OB_OBOROGENSOU: - if( sd && ( (skill_id == OB_OBOROGENSOU && bl->type == BL_MOB) // This skill does not work on monsters. - || is_boss(bl) ) ){ // Does not work on Boss monsters. - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; + case GM_SANDMAN: + if( tsc ) { + if( tsc->opt1 == OPT1_SLEEP ) + tsc->opt1 = 0; + else + tsc->opt1 = OPT1_SLEEP; + clif->changeoption(bl); + clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); } - case KO_IZAYOI: - case OB_ZANGETSU: - case KG_KYOMU: - case KG_KAGEMUSYA: - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; - case KG_KAGEHUMI: - if( flag&1 ){ - if(tsc && ( tsc->option&(OPTION_CLOAK|OPTION_HIDE) || - tsc->data[SC_CAMOUFLAGE] || tsc->data[SC__SHADOWFORM] || - tsc->data[SC_MARIONETTE] || tsc->data[SC_HARMONIZE])){ - sc_start(src, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - status_change_end(bl, SC_HIDING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - status_change_end(bl, SC_MARIONETTE, INVALID_TIMER); - status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - } - if( skill_area_temp[2] == 1 ){ - clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - sc_start(src, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - } - }else{ - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id); + case SO_ARRULLO: + { + // [(15 + 5 * Skill Level) + ( Caster?s INT / 5 ) + ( Caster?s Job Level / 5 ) - ( Target?s INT / 6 ) - ( Target?s LUK / 10 )] % + int rate = (15 + 5 * skill_lv) + status_get_int(src)/5 + (sd ? sd->status.job_level : 0); + rate -= status_get_int(bl)/6 - status_get_luk(bl)/10; + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start2(bl, type, rate, skill_lv, 1, skill->get_time(skill_id, skill_lv)); } break; - case MH_SILENT_BREEZE: { - struct status_change *ssc = status_get_sc(src); - struct block_list *m_bl = battle->get_master(src); - const enum sc_type scs[] = { - SC_MANDRAGORA, SC_HARMONIZE, SC_DEEPSLEEP, SC_VOICEOFSIREN, SC_SLEEP, SC_CONFUSION, SC_HALLUCINATION - }; - int heal; - if(tsc){ - for (i = 0; i < ARRAYLENGTH(scs); i++) { - if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); - } - if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target - status_change_start(bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); - } - heal = status_get_matk_min(src)*4; - status_heal(bl, heal, 0, 7); - - //now inflict silence on everyone - if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun - status_change_start(src, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); - if(m_bl){ - struct status_change *msc = status_get_sc(m_bl); - if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master - status_change_start(m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); - } - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - case MH_OVERED_BOOST: - if (hd){ - struct block_list *s_bl = battle->get_master(src); - if(hd->homunculus.hunger>50) //reduce hunger - hd->homunculus.hunger = hd->homunculus.hunger/2; - else - hd->homunculus.hunger = min(1,hd->homunculus.hunger); - if(s_bl && s_bl->type==BL_PC){ - status_set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp - clif->send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info - sc_start(s_bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); //gene bonus - } - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - case MH_GRANITIC_ARMOR: - case MH_PYROCLASTIC: { - struct block_list *s_bl = battle->get_master(src); - if(s_bl) - sc_start2(s_bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); //start on master - sc_start2(bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - - case MH_LIGHT_OF_REGENE: - if(hd){ - hd->homunculus.intimacy = 251; //change to neutral (can't be cast if < 750) - if(sd) clif->send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy); //refresh intimacy info + case WM_LULLABY_DEEPSLEEP: + if( flag&1 ){ + //[(Skill Level x 4) + (Voice Lessons Skill Level x 2) + (Caster?s Base Level / 15) + (Caster?s Job Level / 5)] % + int rate = (4 * skill_lv) + ( (sd) ? pc->checkskill(sd,WM_LESSON)*2 + sd->status.job_level/5 : 0 ) + status_get_lv(src) / 15; + if( bl != src ) + sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)); + }else { + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ALL|1, skill->castend_nodamage_id); } - //don't break need to start status and start block timer - case MH_STYLE_CHANGE: - case MH_MAGMA_FLOW: - case MH_PAIN_KILLER: - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - break; - case MH_SUMMON_LEGION: - { - int summons[5] = {1004, 1303, 1303, 1994, 1994}; - int qty[5] = {3 , 3 , 4 , 4 , 5}; - struct mob_data *md; - int i, dummy = 0; - - i = iMap->foreachinmap(skill->check_condition_mob_master_sub ,hd->bl.m, BL_MOB, hd->bl.id, summons[skill_lv-1], skill_id, &dummy); - if(i >= qty[skill_lv-1]) - break; - - for(i=0; im, src->x, src->y, status_get_name(src), summons[skill_lv - 1], "", SZ_SMALL, AI_ATTACK); - if (md) { - md->master_id = src->id; - if (md->deletetimer != INVALID_TIMER) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer(iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn(md); //Now it is ready for spawning. - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); - } - } - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - default: - ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->freeblock_unlock(); - return 1; - } - - if(skill_id != SR_CURSEDCIRCLE){ - struct status_change *sc = status_get_sc(src); - if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] )//Should only remove after the skill had been casted. - status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER); - } - - if (dstmd) { //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex] - mob_log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) - mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skill_id<<16)); - } - - if( sd && !(flag&1) ) { // ensure that the skill last-cast tick is recorded - sd->canskill_tick = iTimer->gettick(); + break; - if( sd->state.arrow_atk ) { // consume arrow on last invocation to this skill. - battle->consume_ammo(sd, skill_id, skill_lv); - } - skill->onskillusage(sd, bl, skill_id, tick); - // perform skill requirement consumption - skill->consume_requirement(sd,skill_id,skill_lv,2); - } + case SO_SUMMON_AGNI: + case SO_SUMMON_AQUA: + case SO_SUMMON_VENTUS: + case SO_SUMMON_TERA: + if( sd ) { + int elemental_class = skill->get_elemental_type(skill_id,skill_lv); - iMap->freeblock_unlock(); - return 0; -} + // Remove previous elemental fisrt. + if( sd->ed ) + elemental_delete(sd->ed,0); -/*========================================== - * - *------------------------------------------*/ -int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list *target, *src; - struct map_session_data *sd; - struct mob_data *md; - struct unit_data *ud; - struct status_change *sc = NULL; - int inf,inf2,flag = 0; + // Summoning the new one. + if( !elemental_create(sd,elemental_class,skill->get_time(skill_id,skill_lv)) ) { + clif->skill_fail(sd,skill_id,0,0); + break; + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; - src = iMap->id2bl(id); - if( src == NULL ) - { - ShowDebug("skill_castend_id: src == NULL (tid=%d, id=%d)\n", tid, id); - return 0;// not found - } + case SO_EL_CONTROL: + if( sd ) { + int mode = EL_MODE_PASSIVE; // Standard mode. - ud = unit_bl2ud(src); - if( ud == NULL ) - { - ShowDebug("skill_castend_id: ud == NULL (tid=%d, id=%d)\n", tid, id); - return 0;// ??? - } + if( !sd->ed ) break; - sd = BL_CAST(BL_PC, src); - md = BL_CAST(BL_MOB, src); + if( skill_lv == 4 ) {// At level 4 delete elementals. + elemental_delete(sd->ed, 0); + break; + } + switch( skill_lv ) {// Select mode bassed on skill level used. + case 2: mode = EL_MODE_ASSIST; break; + case 3: mode = EL_MODE_AGGRESSIVE; break; + } + if( !elemental_change_mode(sd->ed,mode) ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } + break; - if( src->prev == NULL ) { - ud->skilltimer = INVALID_TIMER; - return 0; - } + case SO_EL_ACTION: + if( sd ) { + int duration = 3000; + if( !sd->ed ) break; + sd->skill_id_old = skill_id; + elemental_action(sd->ed, bl, tick); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + switch(sd->ed->db->class_){ + case 2115:case 2124: + case 2118:case 2121: + duration = 6000; + break; + case 2116:case 2119: + case 2122:case 2125: + duration = 9000; + break; + } + skill->blockpc_start(sd, skill_id, duration, false); + } + break; - if(ud->skill_id != SA_CASTCANCEL && ud->skill_id != SO_SPELLFIST) {// otherwise handled in unit_skillcastcancel() - if( ud->skilltimer != tid ) { - ShowError("skill_castend_id: Timer mismatch %d!=%d!\n", ud->skilltimer, tid); - ud->skilltimer = INVALID_TIMER; - return 0; - } + case SO_EL_CURE: + if( sd ) { + struct elemental_data *ed = sd->ed; + int s_hp = sd->battle_status.hp * 10 / 100, s_sp = sd->battle_status.sp * 10 / 100; + int e_hp, e_sp; - if( sd && ud->skilltimer != INVALID_TIMER && (pc->checkskill(sd,SA_FREECAST) > 0 || ud->skill_id == LG_EXEEDBREAK) ) - {// restore original walk speed - ud->skilltimer = INVALID_TIMER; - status_calc_bl(&sd->bl, SCB_SPEED); - } + if( !ed ) break; + if( !status_charge(&sd->bl,s_hp,s_sp) ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + e_hp = ed->battle_status.max_hp * 10 / 100; + e_sp = ed->battle_status.max_sp * 10 / 100; + status_heal(&ed->bl,e_hp,e_sp,3); + clif->skill_nodamage(src,&ed->bl,skill_id,skill_lv,1); + } + break; - ud->skilltimer = INVALID_TIMER; - } + case GN_CHANGEMATERIAL: + case SO_EL_ANALYSIS: + if( sd ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + clif->skill_itemlistwindow(sd,skill_id,skill_lv); + } + break; - if (ud->skilltarget == id) - target = src; - else - target = iMap->id2bl(ud->skilltarget); + case GN_BLOOD_SUCKER: + { + struct status_change *sc = status_get_sc(src); - // Use a do so that you can break out of it when the skill fails. - do { - if(!target || target->prev==NULL) break; + if( sc && sc->bs_counter < skill->get_maxcount( skill_id , skill_lv) ) { + if( tsc && tsc->data[type] ){ + (sc->bs_counter)--; + status_change_end(src, type, INVALID_TIMER); // the first one cancels and the last one will take effect resetting the timer + } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); + (sc->bs_counter)++; + } else if( sd ) { + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } + } + break; - if(src->m != target->m || status_isdead(src)) break; + case GN_MANDRAGORA: + if( flag&1 ) { + if ( clif->skill_nodamage(bl, src, skill_id, skill_lv, + sc_start(bl, type, 25 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv))) ) + status_zap(bl, 0, status_get_max_sp(bl) * (25 + 5 * skill_lv) / 100); + } else + iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + break; - switch (ud->skill_id) { - //These should become skill_castend_pos - case WE_CALLPARTNER: - if(sd) clif->callpartner(sd); - case WE_CALLPARENT: - case WE_CALLBABY: - case AM_RESURRECTHOMUN: - case PF_SPIDERWEB: - //Find a random spot to place the skill. [Skotlex] - inf2 = skill->get_splash(ud->skill_id, ud->skill_lv); - ud->skillx = target->x + inf2; - ud->skilly = target->y + inf2; - if (inf2 && !iMap->random_dir(target, &ud->skillx, &ud->skilly)) { - ud->skillx = target->x; - ud->skilly = target->y; + case GN_SLINGITEM: + if( sd ) { + short ammo_id; + i = sd->equip_index[EQI_AMMO]; + if( i <= 0 ) + break; // No ammo. + ammo_id = sd->inventory_data[i]->nameid; + if( ammo_id <= 0 ) + break; + sd->itemid = ammo_id; + if( itemdb_is_GNbomb(ammo_id) ) { + if(battle->check_target(src,bl,BCT_ENEMY) > 0) {// Only attack if the target is an enemy. + if( ammo_id == 13263 ) + iMap->foreachincell(skill->area_sub,bl->m,bl->x,bl->y,BL_CHAR,src,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + else + skill->attack(BF_WEAPON,src,src,bl,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag); + } else //Otherwise, it fails, shows animation and removes items. + clif->skill_fail(sd,GN_SLINGITEM_RANGEMELEEATK,0xa,0); + } else if( itemdb_is_GNthrowable(ammo_id) ){ + struct script_code *script = sd->inventory_data[i]->script; + if( !script ) + break; + if( dstsd ) + run_script(script,0,dstsd->bl.id,fake_nd->bl.id); + else + run_script(script,0,src->id,0); } - ud->skilltimer=tid; - return skill->castend_pos(tid,tick,id,data); - case GN_WALLOFTHORN: - ud->skillx = target->x; - ud->skilly = target->y; - ud->skilltimer = tid; - return skill->castend_pos(tid,tick,id,data); - } + } + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1);// This packet is received twice actually, I think it is to show the animation. + break; - if(ud->skill_id == RG_BACKSTAP) { - uint8 dir = iMap->calc_dir(src,target->x,target->y),t_dir = unit_getdir(target); - if(check_distance_bl(src, target, 0) || iMap->check_dir(dir,t_dir)) { - break; + case GN_MIX_COOKING: + case GN_MAKEBOMB: + case GN_S_PHARMACY: + if( sd ) { + int qty = 1; + sd->skill_id_old = skill_id; + sd->skill_lv_old = skill_lv; + if( skill_id != GN_S_PHARMACY && skill_lv > 1 ) + qty = 10; + clif->cooking_list(sd,(skill_id - GN_MIX_COOKING) + 27,skill_id,qty,skill_id==GN_MAKEBOMB?5:6); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } - } + break; + case EL_CIRCLE_OF_FIRE: + case EL_PYROTECHNIC: + case EL_HEATER: + case EL_TROPIC: + case EL_AQUAPLAY: + case EL_COOLER: + case EL_CHILLY_AIR: + case EL_GUST: + case EL_BLAST: + case EL_WILD_STORM: + case EL_PETROLOGY: + case EL_CURSED_SOIL: + case EL_UPHEAVAL: + case EL_FIRE_CLOAK: + case EL_WATER_DROP: + case EL_WIND_CURTAIN: + case EL_SOLID_SKIN: + case EL_STONE_SHIELD: + case EL_WIND_STEP: { + struct elemental_data *ele = BL_CAST(BL_ELEM, src); + if( ele ) { + sc_type type2 = type-1; + struct status_change *sc = status_get_sc(&ele->bl); - if( ud->skill_id == PR_TURNUNDEAD ) { - struct status_data *tstatus = status_get_status_data(target); - if( !battle->check_undead(tstatus->race, tstatus->def_ele) ) - break; - } + if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { + elemental_clean_single_effect(ele, skill_id); + } else { + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + clif->skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + if( skill_id == EL_WIND_STEP ) // There aren't teleport, just push the master away. + skill->blown(src,bl,(rnd()%skill->get_blewcount(skill_id,skill_lv))+1,rand()%8,0); + sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + } + } + } + break; - if( ud->skill_id == RA_WUGSTRIKE ){ - if( !path_search(NULL,src->m,src->x,src->y,target->x,target->y,1,CELL_CHKNOREACH)) - break; - } + case EL_FIRE_MANTLE: + case EL_WATER_BARRIER: + case EL_ZEPHYR: + case EL_POWER_OF_GAIA: + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + skill->unitsetting(src,skill_id,skill_lv,bl->x,bl->y,0); + break; + + case EL_WATER_SCREEN: { + struct elemental_data *ele = BL_CAST(BL_ELEM, src); + if( ele ) { + struct status_change *sc = status_get_sc(&ele->bl); + sc_type type2 = type-1; - if( ud->skill_id == PR_LEXDIVINA || ud->skill_id == MER_LEXDIVINA ) - { - sc = status_get_sc(target); - if( battle->check_target(src,target, BCT_ENEMY) <= 0 && (!sc || !sc->data[SC_SILENCE]) ) - { //If it's not an enemy, and not silenced, you can't use the skill on them. [Skotlex] - clif->skill_nodamage (src, target, ud->skill_id, ud->skill_lv, 0); - break; + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { + elemental_clean_single_effect(ele, skill_id); + } else { + // This not heals at the end. + clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(bl,type,100,src->id,skill->get_time(skill_id,skill_lv)); + } + } } - } - else - { // Check target validity. - inf = skill->get_inf(ud->skill_id); - inf2 = skill->get_inf2(ud->skill_id); - - if(inf&INF_ATTACK_SKILL || - (inf&INF_SELF_SKILL && inf2&INF2_NO_TARGET_SELF) //Combo skills - ) // Casted through combo. - inf = BCT_ENEMY; //Offensive skill. - else if(inf2&INF2_NO_ENEMY) - inf = BCT_NOENEMY; - else - inf = 0; + break; - if(inf2 & (INF2_PARTY_ONLY|INF2_GUILD_ONLY) && src != target) - { - inf |= - (inf2&INF2_PARTY_ONLY?BCT_PARTY:0)| - (inf2&INF2_GUILD_ONLY?BCT_GUILD:0); - //Remove neutral targets (but allow enemy if skill is designed to be so) - inf &= ~BCT_NEUTRAL; + case KO_KAHU_ENTEN: + case KO_HYOUHU_HUBUKI: + case KO_KAZEHU_SEIRAN: + case KO_DOHU_KOUKAI: + if(sd) { + int ttype = skill->get_ele(skill_id, skill_lv); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + ARR_FIND(1, 6, i, sd->charm[i] > 0 && ttype != i); + if( i < 6 ) + pc->del_charm(sd, sd->charm[i], i); // replace with a new one. + pc->add_charm(sd, skill->get_time(skill_id, skill_lv), 10, ttype); } + break; - if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) { - clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0); - break; - } + case KO_ZANZOU: + if(sd){ + struct mob_data *md; - if( ud->skill_id >= SL_SKE && ud->skill_id <= SL_SKA && target->type == BL_MOB ) - { - if( ((TBL_MOB*)target)->class_ == MOBID_EMPERIUM ) - break; - } - else if (inf && battle->check_target(src, target, inf) <= 0){ - if (sd) clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); - break; + md = mob_once_spawn_sub(src, src->m, src->x, src->y, status_get_name(src), 2308, "", SZ_SMALL, AI_NONE); + if( md ) + { + md->master_id = src->id; + md->special_state.ai = AI_ZANZOU; + if( md->deletetimer != INVALID_TIMER ) + iTimer->delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); + mob_spawn( md ); + pc->setinvincibletimer(sd,500);// unlock target lock + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); + } } + break; - if(inf&BCT_ENEMY && (sc = status_get_sc(target)) && - sc->data[SC_FOGWALL] && - rnd() % 100 < 75) { //Fogwall makes all offensive-type targetted skills fail at 75% - if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); + case KO_KYOUGAKU: + { + int rate = max(5, (45 + 5 * skill_lv - status_get_int(bl) / 10)); + if( sd && !map_flag_gvg(src->m) ){ + clif->skill_fail(sd, skill_id, USESKILL_FAIL_SIZE, 0); break; + } + if( dstsd && tsc && !tsc->data[type] && rand()%100 < rate ){ + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + }else if( sd ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); } - } + break; - //Avoid doing double checks for instant-cast skills. - if (tid != INVALID_TIMER && !status_check_skilluse(src, target, ud->skill_id, 1)) + case KO_JYUSATSU: + if( dstsd && tsc && !tsc->data[type] && + rand()%100 < (10 * (5 * skill_lv - status_get_int(bl) / 2 + 45 + 5 * skill_lv)) ){ + clif->skill_nodamage(src, bl, skill_id, skill_lv, + status_change_start(bl, type, 10000, skill_lv, 0, 0, 0, skill->get_time(skill_id, skill_lv), 1)); + status_zap(bl, tstatus->max_hp * skill_lv * 5 / 100 , 0); + if( status_get_lv(bl) <= status_get_lv(src) ) + status_change_start(bl, SC_COMA, skill_lv, skill_lv, 0, src->id, 0, 0, 0); + }else if( sd ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; - if(md) { - md->last_thinktime=tick +MIN_MOBTHINKTIME; - if(md->skill_idx >= 0 && md->db->skill[md->skill_idx].emotion >= 0) - clif->emotion(src, md->db->skill[md->skill_idx].emotion); - } + case KO_GENWAKU: + if ( !map_flag_gvg(src->m) && ( dstsd || dstmd ) && !(tstatus->mode&MD_PLANT) && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { + int x = src->x, y = src->y; + if( sd && rnd()%100 > max(5, (45 + 5 * skill_lv) - status_get_int(bl) / 10) ){//[(Base chance of success) - ( target's int / 10)]%. + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; + } - if(src != target && battle_config.skill_add_range && - !check_distance_bl(src, target, skill->get_range2(src,ud->skill_id,ud->skill_lv)+battle_config.skill_add_range)) - { - if (sd) { - clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); - if(battle_config.skill_out_range_consume) //Consume items anyway. [Skotlex] - skill->consume_requirement(sd,ud->skill_id,ud->skill_lv,3); + if (unit_movepos(src, bl->x, bl->y, 0, 0)) { + clif->skill_nodamage(src, src, skill_id, skill_lv, 1); + clif->slide(src, bl->x, bl->y) ; + sc_start(src, SC_CONFUSION, 25, skill_lv, skill->get_time(skill_id, skill_lv)); + if ( !is_boss(bl) && unit_stop_walking(&sd->bl, 1) && unit_movepos(bl, x, y, 0, 0) ) + { + if( dstsd && pc_issit(dstsd) ) + pc->setstand(dstsd); + clif->slide(bl, x, y) ; + sc_start(bl, SC_CONFUSION, 75, skill_lv, skill->get_time(skill_id, skill_lv)); + } + } } break; - } - if( sd ) - { - if( !skill->check_condition_castend(sd, ud->skill_id, ud->skill_lv) ) + case OB_AKAITSUKI: + case OB_OBOROGENSOU: + if( sd && ( (skill_id == OB_OBOROGENSOU && bl->type == BL_MOB) // This skill does not work on monsters. + || is_boss(bl) ) ){ // Does not work on Boss monsters. + clif->skill_fail(sd, skill_id, USESKILL_FAIL_TOTARGET_PLAYER, 0); break; - else - skill->consume_requirement(sd,ud->skill_id,ud->skill_lv,1); - } -#ifdef OFFICIAL_WALKPATH - if( !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) ) - break; -#endif - if( (src->type == BL_MER || src->type == BL_HOM) && !skill->check_condition_mercenary(src, ud->skill_id, ud->skill_lv, 1) ) + } + case KO_IZAYOI: + case OB_ZANGETSU: + case KG_KYOMU: + case KG_KAGEMUSYA: + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; - if (ud->state.running && ud->skill_id == TK_JUMPKICK) { - ud->state.running = 0; - status_change_end(src, SC_RUN, INVALID_TIMER); - flag = 1; - } + case KG_KAGEHUMI: + if( flag&1 ){ + if(tsc && ( tsc->option&(OPTION_CLOAK|OPTION_HIDE) || + tsc->data[SC_CAMOUFLAGE] || tsc->data[SC__SHADOWFORM] || + tsc->data[SC_MARIONETTE_MASTER] || tsc->data[SC_HARMONIZE])){ + sc_start(src, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + status_change_end(bl, SC_HIDING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + status_change_end(bl, SC_MARIONETTE_MASTER, INVALID_TIMER); + status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + } + if( skill_area_temp[2] == 1 ){ + clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + sc_start(src, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + } + }else{ + skill_area_temp[2] = 0; + iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_nodamage_id); + } + break; - if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH) - unit_stop_walking(src,1); + case MH_SILENT_BREEZE: { + struct status_change *ssc = status_get_sc(src); + struct block_list *m_bl = battle->get_master(src); + const enum sc_type scs[] = { + SC_MANDRAGORA, SC_HARMONIZE, SC_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION + }; + int heal; + if(tsc){ + for (i = 0; i < ARRAYLENGTH(scs); i++) { + if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); + } + if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target + status_change_start(bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); + } + heal = status_get_matk_min(src)*4; + status_heal(bl, heal, 0, 7); - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) - ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] - if (sd) { //Cooldown application - int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv); - for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { // Increases/Decreases cooldown of a skill by item/card bonuses. - if (sd->skillcooldown[i].id == ud->skill_id){ - cooldown += sd->skillcooldown[i].val; - break; - } + //now inflict silence on everyone + if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun + status_change_start(src, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); + if(m_bl){ + struct status_change *msc = status_get_sc(m_bl); + if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master + status_change_start(m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); } - if(cooldown) - skill->blockpc_start(sd, ud->skill_id, cooldown, false); - } - if( battle_config.display_status_timers && sd ) - clif->status_change(src, SI_ACTIONDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); - if( sd ) - { - switch( ud->skill_id ) - { - case GS_DESPERADO: - sd->canequip_tick = tick + skill->get_time(ud->skill_id, ud->skill_lv); + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + } + break; + case MH_OVERED_BOOST: + if (hd){ + struct block_list *s_bl = battle->get_master(src); + if(hd->homunculus.hunger>50) //reduce hunger + hd->homunculus.hunger = hd->homunculus.hunger/2; + else + hd->homunculus.hunger = min(1,hd->homunculus.hunger); + if(s_bl && s_bl->type==BL_PC){ + status_set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp + clif->send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info + sc_start(s_bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); //gene bonus + } + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + } break; - case CR_GRANDCROSS: - case NPC_GRANDDARKNESS: - if( (sc = status_get_sc(src)) && sc->data[SC_STRIPSHIELD] ) + case MH_GRANITIC_ARMOR: + case MH_PYROCLASTIC: { + struct block_list *s_bl = battle->get_master(src); + if(s_bl) + sc_start2(s_bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); //start on master + sc_start2(bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + } + break; + + case MH_LIGHT_OF_REGENE: + if(hd){ + hd->homunculus.intimacy = 251; //change to neutral (can't be cast if < 750) + if(sd) clif->send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy); //refresh intimacy info + } + //don't break need to start status and start block timer + case MH_STYLE_CHANGE: + case MH_MAGMA_FLOW: + case MH_PAIN_KILLER: + sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + break; + case MH_SUMMON_LEGION: { - const struct TimerData *timer = iTimer->get_timer(sc->data[SC_STRIPSHIELD]->timer); - if( timer && timer->func == status_change_timer && DIFF_TICK(timer->tick,iTimer->gettick()+skill->get_time(ud->skill_id, ud->skill_lv)) > 0 ) + int summons[5] = {1004, 1303, 1303, 1994, 1994}; + int qty[5] = {3 , 3 , 4 , 4 , 5}; + struct mob_data *md; + int i, dummy = 0; + + i = iMap->foreachinmap(skill->check_condition_mob_master_sub ,hd->bl.m, BL_MOB, hd->bl.id, summons[skill_lv-1], skill_id, &dummy); + if(i >= qty[skill_lv-1]) break; + + for(i=0; im, src->x, src->y, status_get_name(src), summons[skill_lv - 1], "", SZ_SMALL, AI_ATTACK); + if (md) { + md->master_id = src->id; + if (md->deletetimer != INVALID_TIMER) + iTimer->delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = iTimer->add_timer(iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); + mob_spawn(md); //Now it is ready for spawning. + sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); + } + } + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); } - sc_start2(src, SC_STRIPSHIELD, 100, 0, 1, skill->get_time(ud->skill_id, ud->skill_lv)); break; - } - } - if (skill->get_state(ud->skill_id) != ST_MOVE_ENABLE) - unit_set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); - - if(battle_config.skill_log && battle_config.skill_log&src->type) - ShowInfo("Type %d, ID %d skill castend id [id =%d, lv=%d, target ID %d]\n", - src->type, src->id, ud->skill_id, ud->skill_lv, target->id); - - iMap->freeblock_lock(); - - // SC_MAGICPOWER needs to switch states before any damage is actually dealt - skill->toggle_magicpower(src, ud->skill_id); - if( ud->skill_id != RA_CAMOUFLAGE ) // only normal attack and auto cast skills benefit from its bonuses - status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); - - if (skill->get_casttype(ud->skill_id) == CAST_NODAMAGE) - skill->castend_nodamage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); - else - skill->castend_damage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); - - sc = status_get_sc(src); - if(sc && sc->count) { - if(sc->data[SC_SPIRIT] && - sc->data[SC_SPIRIT]->val2 == SL_WIZARD && - sc->data[SC_SPIRIT]->val3 == ud->skill_id && - ud->skill_id != WZ_WATERBALL) - sc->data[SC_SPIRIT]->val3 = 0; //Clear bounced spell check. + default: + ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + iMap->freeblock_unlock(); + return 1; + } - if( sc->data[SC_DANCING] && skill->get_inf2(ud->skill_id)&INF2_SONG_DANCE && sd ) - skill->blockpc_start(sd,BD_ADAPTATION,3000, false); - } + if(skill_id != SR_CURSEDCIRCLE){ + struct status_change *sc = status_get_sc(src); + if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] )//Should only remove after the skill had been casted. + status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER); + } - if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish] - sd->skillitem = sd->skillitemlv = 0; + if (dstmd) { //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex] + mob_log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) + mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skill_id<<16)); + } - if (ud->skilltimer == INVALID_TIMER) { - if(md) md->skill_idx = -1; - else ud->skill_id = 0; //mobs can't clear this one as it is used for skill condition 'afterskill' - ud->skill_lv = ud->skilltarget = 0; - } - iMap->freeblock_unlock(); - return 1; - } while(0); + if( sd && !(flag&1) ) { // ensure that the skill last-cast tick is recorded + sd->canskill_tick = iTimer->gettick(); - //Skill failed. - if (ud->skill_id == MO_EXTREMITYFIST && sd && !(sc && sc->data[SC_FOGWALL])) - { //When Asura fails... (except when it fails from Fog of Wall) - //Consume SP/spheres - skill->consume_requirement(sd,ud->skill_id, ud->skill_lv,1); - status_set_sp(src, 0, 0); - sc = &sd->sc; - if (sc->count) - { //End states - status_change_end(src, SC_EXPLOSIONSPIRITS, INVALID_TIMER); - status_change_end(src, SC_BLADESTOP, INVALID_TIMER); -#ifdef RENEWAL - sc_start(src, SC_EXTREMITYFIST2, 100, ud->skill_lv, skill->get_time(ud->skill_id, ud->skill_lv)); -#endif - } - if (target && target->m == src->m) - { //Move character to target anyway. - int dir, x, y; - dir = iMap->calc_dir(src,target->x,target->y); - if( dir > 0 && dir < 4) x = -2; - else if( dir > 4 ) x = 2; - else x = 0; - if( dir > 2 && dir < 6 ) y = -2; - else if( dir == 7 || dir < 2 ) y = 2; - else y = 0; - if (unit_movepos(src, src->x+x, src->y+y, 1, 1)) - { //Display movement + animation. - clif->slide(src,src->x,src->y); - clif->skill_damage(src,target,tick,sd->battle_status.amotion,0,0,1,ud->skill_id, ud->skill_lv, 5); - } - clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); + if( sd->state.arrow_atk ) { // consume arrow on last invocation to this skill. + battle->consume_ammo(sd, skill_id, skill_lv); } + skill->onskillusage(sd, bl, skill_id, tick); + // perform skill requirement consumption + skill->consume_requirement(sd,skill_id,skill_lv,2); } - ud->skill_id = ud->skill_lv = ud->skilltarget = 0; - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) - ud->canact_tick = tick; - //You can't place a skill failed packet here because it would be - //sent in ALL cases, even cases where skill_check_condition fails - //which would lead to double 'skill failed' messages u.u [Skotlex] - if(sd) - sd->skillitem = sd->skillitemlv = 0; - else if(md) - md->skill_idx = -1; + iMap->freeblock_unlock(); return 0; } @@ -9528,7 +9392,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) skill->blockpc_start(sd, ud->skill_id, cooldown, false); } if( battle_config.display_status_timers && sd ) - clif->status_change(src, SI_ACTIONDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); + clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); // if( sd ) // { // switch( ud->skill_id ) @@ -9574,6 +9438,143 @@ static int skill_count_wos(struct block_list *bl,va_list ap) { } return 0; } + +/*========================================== + * + *------------------------------------------*/ +int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *map) +{ + nullpo_ret(sd); + +//Simplify skill_failed code. +#define skill_failed(sd) { sd->menuskill_id = sd->menuskill_val = 0; } + if(skill_id != sd->menuskill_id) + return 0; + + if( sd->bl.prev == NULL || pc_isdead(sd) ) { + skill_failed(sd); + return 0; + } + + if( ( sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING ) || sd->sc.option&OPTION_HIDE ) { + skill_failed(sd); + return 0; + } + if(sd->sc.count && ( + sd->sc.data[SC_SILENCE] || + sd->sc.data[SC_ROKISWEIL] || + sd->sc.data[SC_AUTOCOUNTER] || + sd->sc.data[SC_STEELBODY] || + (sd->sc.data[SC_DANCING] && skill_id < RK_ENCHANTBLADE && !pc->checkskill(sd, WM_LESSON)) || + sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || + sd->sc.data[SC_BASILICA] || + sd->sc.data[SC_MARIONETTE_MASTER] || + sd->sc.data[SC_WHITEIMPRISON] || + (sd->sc.data[SC_STASIS] && skill->block_check(&sd->bl, SC_STASIS, skill_id)) || + (sd->sc.data[SC_KG_KAGEHUMI] && skill->block_check(&sd->bl, SC_KG_KAGEHUMI, skill_id)) || + sd->sc.data[SC_OBLIVIONCURSE] || + sd->sc.data[SC__MANHOLE] || + (sd->sc.data[SC_VOLCANIC_ASH] && rnd()%2) //50% fail chance under ASH + )) { + skill_failed(sd); + return 0; + } + + pc_stop_attack(sd); + pc_stop_walking(sd,0); + + if(battle_config.skill_log && battle_config.skill_log&BL_PC) + ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,map); + + if(strcmp(map,"cancel")==0) { + skill_failed(sd); + return 0; + } + + switch(skill_id) { + case AL_TELEPORT: + if(strcmp(map,"Random")==0) + pc->randomwarp(sd,CLR_TELEPORT); + else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here. + pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); + break; + + case AL_WARP: + { + const struct point *p[4]; + struct skill_unit_group *group; + int i, lv, wx, wy; + int maxcount=0; + int x,y; + unsigned short mapindex; + + mapindex = mapindex_name2id((char*)map); + sd->state.workinprogress = 0; + if(!mapindex) { //Given map not found? + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + skill_failed(sd); + return 0; + } + p[0] = &sd->status.save_point; + p[1] = &sd->status.memo_point[0]; + p[2] = &sd->status.memo_point[1]; + p[3] = &sd->status.memo_point[2]; + + if((maxcount = skill->get_maxcount(skill_id, sd->menuskill_val)) > 0) { + for(i=0;iud.skillunit[i] && maxcount;i++) { + if(sd->ud.skillunit[i]->skill_id == skill_id) + maxcount--; + } + if(!maxcount) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + skill_failed(sd); + return 0; + } + } + + lv = sd->skillitem==skill_id?sd->skillitemlv:pc->checkskill(sd,skill_id); + wx = sd->menuskill_val>>16; + wy = sd->menuskill_val&0xffff; + + if( lv <= 0 ) return 0; + if( lv > 4 ) lv = 4; // crash prevention + + // check if the chosen map exists in the memo list + ARR_FIND( 0, lv, i, mapindex == p[i]->map ); + if( i < lv ) { + x=p[i]->x; + y=p[i]->y; + } else { + skill_failed(sd); + return 0; + } + + if(!skill->check_condition_castend(sd, sd->menuskill_id, lv)) { // This checks versus skill_id/skill_lv... + skill_failed(sd); + return 0; + } + + skill->consume_requirement(sd,sd->menuskill_id,lv,2); + sd->skillitem = sd->skillitemlv = 0; // Clear data that's skipped in 'skill_castend_pos' [Inkfish] + + if((group=skill->unitsetting(&sd->bl,skill_id,lv,wx,wy,0))==NULL) { + skill_failed(sd); + return 0; + } + + group->val1 = (group->val1<<16)|(short)0; + // record the destination coordinates + group->val2 = (x<<16)|y; + group->val3 = mapindex; + } + break; + } + + sd->menuskill_id = sd->menuskill_val = 0; + return 0; +#undef skill_failed +} + /*========================================== * *------------------------------------------*/ @@ -9740,6 +9741,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NJ_HUUMA: #endif case NPC_EVILLAND: + case WL_COMET: case RA_ELECTRICSHOCKER: case RA_CLUSTERBOMB: case RA_MAGENTATRAP: @@ -9776,6 +9778,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case MH_POISON_MIST: case MH_STEINWAND: case MH_XENO_SLASHER: + case NC_MAGMA_ERUPTION: flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. skill->unitsetting(src,skill_id,skill_lv,x,y,0); @@ -10038,6 +10041,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NC_COLDSLOWER: case NC_ARMSCANNON: case RK_DRAGONBREATH: + case RK_DRAGONBREATH_WATER: i = skill->get_splash(skill_id,skill_lv); iMap->foreachinarea(skill->area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); @@ -10070,17 +10074,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui iMap->foreachinarea(skill->area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill->castend_nodamage_id); } break; - /** - * Warlock - **/ - case WL_COMET: - if( sc ) { - sc->comet_x = x; - sc->comet_y = y; - } - i = skill->get_splash(skill_id,skill_lv); - iMap->foreachinarea(skill->area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - break; case WL_EARTHSTRAIN: { @@ -10095,7 +10088,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case 2: sx = x - i; break; case 6: sx = x + i; break; } - skill->addtimerskill(src,iTimer->gettick() + (150 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2); + skill->addtimerskill(src,iTimer->gettick() + (50 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2); } } break; @@ -10142,10 +10135,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui break; case SC_FEINTBOMB: - clif->skill_nodamage(src,src,skill_id,skill_lv,1); skill->unitsetting(src,skill_id,skill_lv,x,y,0); // Set bomb on current Position + clif->skill_nodamage(src,src,skill_id,skill_lv,1); if( skill->blown(src,src,6,unit_getdir(src),0) ) - skill->castend_nodamage_id(src,src,TF_HIDING,1,tick,0); + skill->castend_nodamage_id(src,src,TF_HIDING,1,tick,0x2); break; case LG_OVERBRAND: @@ -10279,141 +10272,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui return 0; } -/*========================================== - * - *------------------------------------------*/ -int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *map) -{ - nullpo_ret(sd); - -//Simplify skill_failed code. -#define skill_failed(sd) { sd->menuskill_id = sd->menuskill_val = 0; } - if(skill_id != sd->menuskill_id) - return 0; - - if( sd->bl.prev == NULL || pc_isdead(sd) ) { - skill_failed(sd); - return 0; - } - - if( ( sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING ) || sd->sc.option&OPTION_HIDE ) { - skill_failed(sd); - return 0; - } - if(sd->sc.count && ( - sd->sc.data[SC_SILENCE] || - sd->sc.data[SC_ROKISWEIL] || - sd->sc.data[SC_AUTOCOUNTER] || - sd->sc.data[SC_STEELBODY] || - (sd->sc.data[SC_DANCING] && skill_id < RK_ENCHANTBLADE && !pc->checkskill(sd, WM_LESSON)) || - sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || - sd->sc.data[SC_BASILICA] || - sd->sc.data[SC_MARIONETTE] || - sd->sc.data[SC_WHITEIMPRISON] || - (sd->sc.data[SC_STASIS] && skill->block_check(&sd->bl, SC_STASIS, skill_id)) || - (sd->sc.data[SC_KAGEHUMI] && skill->block_check(&sd->bl, SC_KAGEHUMI, skill_id)) || - sd->sc.data[SC_OBLIVIONCURSE] || - sd->sc.data[SC__MANHOLE] || - (sd->sc.data[SC_ASH] && rnd()%2) //50% fail chance under ASH - )) { - skill_failed(sd); - return 0; - } - - pc_stop_attack(sd); - pc_stop_walking(sd,0); - - if(battle_config.skill_log && battle_config.skill_log&BL_PC) - ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,map); - - if(strcmp(map,"cancel")==0) { - skill_failed(sd); - return 0; - } - - switch(skill_id) { - case AL_TELEPORT: - if(strcmp(map,"Random")==0) - pc->randomwarp(sd,CLR_TELEPORT); - else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here. - pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); - break; - - case AL_WARP: - { - const struct point *p[4]; - struct skill_unit_group *group; - int i, lv, wx, wy; - int maxcount=0; - int x,y; - unsigned short mapindex; - - mapindex = mapindex_name2id((char*)map); - if(!mapindex) { //Given map not found? - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - skill_failed(sd); - return 0; - } - p[0] = &sd->status.save_point; - p[1] = &sd->status.memo_point[0]; - p[2] = &sd->status.memo_point[1]; - p[3] = &sd->status.memo_point[2]; - - if((maxcount = skill->get_maxcount(skill_id, sd->menuskill_val)) > 0) { - for(i=0;iud.skillunit[i] && maxcount;i++) { - if(sd->ud.skillunit[i]->skill_id == skill_id) - maxcount--; - } - if(!maxcount) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - skill_failed(sd); - return 0; - } - } - - lv = sd->skillitem==skill_id?sd->skillitemlv:pc->checkskill(sd,skill_id); - wx = sd->menuskill_val>>16; - wy = sd->menuskill_val&0xffff; - - if( lv <= 0 ) return 0; - if( lv > 4 ) lv = 4; // crash prevention - - // check if the chosen map exists in the memo list - ARR_FIND( 0, lv, i, mapindex == p[i]->map ); - if( i < lv ) { - x=p[i]->x; - y=p[i]->y; - } else { - skill_failed(sd); - return 0; - } - - if(!skill->check_condition_castend(sd, sd->menuskill_id, lv)) { // This checks versus skill_id/skill_lv... - skill_failed(sd); - return 0; - } - - skill->consume_requirement(sd,sd->menuskill_id,lv,2); - sd->skillitem = sd->skillitemlv = 0; // Clear data that's skipped in 'skill_castend_pos' [Inkfish] - - if((group=skill->unitsetting(&sd->bl,skill_id,lv,wx,wy,0))==NULL) { - skill_failed(sd); - return 0; - } - - group->val1 = (group->val1<<16)|(short)0; - // record the destination coordinates - group->val2 = (x<<16)|y; - group->val3 = mapindex; - } - break; - } - - sd->menuskill_id = sd->menuskill_val = 0; - return 0; -#undef skill_failed -} - /// transforms 'target' skill unit into dissonance (if conditions are met) int skill_dance_overlap_sub(struct block_list* bl, va_list ap) { struct skill_unit* target = (struct skill_unit*)bl; @@ -10713,8 +10571,13 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill } break; case DC_DONTFORGETME: +#ifdef RENEWAL + val1 = status->dex/10 + 3*skill_lv; // ASPD decrease + val2 = status->agi/10 + 2*skill_lv; // Movement speed adjustment. +#else val1 = status->dex/10 + 3*skill_lv + 5; // ASPD decrease val2 = status->agi/10 + 3*skill_lv + 5; // Movement speed adjustment. +#endif if(sd){ val1 += pc->checkskill(sd,DC_DANCINGLESSON); val2 += pc->checkskill(sd,DC_DANCINGLESSON); @@ -10734,9 +10597,15 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill } break; case BA_ASSASSINCROSS: +#ifdef RENEWAL + val1 = 10 + skill_lv + (status->agi/10); // ASPD increase + if(sd) + val1 += 4*pc->checkskill(sd,BA_MUSICALLESSON); +#else val1 = 100+(10*skill_lv)+(status->agi/10); // ASPD increase if(sd) val1 += 5*pc->checkskill(sd,BA_MUSICALLESSON); +#endif break; case DC_FORTUNEKISS: val1 = 10+skill_lv+(status->luk/10); // Critical increase @@ -10823,6 +10692,12 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case GD_HAWKEYES: limit = 1000000;//it doesn't matter break; + case WL_COMET: + if( sc ) { + sc->comet_x = x; + sc->comet_y = y; + } + break; case LG_BANDING: limit = -1; break; @@ -10841,7 +10716,6 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case SO_VACUUM_EXTREME: range++; - break; case SC_BLOODYLUST: skill->clear_group(src, 32); @@ -10853,13 +10727,13 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case KO_ZENKAI: if( sd ){ - ARR_FIND(1, 6, i, sd->talisman[i] > 0); + ARR_FIND(1, 6, i, sd->charm[i] > 0); if( i < 5 ){ - val1 = sd->talisman[i]; // no. of aura + val1 = sd->charm[i]; // no. of aura val2 = i; // aura type limit += val1 * 1000; subunt = i - 1; - pc->del_talisman(sd, sd->talisman[i], i); + pc->del_charm(sd, sd->charm[i], i); } } break; @@ -11151,7 +11025,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned case UNT_INTOABYSS: case UNT_SIEGFRIED: //Needed to check when a dancer/bard leaves their ensemble area. - if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)) + if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) return skill_id; if (!sce) sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); @@ -11164,7 +11038,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned case UNT_DONTFORGETME: case UNT_FORTUNEKISS: case UNT_SERVICEFORYOU: - if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)) + if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) return 0; if (!sc) return 0; @@ -11217,7 +11091,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned case UNT_VOLCANIC_ASH: if (!sce) - sc_start(bl, SC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); + sc_start(bl, SC_VOLCANIC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); break; case UNT_GD_LEADERSHIP: @@ -11543,7 +11417,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( md && md->class_ == MOBID_EMPERIUM ) break; #endif - if( sg->src_id == bl->id && !(tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_BARDDANCER) ) + if( sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER) ) break; // affects self only when soullinked heal = skill->calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true); if( tsc->data[SC_AKAITSUKI] && heal ) @@ -11574,7 +11448,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns status_heal(bl,heal,0,0); break; case 1: // End all negative status - status_change_clear_buffs(bl,6); + status_change_clear_buffs(bl,2); if (tsd) clif->gospel_info(tsd, 0x15); break; case 2: // Immunity to all status @@ -11597,7 +11471,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns sc_start(bl,SC_BLESSING,100,10,time); break; case 7: // Level 10 Increase AGI - sc_start(bl,SC_INCREASEAGI,100,10,time); + sc_start(bl,SC_INC_AGI,100,10,time); break; case 8: // Enchant weapon with Holy element sc_start(bl,SC_ASPERSIO,100,1,time); @@ -11678,6 +11552,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_FIREWALK: case UNT_ELECTRICWALK: case UNT_PSYCHIC_WAVE: + case UNT_MAGMA_ERUPTION: + case UNT_MAKIBISHI: skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -11723,7 +11599,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns } } /* Enable this if kRO fix the current skill. Currently no damage on undead and demon monster. [Jobbie] - else if( battle->check_target(ss, bl, BCT_ENEMY) > 0 && battle_check_undead(tstatus->race, tstatus->def_ele) ) + else if( battle->check_target(ss, bl, BCT_ENEMY) > 0 && battle->check_undead(tstatus->race, tstatus->def_ele) ) skill->castend_damage_id(&src->bl, bl, sg->skill_id, sg->skill_lv, 0, 0);*/ break; @@ -11775,7 +11651,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns } else sec = 3000; // Couldn't trap it? sg->limit = DIFF_TICK(tick, sg->tick) + sec; - } else if( tsc->data[SC_THORNSTRAP] && bl->id == sg->val2 ) + } else if( tsc->data[SC_THORNS_TRAP] && bl->id == sg->val2 ) skill->attack(skill->get_type(GN_THORNS_TRAP), ss, ss, bl, sg->skill_id, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION); } break; @@ -11786,7 +11662,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case 1: case 2: default: - sc_start(bl, SC_BURNING, 4 + 4 * sg->skill_lv, sg->skill_lv, + sc_start4(bl, SC_BURNING, 4 + 4 * sg->skill_lv, sg->skill_lv, 0, ss->id, 0, skill->get_time2(sg->skill_id, sg->skill_lv)); skill->attack(skill->get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv + 10 * sg->val2, tick, 0); @@ -11903,36 +11779,31 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_ZENKAI_WATER: sc_start(bl, SC_CRYSTALIZE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); sc_start(bl, SC_FREEZE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_FREEZING, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(bl, SC_FROSTMISTY, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_LAND: sc_start(bl, SC_STONE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); sc_start(bl, SC_POISON, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_FIRE: - sc_start(bl, SC_BURNING, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start4(bl, SC_BURNING, sg->val1*5, sg->skill_lv, 0, ss->id, 0, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_WIND: sc_start(bl, SC_SILENCE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); sc_start(bl, SC_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_DEEPSLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(bl, SC_DEEP_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; } }else sc_start2(bl,type,100,sg->val1,sg->val2,skill->get_time2(sg->skill_id, sg->skill_lv)); break; - case UNT_MAKIBISHI: - skill->attack(BF_MISC, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); - sg->limit = DIFF_TICK(tick, sg->tick); - sg->unit_id = UNT_USED_TRAPS; - break; - case UNT_LAVA_SLIDE: skill->attack(BF_WEAPON, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); if(++sg->val1 > 4) //after 5 stop hit and destroy me sg->limit = DIFF_TICK(tick, sg->tick); break; + case UNT_POISON_MIST: skill->attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); status_change_start(bl, SC_BLIND, rnd() % 100 > sg->skill_lv * 10, sg->skill_lv, sg->skill_id, 0, 0, skill->get_time2(sg->skill_id, sg->skill_lv), 2|8); @@ -12234,7 +12105,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) { return 1; case WL_COMET: // Comet does not consume Red Gemstones when there is at least 1 Warlock class next to the caster - if( ( sd->class_&MAPID_THIRDMASK ) == MAPID_WARLOCK ) + if( ( tsd->class_&MAPID_THIRDMASK ) == MAPID_WARLOCK ) p_sd[(*c)++] = tsd->bl.id; return 1; case LG_RAYOFGENESIS: @@ -12469,11 +12340,11 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case BS_ADRENALINE: case WS_WEAPONREFINE: case BS_WEAPONPERFECT: case WS_CARTTERMINATION: case BS_OVERTHRUST: case WS_OVERTHRUSTMAX: - case BS_MAXIMIZE: case NC_AXEBOOMERANG: - case BS_ADRENALINE2: case NC_POWERSWING: - case BS_UNFAIRLYTRICK: case NC_AXETORNADO: + case BS_MAXIMIZE: + case BS_ADRENALINE2: + case BS_UNFAIRLYTRICK: case BS_GREED: - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); return 0; default: //Only Mechanic exlcusive skill can be used. break; @@ -12529,30 +12400,43 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; if(sc->data[SC_BLADESTOP]) break; - if(sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MO_TRIPLEATTACK) + if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_TRIPLEATTACK ) break; + if( i ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_TRIPLEATTACK); return 0; case MO_COMBOFINISH: - if(!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MO_CHAINCOMBO)) + if(!sc) return 0; - break; + if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_CHAINCOMBO ) + break; + if( i ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_CHAINCOMBO); + return 0; case CH_TIGERFIST: - if(!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == MO_COMBOFINISH)) + if(!sc) return 0; - break; + if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_COMBOFINISH ) + break; + if( i ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_COMBOFINISH); + return 0; case CH_CHAINCRUSH: - if(!(sc && sc->data[SC_COMBO])) - return 0; - if(sc->data[SC_COMBO]->val1 != MO_COMBOFINISH && sc->data[SC_COMBO]->val1 != CH_TIGERFIST) + if(!sc) return 0; - break; + if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == CH_TIGERFIST ) + break; + if( i ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, CH_TIGERFIST); + return 0; case MO_EXTREMITYFIST: // if(sc && sc->data[SC_EXTREMITYFIST]) //To disable Asura during the 5 min skill block uncomment this... // return 0; if( sc && (sc->data[SC_BLADESTOP] || sc->data[SC_CURSEDCIRCLE_ATKER]) ) break; - if( sc && sc->data[SC_COMBO] ) { - switch(sc->data[SC_COMBO]->val1) { + if( sc && sc->data[SC_COMBOATTACK] ) + { + switch(sc->data[SC_COMBOATTACK]->val1) { case MO_COMBOFINISH: case CH_TIGERFIST: case CH_CHAINCRUSH: @@ -12594,17 +12478,17 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case TK_COUNTER: if ((sd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) return 0; //Anti-Soul Linker check in case you job-changed with Stances active. - if(!(sc && sc->data[SC_COMBO]) || sc->data[SC_COMBO]->val1 == TK_JUMPKICK) + if(!(sc && sc->data[SC_COMBOATTACK]) || sc->data[SC_COMBOATTACK]->val1 == TK_JUMPKICK) return 0; //Combo needs to be ready - if (sc->data[SC_COMBO]->val3) { //Kick chain + if (sc->data[SC_COMBOATTACK]->val3) { //Kick chain //Do not repeat a kick. - if (sc->data[SC_COMBO]->val3 != skill_id) + if (sc->data[SC_COMBOATTACK]->val3 != skill_id) break; - status_change_end(&sd->bl, SC_COMBO, INVALID_TIMER); + status_change_end(&sd->bl, SC_COMBOATTACK, INVALID_TIMER); return 0; } - if(sc->data[SC_COMBO]->val1 != skill_id && !( sd && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )) { //Cancel combo wait. + if(sc->data[SC_COMBOATTACK]->val1 != skill_id && !( sd && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )) { //Cancel combo wait. unit_cancel_combo(&sd->bl); return 0; } @@ -12638,12 +12522,12 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case SL_SMA: - if(!(sc && sc->data[SC_SMA])) + if(!(sc && sc->data[SC_SMA_READY])) return 0; break; case HT_POWER: - if(!(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id)) + if(!(sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == skill_id)) return 0; break; @@ -12709,7 +12593,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; case SG_FUSION: - if (sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_STAR) + if (sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_STAR) break; //Auron insists we should implement SP consumption when you are not Soul Linked. [Skotlex] //Only invoke on skill begin cast (instant cast skill). [Kevin] @@ -12751,7 +12635,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } case NJ_BUNSINJYUTSU: - if (!(sc && sc->data[SC_NEN])) { + if (!(sc && sc->data[SC_NJ_NEN])) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -12824,13 +12708,36 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case WL_SUMMONBL: case WL_SUMMONWB: case WL_SUMMONSTONE: - if( sc ) + case WL_TETRAVORTEX: + case WL_RELEASE: { - ARR_FIND(SC_SPHERE_1,SC_SPHERE_5+1,i,!sc->data[i]); - if( i == SC_SPHERE_5+1 ) - { // No more free slots - clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); - return 0; + int x = SC_SUMMON1; + i = 0; + for(; x <= SC_SUMMON5; x++) + if( sc && sc->data[x] ) + i++; + + switch(skill_id){ + case WL_TETRAVORTEX: + if( i < 4 ){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION,0); + return 0; + } + break; + case WL_RELEASE: + for(x = SC_SPELLBOOK7; x >= SC_SPELLBOOK1; x--) + if( sc && sc->data[x] ) + i++; + if( i == 0 ){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0); + return 0; + } + break; + default: + if( i == 5 ){ + clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); + return 0; + } } } break; @@ -12845,7 +12752,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case GC_COUNTERSLASH: case GC_WEAPONCRUSH: - if( !(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING) ) { + if( !(sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == GC_WEAPONBLOCKING) ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_GC_WEAPONBLOCKING, 0); return 0; } @@ -12854,26 +12761,26 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id * Ranger **/ case RA_WUGMASTERY: - if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY] ) { + clif->skill_fail(sd,skill_id,sd->sc.data[SC__GROOMY]?USESKILL_FAIL_MANUAL_NOTIFY:USESKILL_FAIL_CONDITION,0); return 0; } break; case RA_WUGSTRIKE: if( !pc_iswug(sd) && !pc_isridingwug(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION,0); return 0; } break; case RA_WUGRIDER: if( pc_isfalcon(sd) || ( !pc_isridingwug(sd) && !pc_iswug(sd) ) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION,0); return 0; } break; case RA_WUGDASH: if(!pc_isridingwug(sd)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CONDITION,0); return 0; } break; @@ -12915,10 +12822,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case SR_FALLENEMPIRE: - if( !(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO) ) + if( !sc ) return 0; - break; - + if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == SR_DRAGONCOMBO ) + break; + if( i ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, SR_DRAGONCOMBO); + return 0; case SR_CRESCENTELBOW: if( sc && sc->data[SC_CRESCENTELBOW] ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_DUPLICATE, 0); @@ -12973,7 +12883,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case SO_EL_CONTROL: if( !sd->status.ele_id || !sd->ed ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_EL_SUMMON,0); return 0; } break; @@ -12985,7 +12895,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case LG_REFLECTDAMAGE: case CR_REFLECTSHIELD: - if( sc && sc->data[SC_KYOMU] && rand()%100 < 30){ + if( sc && sc->data[SC_KYOMU] && rand()%100 < 5 * sc->data[SC_KYOMU]->val1 ){ clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -12996,18 +12906,17 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case KO_DOHU_KOUKAI: { int ttype = skill->get_ele(skill_id, skill_lv); - ARR_FIND(1, 5, i, sd->talisman[i] > 0 && i != ttype); - if( (i < 5 && i != ttype) || sd->talisman[ttype] >= 10 ){ - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + if( sd->charm[ttype] >= 10 ){ + clif->skill_fail(sd, skill_id, USESKILL_FAIL_SUMMON, 0); return 0; } } break; case KO_KAIHOU: case KO_ZENKAI: - ARR_FIND(1, 6, i, sd->talisman[i] > 0); + ARR_FIND(1, 6, i, sd->charm[i] > 0); if( i > 4 ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); return 0; } break; @@ -13051,7 +12960,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } case ST_CART: if(!pc_iscarton(sd)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CART,0); return 0; } break; @@ -13069,7 +12978,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case ST_EXPLOSIONSPIRITS: if(!(sc && sc->data[SC_EXPLOSIONSPIRITS])) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_EXPLOSIONSPIRITS,0); return 0; } break; @@ -13080,7 +12989,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case ST_MOVE_ENABLE: - if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id) + if (sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == skill_id) sd->ud.canmove_tick = iTimer->gettick(); //When using a combo, cancel the can't move delay to enable the skill. [Skotlex] if (!unit_can_move(&sd->bl)) { @@ -13089,7 +12998,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case ST_WATER: - if (sc && (sc->data[SC_DELUGE] || sc->data[SC_SUITON])) + if (sc && (sc->data[SC_DELUGE] || sc->data[SC_NJ_SUITON])) break; if (iMap->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKWATER)) break; @@ -13097,7 +13006,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; case ST_RIDINGDRAGON: if( !pc_isridingdragon(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_DRAGON,0); return 0; } break; @@ -13115,7 +13024,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case ST_MADO: if( !pc_ismadogear(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); return 0; } break; @@ -13182,7 +13091,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } - if( sd->sc.data[SC_COMBO] ) { + if( sd->sc.data[SC_COMBOATTACK] ) { switch( skill_id ) { case MO_CHAINCOMBO: case MO_COMBOFINISH: @@ -13329,7 +13238,10 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, if( require.ammo ) { //Skill requires stuff equipped in the arrow slot. if((i=sd->equip_index[EQI_AMMO]) < 0 || !sd->inventory_data[i] ) { - clif->arrow_fail(sd,0); + if( require.ammo&1<<8 ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_CANONBALL,0); + else + clif->arrow_fail(sd,0); return 0; } else if( sd->status.inventory[i].amount < require.ammo_qty ) { char e_msg[100]; @@ -13353,12 +13265,39 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, continue; index[i] = pc->search_inventory(sd,require.itemid[i]); if( index[i] < 0 || sd->status.inventory[index[i]].amount < require.amount[i] ) { - if( require.itemid[i] == ITEMID_RED_GEMSTONE ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_REDJAMSTONE,0);// red gemstone required - else if( require.itemid[i] == ITEMID_BLUE_GEMSTONE ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_BLUEJAMSTONE,0);// blue gemstone required - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + useskill_fail_cause cause = USESKILL_FAIL_NEED_ITEM; + switch( skill_id ){ + case NC_SILVERSNIPER: + case NC_MAGICDECOY: + cause = USESKILL_FAIL_STUFF_INSUFFICIENT; + break; + default: + switch(require.itemid[i]){ + case ITEMID_RED_GEMSTONE: + cause = USESKILL_FAIL_REDJAMSTONE; break; + case ITEMID_BLUE_GEMSTONE: + cause = USESKILL_FAIL_BLUEJAMSTONE; break; + case ITEMID_HOLY_WATER: + cause = USESKILL_FAIL_HOLYWATER; break; + case ITEMID_ANCILLA: + cause = USESKILL_FAIL_ANCILLA; break; + case ITEMID_ACCELERATOR: + case ITEMID_HOVERING_BOOSTER: + case ITEMID_SUICIDAL_DEVICE: + case ITEMID_SHAPE_SHIFTER: + case ITEMID_COOLING_DEVICE: + case ITEMID_MAGNETIC_FIELD_GENERATOR: + case ITEMID_BARRIER_BUILDER: + case ITEMID_CAMOUFLAGE_GENERATOR: + case ITEMID_REPAIR_KIT: + case ITEMID_MONKEY_SPANNER: + cause = USESKILL_FAIL_NEED_EQUIPMENT; + default: + clif->skill_fail(sd, skill_id, cause, max(1,require.amount[i])|(require.itemid[i] << 16)); + return 0; + } + } + clif->skill_fail(sd, skill_id, cause, 0); return 0; } } @@ -13417,7 +13356,7 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin if( !req.itemid[i] ) continue; - if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_WIZARD ) + if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD ) continue; //Gemstones are checked, but not substracted from inventory. switch( skill_id ){ @@ -13521,10 +13460,12 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if( sc ) { if( sc->data[SC__LAZINESS] ) req.sp += req.sp + sc->data[SC__LAZINESS]->val1 * 10; - if (sc->data[SC_UNLIMITEDHUMMINGVOICE]) - req.sp += req.sp * sc->data[SC_UNLIMITEDHUMMINGVOICE]->val2 / 100; + if( sc->data[SC_UNLIMITED_HUMMING_VOICE] ) + req.sp += req.sp * sc->data[SC_UNLIMITED_HUMMING_VOICE]->val2 / 100; if( sc->data[SC_RECOGNIZEDSPELL] ) req.sp += req.sp / 4; + if( sc->data[SC_TELEKINESIS_INTENSE] && skill->get_ele(skill_id, skill_lv) == ELE_GHOST) + req.sp -= req.sp * sc->data[SC_TELEKINESIS_INTENSE]->val2 / 100; } req.zeny = skill_db[idx].zeny[skill_lv-1]; @@ -13644,7 +13585,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 req.zeny -= req.zeny*10/100; break; case AL_HOLYLIGHT: - if(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_PRIEST) + if(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_PRIEST) req.sp *= 5; break; case SL_SMA: @@ -13668,7 +13609,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 case MO_COMBOFINISH: case CH_TIGERFIST: case CH_CHAINCRUSH: - if(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_MONK) + if(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_MONK) req.sp -= req.sp*25/100; //FIXME: Need real data. this is a custom value. break; case MO_BODYRELOCATION: @@ -13680,9 +13621,9 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 { if( sc->data[SC_BLADESTOP] ) req.spiritball--; - else if( sc->data[SC_COMBO] ) + else if( sc->data[SC_COMBOATTACK] ) { - switch( sc->data[SC_COMBO]->val1 ) + switch( sc->data[SC_COMBOATTACK]->val1 ) { case MO_COMBOFINISH: req.spiritball = 4; @@ -13702,7 +13643,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 req.spiritball = sd->spiritball?sd->spiritball:15; break; case SR_GATEOFHELL: - if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) + if( sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) req.sp -= req.sp * 10 / 100; break; case SO_SUMMON_AGNI: @@ -13779,15 +13720,15 @@ int skill_castfix_sc (struct block_list *bl, int time) if( time < 0 ) return 0; - + if( bl->type == BL_MOB ) // mobs casttime is fixed nothing to alter. return time; if (sc && sc->count) { if (sc->data[SC_SLOWCAST]) time += time * sc->data[SC_SLOWCAST]->val2 / 100; - if (sc->data[SC_PARALYSIS]) - time += sc->data[SC_PARALYSIS]->val3; + if (sc->data[SC_NEEDLE_OF_PARALYZE]) + time += sc->data[SC_NEEDLE_OF_PARALYZE]->val3; if (sc->data[SC_SUFFRAGIUM]) { time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100; status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER); @@ -13859,8 +13800,12 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 if (sc && sc->count && !(skill->get_castnodex(skill_id, skill_lv)&2) ) { // All variable cast additive bonuses must come first + if (sc->data[SC_MAGICPOWER] ) + time += 700; if (sc->data[SC_SLOWCAST]) VARCAST_REDUCTION(-sc->data[SC_SLOWCAST]->val2); + if (sc->data[SC_FROSTMISTY]) + VARCAST_REDUCTION(-15); // Variable cast reduction bonuses if (sc->data[SC_SUFFRAGIUM]) { @@ -13878,17 +13823,33 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 VARCAST_REDUCTION(50); if (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 3 && (skill->get_ele(skill_id, skill_lv) == ELE_WATER)) VARCAST_REDUCTION(30); //Reduces 30% Variable Cast Time of Water spells. + if (sc->data[SC_TELEKINESIS_INTENSE]) + VARCAST_REDUCTION(sc->data[SC_TELEKINESIS_INTENSE]->val2); + if (sc->data[SC_SOULLINK]){ + if(sc->data[SC_SOULLINK]->val2 == SL_WIZARD || sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER) + switch(skill_id){ + case WZ_FIREPILLAR: + if(skill_lv < 5) + break; + case HW_GRAVITATION: + case MG_SAFETYWALL: + case MG_STONECURSE: + case BA_MUSICALSTRIKE: + case DC_THROWARROW: + VARCAST_REDUCTION(50); + } + } // Fixed cast reduction bonuses if( sc->data[SC__LAZINESS] ) fixcast_r = max(fixcast_r, sc->data[SC__LAZINESS]->val2); if( sc->data[SC_SECRAMENT] ) fixcast_r = max(fixcast_r, sc->data[SC_SECRAMENT]->val2); - if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP ) - fixcast_r = max(fixcast_r, 5 + skill_lv * 5); + if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && (skill_id >= WL_WHITEIMPRISON && skill_id < WL_FREEZE_SP) ) + fixcast_r = max(fixcast_r, (status_get_int(bl) + status_get_lv(bl)) / 15 + skill_lv * 5); // [{(Caster?s INT / 15) + (Caster?s Base Level / 15) + (Radius Skill Level x 5)}] % // Fixed cast non percentage bonuses if( sc->data[SC_MANDRAGORA] ) fixed += sc->data[SC_MANDRAGORA]->val1 * 1000 / 2; - if (sc->data[SC_IZAYOI] && (skill_id >= NJ_TOBIDOUGU && skill_id <= NJ_ISSEN)) + if( sc->data[SC_IZAYOI] ) fixed = 0; if( sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_WILD_STORM_OPTION] ) fixed -= 1000; @@ -13966,14 +13927,14 @@ int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) } } - if ( sc && sc->data[SC_SPIRIT] ) { + if ( sc && sc->data[SC_SOULLINK] ) { switch (skill_id) { case CR_SHIELDBOOMERANG: - if (sc->data[SC_SPIRIT]->val2 == SL_CRUSADER) + if (sc->data[SC_SOULLINK]->val2 == SL_CRUSADER) time /= 2; break; case AS_SONICBLOW: - if (!map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && sc->data[SC_SPIRIT]->val2 == SL_ASSASIN) + if (!map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && sc->data[SC_SOULLINK]->val2 == SL_ASSASIN) time /= 2; break; } @@ -14231,7 +14192,7 @@ void skill_identify (struct map_session_data *sd, int idx) int flag=1; nullpo_retv(sd); - + sd->state.workinprogress = 0; if(idx >= 0 && idx < MAX_INVENTORY) { if(sd->status.inventory[idx].nameid > 0 && sd->status.inventory[idx].identify == 0 ){ flag=0; @@ -14258,20 +14219,29 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) if(item->nameid > 0 && ditem->type == IT_WEAPON) { - if( item->refine >= sd->menuskill_val - || item->refine >= 10 // if it's no longer refineable - || ditem->flag.no_refine // if the item isn't refinable - || (i = pc->search_inventory(sd, material [ditem->wlv])) < 0 ) - { + if( ditem->flag.no_refine ){ // if the item isn't refinable clif->skill_fail(sd,sd->menuskill_id,USESKILL_FAIL_LEVEL,0); return; } + if( item->refine >= sd->menuskill_val || item->refine >= 10 ){ + clif->upgrademessage(sd->fd, 2, item->nameid); + return; + } + if( (i = pc->search_inventory(sd, material [ditem->wlv])) < 0 ){ + clif->upgrademessage(sd->fd, 3, material [ditem->wlv]); + return; + } - per = status_get_refine_chance(ditem->wlv, (int)item->refine); - per += (((signed int)sd->status.job_level)-50)/2; //Updated per the new kro descriptions. [Skotlex] - + per = status_get_refine_chance(ditem->wlv, (int)item->refine) * 10; + + // Aegis leaked formula. [malufett] + if( sd->status.class_ == JOB_MECHANIC_T ) + per += 100; + else + per += 5 * ((signed int)sd->status.job_level - 50); + pc->delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER); - if (per > rnd() % 100) { + if (per > rnd() % 1000) { logs->pick_pc(sd, LOG_TYPE_OTHER, -1, item, ditem); item->refine++; logs->pick_pc(sd, LOG_TYPE_OTHER, 1, item, ditem); @@ -14279,9 +14249,10 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) ep = item->equip; pc->unequipitem(sd,idx,3); } + clif->delitem(sd,idx,1,0); + clif->upgrademessage(sd->fd, 0,item->nameid); + clif->inventorylist(sd); clif->refine(sd->fd,0,idx,item->refine); - clif->delitem(sd,idx,1,3); - clif->additem(sd,idx,1,0); if (ep) pc->equipitem(sd,idx,ep); clif->misceffect(&sd->bl,3); @@ -14306,7 +14277,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) if(item->equip) pc->unequipitem(sd,idx,3); clif->refine(sd->fd,1,idx,item->refine); - pc->delitem(sd,idx,1,0,2, LOG_TYPE_OTHER); + pc->delitem(sd,idx,1,0,0, LOG_TYPE_OTHER); clif->misceffect(&sd->bl,2); clif->emotion(&sd->bl, E_OMG); } @@ -14331,7 +14302,7 @@ int skill_autospell (struct map_session_data *sd, uint16 skill_id) if(skill_id==MG_NAPALMBEAT) maxlv=3; else if(skill_id==MG_COLDBOLT || skill_id==MG_FIREBOLT || skill_id==MG_LIGHTNINGBOLT){ - if (sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_SAGE) + if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SAGE) maxlv =10; //Soul Linker bonus. [Skotlex] else if(skill_lv==2) maxlv=1; else if(skill_lv==3) maxlv=2; @@ -14862,7 +14833,7 @@ int skill_trap_splash (struct block_list *bl, va_list ap) { case UNT_MAIZETRAP: case UNT_VERDURETRAP: if( bl->type != BL_PC && !is_boss(bl) ) - sc_start2(bl,SC_ELEMENTALCHANGE,100,sg->skill_lv,skill->get_ele(sg->skill_id,sg->skill_lv),skill->get_time2(sg->skill_id,sg->skill_lv)); + sc_start2(bl,SC_ARMOR_PROPERTY,100,sg->skill_lv,skill->get_ele(sg->skill_id,sg->skill_lv),skill->get_time2(sg->skill_id,sg->skill_lv)); break; case UNT_REVERBERATION: skill->addtimerskill(ss,tick+50,bl->id,0,0,WM_REVERBERATION_MELEE,sg->skill_lv,BF_WEAPON,0); // for proper skill delay animation when use with Dominion Impulse @@ -14881,7 +14852,7 @@ int skill_trap_splash (struct block_list *bl, va_list ap) { int skill_enchant_elemental_end (struct block_list *bl, int type) { struct status_change *sc; - const enum sc_type scs[] = { SC_ENCPOISON, SC_ASPERSIO, SC_FIREWEAPON, SC_WATERWEAPON, SC_WINDWEAPON, SC_EARTHWEAPON, SC_SHADOWWEAPON, SC_GHOSTWEAPON, SC_ENCHANTARMS, SC_EXEEDBREAK }; + const enum sc_type scs[] = { SC_ENCHANTPOISON, SC_ASPERSIO, SC_PROPERTYFIRE, SC_PROPERTYWATER, SC_PROPERTYWIND, SC_PROPERTYGROUND, SC_PROPERTYDARK, SC_PROPERTYTELEKINESIS, SC_ENCHANTARMS, SC_EXEEDBREAK }; int i; nullpo_ret(bl); nullpo_ret(sc= status_get_sc(bl)); @@ -15036,7 +15007,7 @@ int skill_delunit (struct skill_unit* unit) { case HT_ANKLESNARE: { struct block_list* target = iMap->id2bl(group->val2); if( target ) - status_change_end(target, SC_ANKLE, INVALID_TIMER); + status_change_end(target, SC_ANKLESNARE, INVALID_TIMER); } break; case WZ_ICEWALL: @@ -16083,40 +16054,39 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, **/ case RK_RUNEMASTERY: { - int A = 100 * (51 + 2 * pc->checkskill(sd, skill_id)); - int B = 100 * status->dex / 30 + 10 * (status->luk + sd->status.job_level); + int A = 5100 + 200 * pc->checkskill(sd, skill_id); + int B = 10 * status->dex / 3 + (status->luk + sd->status.job_level); int C = 100 * cap_value(sd->itemid,0,100); //itemid depend on makerune() - int D = 0; + int D = 2500; switch (nameid) { //rune rank it_diff 9 craftable rune - case ITEMID_BERKANA: - D = -2000; - break; //Rank S - case ITEMID_NAUTHIZ: - case ITEMID_URUZ: - D = -1500; - break; //Rank A - case ITEMID_ISA: - case ITEMID_WYRD: - D = -1000; - break; //Rank B case ITEMID_RAIDO: case ITEMID_THURISAZ: case ITEMID_HAGALAZ: case ITEMID_OTHILA: - D = -500; - break; //Rank C - default: D = -1500; - break; //not specified =-15% + D -= 500; //Rank C + case ITEMID_ISA: + case ITEMID_WYRD: + D -= 500; //Rank B + case ITEMID_NAUTHIZ: + case ITEMID_URUZ: + D -= 500; //Rank A + case ITEMID_BERKANA: + D -= 500; //Rank S } - make_per = A + B + C + D; + make_per = A + B + C - D; break; } /** * Guilotine Cross **/ case GC_CREATENEWPOISON: - make_per = 3000 + 500 * pc->checkskill(sd,GC_RESEARCHNEWPOISON); - qty = 1+rnd()%pc->checkskill(sd,GC_RESEARCHNEWPOISON); + { + const int min[] = {2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; + const int max[] = {4, 5, 5, 6, 6, 7, 7, 8, 8, 9}; + uint16 lv = pc->checkskill(sd,GC_RESEARCHNEWPOISON); + make_per = 3000 + 500 * lv ; + qty = min[lv] + rand()%(max[lv] - min[lv]); + } break; case GN_CHANGEMATERIAL: for(i=0; ibl); status_change_end(&sd->bl, SC_STOP, INVALID_TIMER); - for(i=SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) if( sc && !sc->data[i] ) break; - if( i > SC_MAXSPELLBOOK ) + for(i=SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) if( sc && !sc->data[i] ) break; + if( i > SC_SPELLBOOK7 ) { clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0); return 0; @@ -16637,7 +16607,7 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { return 0; } - max_preserve = 4 * pc->checkskill(sd, WL_FREEZE_SP) + status_get_int(&sd->bl) / 10 + sd->status.base_level / 10; + max_preserve = 4 * pc->checkskill(sd, WL_FREEZE_SP) + (status_get_int(&sd->bl) + sd->status.base_level) / 10; point = skill_spellbook_db[i].point; if( sc && sc->data[SC_READING_SB] ) { @@ -16645,7 +16615,7 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_PRESERVATION_POINT, 0); return 0; } - for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett] + for(i = SC_SPELLBOOK7; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett] if( !sc->data[i] ){ sc->data[SC_READING_SB]->val2 += point; // increase points sc_start4(&sd->bl, (sc_type)i, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); @@ -16654,7 +16624,7 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { } }else{ sc_start2(&sd->bl, SC_READING_SB, 100, 0, point, INVALID_TIMER); - sc_start4(&sd->bl, SC_MAXSPELLBOOK, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); + sc_start4(&sd->bl, SC_SPELLBOOK7, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); } return 1; @@ -17365,7 +17335,7 @@ int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) { return 1; // Can't do it. } break; - case SC_KAGEHUMI: + case SC_KG_KAGEHUMI: switch(skill_id) { case TF_HIDING: case AS_CLOAKING: case GC_CLOAKINGEXCEED: case SC_SHADOWFORM: case MI_HARMONIZE: case CG_MARIONETTE: case AL_TELEPORT: case TF_BACKSLIDING: @@ -17995,6 +17965,7 @@ void skill_defaults(void) { skill->delay_fix = skill_delay_fix; skill->check_condition_castbegin = skill_check_condition_castbegin; skill->check_condition_castend = skill_check_condition_castend; + skill->check_condition_char_sub = skill_check_condition_char_sub; skill->get_requirement = skill_get_requirement; skill->check_pc_partner = skill_check_pc_partner; skill->consume_requirement = skill_consume_requirement; diff --git a/src/map/skill.h b/src/map/skill.h index c585bbb3a..cc9ac4bfc 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1281,7 +1281,26 @@ enum e_skill { ECL_SADAGUI, ECL_SEQUOIADUST, ECLAGE_RECALL, - + + GC_DARKCROW = 5001, + RA_UNLIMIT, + GN_ILLUSIONDOPING, + RK_DRAGONBREATH_WATER, + RK_LUXANIMA, + NC_MAGMA_ERUPTION, + WM_FRIGG_SONG, + SO_ELEMENTAL_SHIELD, + SR_FLASHCOMBO, + SC_ESCAPE, + AB_OFFERTORIUM, + WL_TELEKINESIS_INTENSE, + LG_KINGS_GRACE, + ALL_FULL_THROTTLE, + SR_FLASHCOMBO_ATK_STEP1, + SR_FLASHCOMBO_ATK_STEP2, + SR_FLASHCOMBO_ATK_STEP3, + SR_FLASHCOMBO_ATK_STEP4, + HLIF_HEAL = 8001, HLIF_AVOID, HLIF_BRAIN, @@ -1541,6 +1560,10 @@ enum { UNT_ZENKAI_WIND, UNT_MAKIBISHI, UNT_VENOMFOG, + UNT_ICEMINE, + UNT_FLAMECROSS, + UNT_HELLBURNING, + UNT_MAGMA_ERUPTION, /** * Guild Auras diff --git a/src/map/status.c b/src/map/status.c index c163135d8..0e1661728 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -69,6 +69,7 @@ static struct { static int atkmods[3][MAX_WEAPON_TYPE]; //ATK weapon modification for size (size_fix.txt) static char job_bonus[CLASS_COUNT][MAX_LEVEL]; +static sc_conf_type sc_conf[SC_MAX]; static struct eri *sc_data_ers; //For sc_data entries static struct status_data dummy_status; @@ -189,7 +190,7 @@ void initChangeTables(void) { set_sc( NPC_SILENCEATTACK , SC_SILENCE , SI_BLANK , SCB_NONE ); set_sc( NPC_WIDECONFUSE , SC_CONFUSION , SI_BLANK , SCB_NONE ); set_sc( NPC_BLINDATTACK , SC_BLIND , SI_BLANK , SCB_HIT|SCB_FLEE ); - set_sc( NPC_BLEEDING , SC_BLEEDING , SI_BLEEDING , SCB_REGEN ); + set_sc( NPC_BLEEDING , SC_BLOODING , SI_BLOODING , SCB_REGEN ); set_sc( NPC_POISON , SC_DPOISON , SI_BLANK , SCB_DEF2|SCB_REGEN ); //The main status definitions @@ -203,12 +204,12 @@ void initChangeTables(void) { add_sc( MG_STONECURSE , SC_STONE ); add_sc( AL_RUWACH , SC_RUWACH ); add_sc( AL_PNEUMA , SC_PNEUMA ); - set_sc( AL_INCAGI , SC_INCREASEAGI , SI_INCREASEAGI , SCB_AGI|SCB_SPEED ); - set_sc( AL_DECAGI , SC_DECREASEAGI , SI_DECREASEAGI , SCB_AGI|SCB_SPEED ); - set_sc( AL_CRUCIS , SC_SIGNUMCRUCIS , SI_SIGNUMCRUCIS , SCB_DEF ); + set_sc( AL_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); + set_sc( AL_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); + set_sc( AL_CRUCIS , SC_CRUCIS , SI_CRUCIS , SCB_DEF ); set_sc( AL_ANGELUS , SC_ANGELUS , SI_ANGELUS , SCB_DEF2 ); set_sc( AL_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( AC_CONCENTRATION , SC_CONCENTRATE , SI_CONCENTRATE , SCB_AGI|SCB_DEX ); + set_sc( AC_CONCENTRATION , SC_CONCENTRATION , SI_CONCENTRATION , SCB_AGI|SCB_DEX ); set_sc( TF_HIDING , SC_HIDING , SI_HIDING , SCB_SPEED ); add_sc( TF_POISON , SC_POISON ); set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SI_TWOHANDQUICKEN , SCB_ASPD ); @@ -222,44 +223,44 @@ void initChangeTables(void) { set_sc( PR_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); set_sc( PR_GLORIA , SC_GLORIA , SI_GLORIA , SCB_LUK ); add_sc( PR_LEXDIVINA , SC_SILENCE ); - set_sc( PR_LEXAETERNA , SC_AETERNA , SI_AETERNA , SCB_NONE ); + set_sc( PR_LEXAETERNA , SC_LEXAETERNA , SI_LEXAETERNA , SCB_NONE ); add_sc( WZ_METEOR , SC_STUN ); add_sc( WZ_VERMILION , SC_BLIND ); add_sc( WZ_FROSTNOVA , SC_FREEZE ); add_sc( WZ_STORMGUST , SC_FREEZE ); - set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SI_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED ); - set_sc( BS_ADRENALINE , SC_ADRENALINE , SI_ADRENALINE , SCB_ASPD ); - set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECTION, SI_WEAPONPERFECTION, SCB_NONE ); - set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SI_OVERTHRUST , SCB_NONE ); - set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SI_MAXIMIZEPOWER , SCB_REGEN ); - add_sc( HT_LANDMINE , SC_STUN ); - add_sc( HT_ANKLESNARE , SC_ANKLE ); + set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SI_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED ); + set_sc( BS_ADRENALINE , SC_ADRENALINE , SI_ADRENALINE , SCB_ASPD ); + set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECT , SI_WEAPONPERFECT, SCB_NONE ); + set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SI_OVERTHRUST , SCB_NONE ); + set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SI_MAXIMIZE , SCB_REGEN ); + add_sc( HT_LANDMINE , SC_STUN ); + set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SI_ANKLESNARE , SCB_NONE ); add_sc( HT_SANDMAN , SC_SLEEP ); add_sc( HT_FLASHER , SC_BLIND ); add_sc( HT_FREEZINGTRAP , SC_FREEZE ); - set_sc( AS_CLOAKING , SC_CLOAKING , SI_CLOAKING , SCB_CRI|SCB_SPEED ); + set_sc( AS_CLOAKING , SC_CLOAKING , SI_CLOAKING , SCB_CRI|SCB_SPEED ); add_sc( AS_SONICBLOW , SC_STUN ); - set_sc( AS_ENCHANTPOISON , SC_ENCPOISON , SI_ENCPOISON , SCB_ATK_ELE ); - set_sc( AS_POISONREACT , SC_POISONREACT , SI_POISONREACT , SCB_NONE ); + set_sc( AS_ENCHANTPOISON , SC_ENCHANTPOISON , SI_ENCHANTPOISON, SCB_ATK_ELE ); + set_sc( AS_POISONREACT , SC_POISONREACT , SI_POISONREACT , SCB_NONE ); add_sc( AS_VENOMDUST , SC_POISON ); add_sc( AS_SPLASHER , SC_SPLASHER ); - set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SI_TRICKDEAD , SCB_REGEN ); - set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); + set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SI_TRICKDEAD , SCB_REGEN ); + set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); add_sc( TF_SPRINKLESAND , SC_BLIND ); add_sc( TF_THROWSTONE , SC_STUN ); - set_sc( MC_LOUD , SC_LOUD , SI_LOUD , SCB_STR ); - set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SI_ENERGYCOAT , SCB_NONE ); - set_sc( NPC_EMOTION , SC_MODECHANGE , SI_BLANK , SCB_MODE ); - add_sc( NPC_EMOTION_ON , SC_MODECHANGE ); - set_sc( NPC_ATTRICHANGE , SC_ELEMENTALCHANGE , SI_ARMOR_PROPERTY , SCB_DEF_ELE ); - add_sc( NPC_CHANGEWATER , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEGROUND , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEFIRE , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEWIND , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEPOISON , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEHOLY , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGEDARKNESS , SC_ELEMENTALCHANGE ); - add_sc( NPC_CHANGETELEKINESIS, SC_ELEMENTALCHANGE ); + set_sc( MC_LOUD , SC_SHOUT , SI_SHOUT , SCB_STR ); + set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SI_ENERGYCOAT , SCB_NONE ); + set_sc( NPC_EMOTION , SC_MODECHANGE , SI_BLANK , SCB_MODE ); + add_sc( NPC_EMOTION_ON , SC_MODECHANGE ); + set_sc( NPC_ATTRICHANGE , SC_ARMOR_PROPERTY , SI_ARMOR_PROPERTY , SCB_DEF_ELE ); + add_sc( NPC_CHANGEWATER , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEGROUND , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEFIRE , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEWIND , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEPOISON , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEHOLY , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGEDARKNESS , SC_ARMOR_PROPERTY ); + add_sc( NPC_CHANGETELEKINESIS, SC_ARMOR_PROPERTY ); add_sc( NPC_POISON , SC_POISON ); add_sc( NPC_BLINDATTACK , SC_BLIND ); add_sc( NPC_SILENCEATTACK , SC_SILENCE ); @@ -273,25 +274,25 @@ void initChangeTables(void) { set_sc( NPC_BARRIER , SC_BARRIER , SI_BLANK , SCB_MDEF|SCB_DEF ); add_sc( NPC_DEFENDER , SC_ARMOR ); add_sc( NPC_LICK , SC_STUN ); - set_sc( NPC_HALLUCINATION , SC_HALLUCINATION , SI_HALLUCINATION , SCB_NONE ); + set_sc( NPC_HALLUCINATION , SC_ILLUSION , SI_ILLUSION , SCB_NONE ); add_sc( NPC_REBIRTH , SC_REBIRTH ); add_sc( RG_RAID , SC_STUN ); #ifdef RENEWAL add_sc( RG_RAID , SC_RAID ); add_sc( RG_BACKSTAP , SC_STUN ); #endif - set_sc( RG_STRIPWEAPON , SC_STRIPWEAPON , SI_STRIPWEAPON , SCB_WATK ); - set_sc( RG_STRIPSHIELD , SC_STRIPSHIELD , SI_STRIPSHIELD , SCB_DEF ); - set_sc( RG_STRIPARMOR , SC_STRIPARMOR , SI_STRIPARMOR , SCB_VIT ); - set_sc( RG_STRIPHELM , SC_STRIPHELM , SI_STRIPHELM , SCB_INT ); - add_sc( AM_ACIDTERROR , SC_BLEEDING ); - set_sc( AM_CP_WEAPON , SC_CP_WEAPON , SI_CP_WEAPON , SCB_NONE ); - set_sc( AM_CP_SHIELD , SC_CP_SHIELD , SI_CP_SHIELD , SCB_NONE ); - set_sc( AM_CP_ARMOR , SC_CP_ARMOR , SI_CP_ARMOR , SCB_NONE ); - set_sc( AM_CP_HELM , SC_CP_HELM , SI_CP_HELM , SCB_NONE ); - set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); + set_sc( RG_STRIPWEAPON , SC_NOEQUIPWEAPON , SI_NOEQUIPWEAPON , SCB_WATK ); + set_sc( RG_STRIPSHIELD , SC_NOEQUIPSHIELD , SI_NOEQUIPSHIELD , SCB_DEF ); + set_sc( RG_STRIPARMOR , SC_NOEQUIPARMOR , SI_NOEQUIPARMOR , SCB_VIT ); + set_sc( RG_STRIPHELM , SC_NOEQUIPHELM , SI_NOEQUIPHELM , SCB_INT ); + add_sc( AM_ACIDTERROR , SC_BLOODING ); + set_sc( AM_CP_WEAPON , SC_PROTECTWEAPON , SI_PROTECTWEAPON , SCB_NONE ); + set_sc( AM_CP_SHIELD , SC_PROTECTSHIELD , SI_PROTECTSHIELD , SCB_NONE ); + set_sc( AM_CP_ARMOR , SC_PROTECTARMOR , SI_PROTECTARMOR , SCB_NONE ); + set_sc( AM_CP_HELM , SC_PROTECTHELM , SI_PROTECTHELM , SCB_NONE ); + set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); add_sc( CR_SHIELDCHARGE , SC_STUN ); - set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); + set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); add_sc( CR_HOLYCROSS , SC_BLIND ); add_sc( CR_GRANDCROSS , SC_BLIND ); add_sc( CR_DEVOTION , SC_DEVOTION ); @@ -304,17 +305,17 @@ void initChangeTables(void) { set_sc( MO_EXPLOSIONSPIRITS , SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN ); set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST , SI_BLANK , SCB_REGEN ); #ifdef RENEWAL - set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SI_EXTREMITYFIST , SCB_NONE ); + set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SI_EXTREMITYFIST , SCB_NONE ); #endif add_sc( SA_MAGICROD , SC_MAGICROD ); set_sc( SA_AUTOSPELL , SC_AUTOSPELL , SI_AUTOSPELL , SCB_NONE ); - set_sc( SA_FLAMELAUNCHER , SC_FIREWEAPON , SI_FIREWEAPON , SCB_ATK_ELE ); - set_sc( SA_FROSTWEAPON , SC_WATERWEAPON , SI_WATERWEAPON , SCB_ATK_ELE ); - set_sc( SA_LIGHTNINGLOADER , SC_WINDWEAPON , SI_WINDWEAPON , SCB_ATK_ELE ); - set_sc( SA_SEISMICWEAPON , SC_EARTHWEAPON , SI_EARTHWEAPON , SCB_ATK_ELE ); - set_sc( SA_VOLCANO , SC_VOLCANO , SI_LANDENDOW , SCB_WATK ); - set_sc( SA_DELUGE , SC_DELUGE , SI_LANDENDOW , SCB_MAXHP ); - set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SI_LANDENDOW , SCB_FLEE ); + set_sc( SA_FLAMELAUNCHER , SC_PROPERTYFIRE , SI_PROPERTYFIRE , SCB_ATK_ELE ); + set_sc( SA_FROSTWEAPON , SC_PROPERTYWATER , SI_PROPERTYWATER , SCB_ATK_ELE ); + set_sc( SA_LIGHTNINGLOADER , SC_PROPERTYWIND , SI_PROPERTYWIND , SCB_ATK_ELE ); + set_sc( SA_SEISMICWEAPON , SC_PROPERTYGROUND , SI_PROPERTYGROUND , SCB_ATK_ELE ); + set_sc( SA_VOLCANO , SC_VOLCANO , SI_GROUNDMAGIC , SCB_WATK ); + set_sc( SA_DELUGE , SC_DELUGE , SI_GROUNDMAGIC , SCB_MAXHP ); + set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SI_GROUNDMAGIC , SCB_FLEE ); add_sc( SA_REVERSEORCISH , SC_ORCISH ); add_sc( SA_COMA , SC_COMA ); set_sc( BD_ENCORE , SC_DANCING , SI_BLANK , SCB_SPEED|SCB_REGEN ); @@ -334,19 +335,23 @@ void initChangeTables(void) { set_sc( DC_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT ); set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD ); set_sc( DC_FORTUNEKISS , SC_FORTUNE , SI_BLANK , SCB_CRI ); - set_sc( DC_SERVICEFORYOU , SC_SERVICE4U , SI_BLANK , SCB_ALL ); + set_sc( DC_SERVICEFORYOU , SC_SERVICEFORYOU , SI_BLANK , SCB_ALL ); add_sc( NPC_DARKCROSS , SC_BLIND ); add_sc( NPC_GRANDDARKNESS , SC_BLIND ); set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE ); set_sc( NPC_WEAPONBRAKER , SC_BROKENWEAPON , SI_BROKENWEAPON , SCB_NONE ); set_sc( NPC_ARMORBRAKE , SC_BROKENARMOR , SI_BROKENARMOR , SCB_NONE ); - set_sc( NPC_CHANGEUNDEAD , SC_CHANGEUNDEAD , SI_UNDEAD , SCB_DEF_ELE ); + set_sc( NPC_CHANGEUNDEAD , SC_PROPERTYUNDEAD , SI_PROPERTYUNDEAD , SCB_DEF_ELE ); set_sc( NPC_POWERUP , SC_INCHITRATE , SI_BLANK , SCB_HIT ); set_sc( NPC_AGIUP , SC_INCFLEERATE , SI_BLANK , SCB_FLEE ); add_sc( NPC_INVISIBLE , SC_CLOAKING ); set_sc( LK_AURABLADE , SC_AURABLADE , SI_AURABLADE , SCB_NONE ); set_sc( LK_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); - set_sc( LK_CONCENTRATION , SC_CONCENTRATION , SI_CONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_DSPD ); +#ifndef RENEWAL + set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_CONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2); +#else + set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_CONCENTRATION , SCB_HIT|SCB_DEF); +#endif set_sc( LK_TENSIONRELAX , SC_TENSIONRELAX , SI_TENSIONRELAX , SCB_REGEN ); set_sc( LK_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); set_sc( HP_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); @@ -362,32 +367,32 @@ void initChangeTables(void) { set_sc( WS_MELTDOWN , SC_MELTDOWN , SI_MELTDOWN , SCB_NONE ); set_sc( WS_CARTBOOST , SC_CARTBOOST , SI_CARTBOOST , SCB_SPEED ); set_sc( ST_CHASEWALK , SC_CHASEWALK , SI_BLANK , SCB_SPEED ); - set_sc( ST_REJECTSWORD , SC_REJECTSWORD , SI_REJECTSWORD , SCB_NONE ); + set_sc( ST_REJECTSWORD , SC_SWORDREJECT , SI_SWORDREJECT , SCB_NONE ); add_sc( ST_REJECTSWORD , SC_AUTOCOUNTER ); - set_sc( CG_MARIONETTE , SC_MARIONETTE , SI_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); - set_sc( CG_MARIONETTE , SC_MARIONETTE2 , SI_MARIONETTE2 , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + set_sc( CG_MARIONETTE , SC_MARIONETTE_MASTER , SI_MARIONETTE_MASTER , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + set_sc( CG_MARIONETTE , SC_MARIONETTE , SI_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); add_sc( LK_SPIRALPIERCE , SC_STOP ); - add_sc( LK_HEADCRUSH , SC_BLEEDING ); + add_sc( LK_HEADCRUSH , SC_BLOODING ); set_sc( LK_JOINTBEAT , SC_JOINTBEAT , SI_JOINTBEAT , SCB_BATK|SCB_DEF2|SCB_SPEED|SCB_ASPD ); add_sc( HW_NAPALMVULCAN , SC_CURSE ); set_sc( PF_MINDBREAKER , SC_MINDBREAKER , SI_BLANK , SCB_MATK|SCB_MDEF2 ); add_sc( PF_MEMORIZE , SC_MEMORIZE ); add_sc( PF_FOGWALL , SC_FOGWALL ); set_sc( PF_SPIDERWEB , SC_SPIDERWEB , SI_BLANK , SCB_FLEE ); - set_sc( WE_BABY , SC_BABY , SI_BABY , SCB_NONE ); + set_sc( WE_BABY , SC_BABY , SI_PROTECTEXP , SCB_NONE ); set_sc( TK_RUN , SC_RUN , SI_RUN , SCB_SPEED|SCB_DSPD ); - set_sc( TK_RUN , SC_SPURT , SI_SPURT , SCB_STR ); - set_sc( TK_READYSTORM , SC_READYSTORM , SI_READYSTORM , SCB_NONE ); - set_sc( TK_READYDOWN , SC_READYDOWN , SI_READYDOWN , SCB_NONE ); + set_sc( TK_RUN , SC_STRUP , SI_STRUP , SCB_STR ); + set_sc( TK_READYSTORM , SC_STORMKICK_READY , SI_STORMKICK_ON , SCB_NONE ); + set_sc( TK_READYDOWN , SC_DOWNKICK_READY , SI_DOWNKICK_ON , SCB_NONE ); add_sc( TK_DOWNKICK , SC_STUN ); - set_sc( TK_READYTURN , SC_READYTURN , SI_READYTURN , SCB_NONE ); - set_sc( TK_READYCOUNTER , SC_READYCOUNTER , SI_READYCOUNTER , SCB_NONE ); - set_sc( TK_DODGE , SC_DODGE , SI_DODGE , SCB_NONE ); + set_sc( TK_READYTURN , SC_TURNKICK_READY , SI_TURNKICK_ON , SCB_NONE ); + set_sc( TK_READYCOUNTER , SC_COUNTERKICK_READY , SI_COUNTER_ON , SCB_NONE ); + set_sc( TK_DODGE , SC_DODGE_READY , SI_DODGE_ON , SCB_NONE ); set_sc( TK_SPTIME , SC_EARTHSCROLL , SI_EARTHSCROLL , SCB_NONE ); - add_sc( TK_SEVENWIND , SC_SEVENWIND ); - set_sc( TK_SEVENWIND , SC_GHOSTWEAPON , SI_GHOSTWEAPON , SCB_ATK_ELE ); - set_sc( TK_SEVENWIND , SC_SHADOWWEAPON , SI_SHADOWWEAPON , SCB_ATK_ELE ); - set_sc( SG_SUN_WARM , SC_WARM , SI_WARM , SCB_NONE ); + add_sc( TK_SEVENWIND , SC_TK_SEVENWIND ); + set_sc( TK_SEVENWIND , SC_PROPERTYTELEKINESIS , SI_PROPERTYTELEKINESIS , SCB_ATK_ELE ); + set_sc( TK_SEVENWIND , SC_PROPERTYDARK , SI_PROPERTYDARK , SCB_ATK_ELE ); + set_sc( SG_SUN_WARM , SC_WARM , SI_SG_SUN_WARM , SCB_NONE ); add_sc( SG_MOON_WARM , SC_WARM ); add_sc( SG_STAR_WARM , SC_WARM ); set_sc( SG_SUN_COMFORT , SC_SUN_COMFORT , SI_SUN_COMFORT , SCB_DEF2 ); @@ -405,39 +410,40 @@ void initChangeTables(void) { set_sc( SL_SWOO , SC_SWOO , SI_BLANK , SCB_SPEED ); set_sc( SL_SKE , SC_SKE , SI_BLANK , SCB_BATK|SCB_WATK|SCB_DEF|SCB_DEF2 ); set_sc( SL_SKA , SC_SKA , SI_BLANK , SCB_DEF|SCB_MDEF|SCB_ASPD ); - set_sc( SL_SMA , SC_SMA , SI_SMA , SCB_NONE ); + set_sc( SL_SMA , SC_SMA_READY , SI_SMA_READY , SCB_NONE ); set_sc( SM_SELFPROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); set_sc( ST_PRESERVE , SC_PRESERVE , SI_PRESERVE , SCB_NONE ); - set_sc( PF_DOUBLECASTING , SC_DOUBLECAST , SI_DOUBLECAST , SCB_NONE ); + set_sc( PF_DOUBLECASTING , SC_DOUBLECASTING , SI_DOUBLECASTING , SCB_NONE ); set_sc( HW_GRAVITATION , SC_GRAVITATION , SI_BLANK , SCB_ASPD ); add_sc( WS_CARTTERMINATION , SC_STUN ); - set_sc( WS_OVERTHRUSTMAX , SC_MAXOVERTHRUST , SI_MAXOVERTHRUST , SCB_NONE ); + set_sc( WS_OVERTHRUSTMAX , SC_OVERTHRUSTMAX , SI_OVERTHRUSTMAX , SCB_NONE ); set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD ); add_sc( CG_HERMODE , SC_HERMODE ); + set_sc( CG_TAROTCARD , SC_TAROTCARD , SI_TAROTCARD , SCB_NONE ); set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE ); - set_sc( SL_HIGH , SC_SPIRIT , SI_SPIRIT , SCB_ALL ); - set_sc( KN_ONEHAND , SC_ONEHAND , SI_ONEHAND , SCB_ASPD ); + set_sc( SL_HIGH , SC_SOULLINK , SI_SOULLINK , SCB_ALL ); + set_sc( KN_ONEHAND , SC_ONEHANDQUICKEN , SI_ONEHANDQUICKEN , SCB_ASPD ); set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 ); add_sc( GS_CRACKER , SC_STUN ); - add_sc( GS_DISARM , SC_STRIPWEAPON ); - add_sc( GS_PIERCINGSHOT , SC_BLEEDING ); - set_sc( GS_MADNESSCANCEL , SC_MADNESSCANCEL , SI_MADNESSCANCEL , SCB_BATK|SCB_ASPD ); - set_sc( GS_ADJUSTMENT , SC_ADJUSTMENT , SI_ADJUSTMENT , SCB_HIT|SCB_FLEE ); - set_sc( GS_INCREASING , SC_INCREASING , SI_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT ); - set_sc( GS_GATLINGFEVER , SC_GATLINGFEVER , SI_GATLINGFEVER , SCB_BATK|SCB_FLEE|SCB_SPEED|SCB_ASPD ); - set_sc( NJ_TATAMIGAESHI , SC_TATAMIGAESHI , SI_BLANK , SCB_NONE ); - set_sc( NJ_SUITON , SC_SUITON , SI_BLANK , SCB_AGI|SCB_SPEED ); + add_sc( GS_DISARM , SC_NOEQUIPWEAPON ); + add_sc( GS_PIERCINGSHOT , SC_BLOODING ); + set_sc( GS_MADNESSCANCEL , SC_GS_MADNESSCANCEL , SI_GS_MADNESSCANCEL , SCB_BATK|SCB_ASPD ); + set_sc( GS_ADJUSTMENT , SC_GS_ADJUSTMENT , SI_GS_ADJUSTMENT , SCB_HIT|SCB_FLEE ); + set_sc( GS_INCREASING , SC_GS_ACCURACY , SI_GS_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT ); + set_sc( GS_GATLINGFEVER , SC_GS_GATLINGFEVER , SI_GS_GATLINGFEVER , SCB_BATK|SCB_FLEE|SCB_SPEED|SCB_ASPD ); + set_sc( NJ_TATAMIGAESHI , SC_NJ_TATAMIGAESHI , SI_BLANK , SCB_NONE ); + set_sc( NJ_SUITON , SC_NJ_SUITON , SI_NJ_SUITON , SCB_AGI|SCB_SPEED ); add_sc( NJ_HYOUSYOURAKU , SC_FREEZE ); - set_sc( NJ_NEN , SC_NEN , SI_NEN , SCB_STR|SCB_INT ); - set_sc( NJ_UTSUSEMI , SC_UTSUSEMI , SI_UTSUSEMI , SCB_NONE ); - set_sc( NJ_BUNSINJYUTSU , SC_BUNSINJYUTSU , SI_BUNSINJYUTSU , SCB_DYE ); + set_sc( NJ_NEN , SC_NJ_NEN , SI_NJ_NEN , SCB_STR|SCB_INT ); + set_sc( NJ_UTSUSEMI , SC_NJ_UTSUSEMI , SI_NJ_UTSUSEMI , SCB_NONE ); + set_sc( NJ_BUNSINJYUTSU , SC_NJ_BUNSINJYUTSU , SI_NJ_BUNSINJYUTSU , SCB_DYE ); add_sc( NPC_ICEBREATH , SC_FREEZE ); add_sc( NPC_ACIDBREATH , SC_POISON ); add_sc( NPC_HELLJUDGEMENT , SC_CURSE ); add_sc( NPC_WIDESILENCE , SC_SILENCE ); add_sc( NPC_WIDEFREEZE , SC_FREEZE ); - add_sc( NPC_WIDEBLEEDING , SC_BLEEDING ); + add_sc( NPC_WIDEBLEEDING , SC_BLOODING ); add_sc( NPC_WIDESTONE , SC_STONE ); add_sc( NPC_WIDECONFUSE , SC_CONFUSION ); add_sc( NPC_WIDESLEEP , SC_SLEEP ); @@ -446,8 +452,8 @@ void initChangeTables(void) { add_sc( NPC_MAGICMIRROR , SC_MAGICMIRROR ); set_sc( NPC_SLOWCAST , SC_SLOWCAST , SI_SLOWCAST , SCB_NONE ); set_sc( NPC_CRITICALWOUND , SC_CRITICALWOUND , SI_CRITICALWOUND , SCB_NONE ); - set_sc( NPC_STONESKIN , SC_ARMORCHANGE , SI_BLANK , SCB_DEF|SCB_MDEF ); - add_sc( NPC_ANTIMAGIC , SC_ARMORCHANGE ); + set_sc( NPC_STONESKIN , SC_STONESKIN , SI_BLANK , SCB_DEF|SCB_MDEF ); + add_sc( NPC_ANTIMAGIC , SC_STONESKIN ); add_sc( NPC_WIDECURSE , SC_CURSE ); add_sc( NPC_WIDESTUN , SC_STUN ); @@ -457,29 +463,29 @@ void initChangeTables(void) { set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SI_BLANK , SCB_SPEED ); set_sc( CASH_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( CASH_INCAGI , SC_INCREASEAGI , SI_INCREASEAGI , SCB_AGI|SCB_SPEED ); + set_sc( CASH_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE ); set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SI_PARTYFLEE , SCB_NONE ); set_sc( ALL_ODINS_POWER , SC_ODINS_POWER , SI_ODINS_POWER , SCB_MATK|SCB_BATK|SCB_MDEF|SCB_DEF ); - set_sc( CR_SHRINK , SC_SHRINK , SI_SHRINK , SCB_NONE ); - set_sc( RG_CLOSECONFINE , SC_CLOSECONFINE2 , SI_CLOSECONFINE2 , SCB_NONE ); - set_sc( RG_CLOSECONFINE , SC_CLOSECONFINE , SI_CLOSECONFINE , SCB_FLEE ); - set_sc( WZ_SIGHTBLASTER , SC_SIGHTBLASTER , SI_SIGHTBLASTER , SCB_NONE ); - set_sc( DC_WINKCHARM , SC_WINKCHARM , SI_WINKCHARM , SCB_NONE ); + set_sc( CR_SHRINK , SC_CR_SHRINK , SI_CR_SHRINK , SCB_NONE ); + set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); + set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); + set_sc( WZ_SIGHTBLASTER , SC_WZ_SIGHTBLASTER , SI_WZ_SIGHTBLASTER , SCB_NONE ); + set_sc( DC_WINKCHARM , SC_DC_WINKCHARM , SI_DC_WINKCHARM , SCB_NONE ); add_sc( MO_BALKYOUNG , SC_STUN ); - add_sc( SA_ELEMENTWATER , SC_ELEMENTALCHANGE ); - add_sc( SA_ELEMENTFIRE , SC_ELEMENTALCHANGE ); - add_sc( SA_ELEMENTGROUND , SC_ELEMENTALCHANGE ); - add_sc( SA_ELEMENTWIND , SC_ELEMENTALCHANGE ); - - set_sc( HLIF_AVOID , SC_AVOID , SI_BLANK , SCB_SPEED ); - set_sc( HLIF_CHANGE , SC_CHANGE , SI_BLANK , SCB_VIT|SCB_INT ); - set_sc( HFLI_FLEET , SC_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK ); - set_sc( HFLI_SPEED , SC_SPEED , SI_BLANK , SCB_FLEE ); - set_sc( HAMI_DEFENCE , SC_DEFENCE , SI_BLANK , SCB_DEF ); - set_sc( HAMI_BLOODLUST , SC_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); + add_sc( SA_ELEMENTWATER , SC_ARMOR_PROPERTY ); + add_sc( SA_ELEMENTFIRE , SC_ARMOR_PROPERTY ); + add_sc( SA_ELEMENTGROUND , SC_ARMOR_PROPERTY ); + add_sc( SA_ELEMENTWIND , SC_ARMOR_PROPERTY ); + + set_sc( HLIF_AVOID , SC_HLIF_AVOID , SI_BLANK , SCB_SPEED ); + set_sc( HLIF_CHANGE , SC_HLIF_CHANGE , SI_BLANK , SCB_VIT|SCB_INT ); + set_sc( HFLI_FLEET , SC_HLIF_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK ); + set_sc( HFLI_SPEED , SC_HLIF_SPEED , SI_BLANK , SCB_FLEE ); + set_sc( HAMI_DEFENCE , SC_HAMI_DEFENCE , SI_BLANK , SCB_DEF ); + set_sc( HAMI_BLOODLUST , SC_HAMI_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); // Homunculus S add_sc(MH_STAHL_HORN, SC_STUN); @@ -489,25 +495,25 @@ void initChangeTables(void) { add_sc(MH_ERASER_CUTTER, SC_ERASER_CUTTER); set_sc(MH_OVERED_BOOST, SC_OVERED_BOOST, SI_BLANK, SCB_FLEE|SCB_ASPD); add_sc(MH_LIGHT_OF_REGENE, SC_LIGHT_OF_REGENE); - set_sc(MH_VOLCANIC_ASH, SC_ASH, SI_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE); + set_sc(MH_VOLCANIC_ASH, SC_VOLCANIC_ASH, SI_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE); set_sc(MH_GRANITIC_ARMOR, SC_GRANITIC_ARMOR, SI_GRANITIC_ARMOR, SCB_NONE); set_sc(MH_MAGMA_FLOW, SC_MAGMA_FLOW, SI_MAGMA_FLOW, SCB_NONE); set_sc(MH_PYROCLASTIC, SC_PYROCLASTIC, SI_PYROCLASTIC, SCB_BATK|SCB_ATK_ELE); add_sc(MH_LAVA_SLIDE, SC_BURNING); - set_sc(MH_NEEDLE_OF_PARALYZE, SC_PARALYSIS, SI_NEEDLE_OF_PARALYZE, SCB_DEF2); + set_sc(MH_NEEDLE_OF_PARALYZE, SC_NEEDLE_OF_PARALYZE, SI_NEEDLE_OF_PARALYZE, SCB_DEF2); add_sc(MH_POISON_MIST, SC_BLIND); set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); add_sc(MH_STYLE_CHANGE, SC_STYLE_CHANGE); - set_sc( MH_TINDER_BREAKER , SC_CLOSECONFINE2 , SI_CLOSECONFINE2 , SCB_NONE ); - set_sc( MH_TINDER_BREAKER , SC_CLOSECONFINE , SI_CLOSECONFINE , SCB_FLEE ); + set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE ); + set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE ); add_sc( MER_CRASH , SC_STUN ); set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); add_sc( MS_MAGNUM , SC_WATK_ELEMENT ); add_sc( MER_SIGHT , SC_SIGHT ); - set_sc( MER_DECAGI , SC_DECREASEAGI , SI_DECREASEAGI , SCB_AGI|SCB_SPEED ); + set_sc( MER_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED ); set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); add_sc( MER_LEXDIVINA , SC_SILENCE ); add_sc( MA_LANDMINE , SC_STUN ); @@ -520,19 +526,19 @@ void initChangeTables(void) { set_sc( MS_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); set_sc( MS_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); add_sc( ML_SPIRALPIERCE , SC_STOP ); - set_sc( MER_QUICKEN , SC_MERC_QUICKEN , SI_BLANK , SCB_ASPD ); + set_sc( MER_QUICKEN , SC_MER_QUICKEN , SI_BLANK , SCB_ASPD ); add_sc( ML_DEVOTION , SC_DEVOTION ); set_sc( MER_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE ); set_sc( MER_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( MER_INCAGI , SC_INCREASEAGI , SI_INCREASEAGI , SCB_AGI|SCB_SPEED ); + set_sc( MER_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED ); set_sc( GD_LEADERSHIP , SC_LEADERSHIP , SI_BLANK , SCB_STR ); set_sc( GD_GLORYWOUNDS , SC_GLORYWOUNDS , SI_BLANK , SCB_VIT ); set_sc( GD_SOULCOLD , SC_SOULCOLD , SI_BLANK , SCB_AGI ); set_sc( GD_HAWKEYES , SC_HAWKEYES , SI_BLANK , SCB_DEX ); - set_sc( GD_BATTLEORDER , SC_BATTLEORDERS , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); - set_sc( GD_REGENERATION , SC_REGENERATION , SI_BLANK , SCB_REGEN ); + set_sc( GD_BATTLEORDER , SC_GDSKILL_BATTLEORDER , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); + set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SI_BLANK , SCB_REGEN ); /** * Rune Knight @@ -541,15 +547,16 @@ void initChangeTables(void) { set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE ); set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT ); - add_sc( RK_DRAGONBREATH , SC_BURNING ); - set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_REUSE_MILLENNIUMSHIELD , SCB_NONE ); + set_sc( RK_DRAGONBREATH , SC_BURNING , SI_BLANK , SCB_MDEF ); + set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE ); set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE ); set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR ); - set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_DEF|SCB_MDEF ); + set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE ); set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN ); set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD ); set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE ); set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE ); + add_sc( RK_DRAGONBREATH_WATER, SC_FROSTMISTY ); /** * GC Guillotine Cross **/ @@ -559,12 +566,13 @@ void initChangeTables(void) { set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED ); set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE ); set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE ); + set_sc_with_vfx( GC_DARKCROW , SC_DARKCROW , SI_DARKCROW , SCB_NONE ); /** * Arch Bishop **/ set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED ); add_sc( AB_CLEMENTIA , SC_BLESSING ); - add_sc( AB_CANTO , SC_INCREASEAGI ); + add_sc( AB_CANTO , SC_INC_AGI ); set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP ); add_sc( AB_PRAEFATIO , SC_KYRIE ); set_sc_with_vfx( AB_ORATIO , SC_ORATIO , SI_ORATIO , SCB_NONE ); @@ -574,14 +582,16 @@ void initChangeTables(void) { set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE ); set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE ); set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE ); + set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SI_OFFERTORIUM , SCB_NONE ); /** * Warlock **/ add_sc( WL_WHITEIMPRISON , SC_WHITEIMPRISON ); - set_sc_with_vfx( WL_FROSTMISTY , SC_FREEZING , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF|SCB_DEF2 ); - set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_DEF|SCB_MDEF ); + set_sc_with_vfx( WL_FROSTMISTY , SC_FROSTMISTY , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF ); + set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_AGI|SCB_DEX ); set_sc(WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_MATK); set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE ); + set_sc( WL_TELEKINESIS_INTENSE, SC_TELEKINESIS_INTENSE , SI_TELEKINESIS_INTENSE , SCB_MATK ); /** * Ranger **/ @@ -589,12 +599,13 @@ void initChangeTables(void) { set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE ); set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED ); set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_SPEED ); - add_sc( RA_MAGENTATRAP , SC_ELEMENTALCHANGE ); - add_sc( RA_COBALTTRAP , SC_ELEMENTALCHANGE ); - add_sc( RA_MAIZETRAP , SC_ELEMENTALCHANGE ); - add_sc( RA_VERDURETRAP , SC_ELEMENTALCHANGE ); - add_sc( RA_FIRINGTRAP , SC_BURNING ); - set_sc_with_vfx( RA_ICEBOUNDTRAP , SC_FREEZING , SI_FROSTMISTY , SCB_NONE ); + add_sc( RA_MAGENTATRAP , SC_ARMOR_PROPERTY ); + add_sc( RA_COBALTTRAP , SC_ARMOR_PROPERTY ); + add_sc( RA_MAIZETRAP , SC_ARMOR_PROPERTY ); + add_sc( RA_VERDURETRAP , SC_ARMOR_PROPERTY ); + add_sc( RA_FIRINGTRAP , SC_BURNING ); + add_sc( RA_ICEBOUNDTRAP , SC_FROSTMISTY ); + set_sc( RA_UNLIMIT , SC_UNLIMIT , SI_UNLIMIT , SCB_NONE ); /** * Mechanic **/ @@ -609,7 +620,7 @@ void initChangeTables(void) { /** * Royal Guard **/ - set_sc( LG_REFLECTDAMAGE , SC_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); + set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP|SCB_DEF ); set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE ); set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF ); @@ -619,6 +630,7 @@ void initChangeTables(void) { set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK); set_sc( LG_SHIELDSPELL , SC_SHIELDSPELL_DEF , SI_SHIELDSPELL_DEF , SCB_WATK ); set_sc( LG_SHIELDSPELL , SC_SHIELDSPELL_REF , SI_SHIELDSPELL_REF , SCB_DEF ); + set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE ); /** * Shadow Chaser **/ @@ -634,7 +646,7 @@ void initChangeTables(void) { set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE ); set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 ); set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP ); - set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); + set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); add_sc( SC_CHAOSPANIC , SC_CONFUSION ); set_sc_with_vfx( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF | SCB_DEF2 | SCB_MDEF | SCB_MDEF2 | SCB_FLEE | SCB_SPEED | SCB_ASPD | SCB_MAXHP | SCB_REGEN ); @@ -647,30 +659,32 @@ void initChangeTables(void) { set_sc_with_vfx( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP ); - set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GT_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); - set_sc( SR_GENTLETOUCH_CHANGE , SC_GT_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP ); - set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GT_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_REGEN ); + set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); + set_sc( SR_GENTLETOUCH_CHANGE , SC_GENTLETOUCH_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP ); + set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GENTLETOUCH_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_REGEN ); /** * Wanderer / Minstrel **/ - set_sc( WA_SWING_DANCE , SC_SWINGDANCE , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); - set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONYOFLOVER , SI_SYMPHONYOFLOVERS , SCB_MDEF ); - set_sc( WA_MOONLIT_SERENADE , SC_MOONLITSERENADE , SI_MOONLITSERENADE , SCB_MATK ); - set_sc( MI_RUSH_WINDMILL , SC_RUSHWINDMILL , SI_RUSHWINDMILL , SCB_BATK ); - set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); - set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); - set_sc_with_vfx( WM_POEMOFNETHERWORLD , SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE ); - set_sc_with_vfx( WM_VOICEOFSIREN , SC_VOICEOFSIREN , SI_VOICEOFSIREN , SCB_NONE ); - set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE ); - set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); - set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD ); - set_sc( WM_SONG_OF_MANA , SC_SONGOFMANA , SI_SONGOFMANA , SCB_NONE ); - set_sc( WM_DANCE_WITH_WUG , SC_DANCEWITHWUG , SI_DANCEWITHWUG , SCB_ASPD ); - set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAYNIGHTFEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); - set_sc( WM_LERADS_DEW , SC_LERADSDEW , SI_LERADSDEW , SCB_MAXHP ); - set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_BATK|SCB_MATK ); - set_sc( WM_BEYOND_OF_WARCRY , SC_BEYONDOFWARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK ); - set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITEDHUMMINGVOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); + set_sc( WA_SWING_DANCE , SC_SWING , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD ); + set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SI_SYMPHONYOFLOVERS , SCB_MDEF ); + set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SI_MOONLITSERENADE , SCB_MATK ); + set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_BATK ); + set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 ); + set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + set_sc_with_vfx( WM_POEMOFNETHERWORLD , SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE ); + set_sc_with_vfx( WM_VOICEOFSIREN , SC_SIREN , SI_SIREN , SCB_NONE ); + set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); + set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE ); + set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD ); + set_sc( WM_SONG_OF_MANA , SC_SONG_OF_MANA , SI_SONG_OF_MANA , SCB_NONE ); + set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SI_DANCEWITHWUG , SCB_ASPD ); + set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN ); + set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SI_LERADSDEW , SCB_MAXHP ); + set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_BATK|SCB_MATK ); + set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK ); + set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE ); + set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SI_FRIGG_SONG , SCB_MAXHP ); + /** * Sorcerer **/ @@ -682,7 +696,7 @@ void initChangeTables(void) { set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI ); set_sc( SO_WARMER , SC_WARMER , SI_WARMER , SCB_NONE ); set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); - set_sc( SO_ARRULLO , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE ); + set_sc( SO_ARRULLO , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE ); set_sc( SO_FIRE_INSIGNIA , SC_FIRE_INSIGNIA , SI_FIRE_INSIGNIA , SCB_MATK | SCB_BATK | SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SI_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SI_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN ); @@ -691,11 +705,11 @@ void initChangeTables(void) { * Genetic **/ set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED ); - set_sc( GN_THORNS_TRAP , SC_THORNSTRAP , SI_THORNTRAP , SCB_NONE ); - set_sc_with_vfx( GN_BLOOD_SUCKER , SC_BLOODSUCKER , SI_BLOODSUCKER , SCB_NONE ); + set_sc( GN_THORNS_TRAP , SC_THORNS_TRAP , SI_THORNTRAP , SCB_NONE ); + set_sc_with_vfx( GN_BLOOD_SUCKER , SC_BLOOD_SUCKER , SI_BLOODSUCKER , SCB_NONE ); set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE ); - set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_SMOKEPOWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE ); - set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_TEARGAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); + set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_FIRE_EXPANSION_SMOKE_POWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE ); + set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT ); // Elemental Spirit summoner's 'side' status changes. @@ -727,7 +741,7 @@ void initChangeTables(void) { set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SI_ROCK_CRUSHER_ATK , SCB_SPEED ); add_sc( KO_YAMIKUMO , SC_HIDING ); - set_sc_with_vfx( KO_JYUMONJIKIRI , SC_JYUMONJIKIRI , SI_KO_JYUMONJIKIRI , SCB_NONE ); + set_sc_with_vfx( KO_JYUMONJIKIRI , SC_KO_JYUMONJIKIRI , SI_KO_JYUMONJIKIRI , SCB_NONE ); add_sc( KO_MAKIBISHI , SC_STUN ); set_sc( KO_MEIKYOUSISUI , SC_MEIKYOUSISUI , SI_MEIKYOUSISUI , SCB_NONE ); set_sc( KO_KYOUGAKU , SC_KYOUGAKU , SI_KYOUGAKU , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); @@ -736,12 +750,14 @@ void initChangeTables(void) { set_sc( KO_IZAYOI , SC_IZAYOI , SI_IZAYOI , SCB_MATK ); set_sc( KG_KYOMU , SC_KYOMU , SI_KYOMU , SCB_NONE ); set_sc( KG_KAGEMUSYA , SC_KAGEMUSYA , SI_KAGEMUSYA , SCB_NONE ); - set_sc( KG_KAGEHUMI , SC_KAGEHUMI , SI_KG_KAGEHUMI , SCB_NONE ); + set_sc( KG_KAGEHUMI , SC_KG_KAGEHUMI , SI_KG_KAGEHUMI , SCB_NONE ); set_sc( OB_ZANGETSU , SC_ZANGETSU , SI_ZANGETSU , SCB_MATK|SCB_BATK ); set_sc_with_vfx( OB_AKAITSUKI , SC_AKAITSUKI , SI_AKAITSUKI , SCB_NONE ); set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE ); - // Storing the target job rather than simply SC_SPIRIT simplifies code later on. + set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK ); + + // Storing the target job rather than simply SC_SOULLINK simplifies code later on. SkillStatusChangeTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST, SkillStatusChangeTable[SL_MONK] = (sc_type)MAPID_MONK, SkillStatusChangeTable[SL_STAR] = (sc_type)MAPID_STAR_GLADIATOR, @@ -759,33 +775,33 @@ void initChangeTables(void) { SkillStatusChangeTable[SL_SOULLINKER] = (sc_type)MAPID_SOUL_LINKER, //Status that don't have a skill associated. - StatusIconChangeTable[SC_WEIGHT50] = SI_WEIGHT50; - StatusIconChangeTable[SC_WEIGHT90] = SI_WEIGHT90; - StatusIconChangeTable[SC_ASPDPOTION0] = SI_ASPDPOTION0; - StatusIconChangeTable[SC_ASPDPOTION1] = SI_ASPDPOTION1; - StatusIconChangeTable[SC_ASPDPOTION2] = SI_ASPDPOTION2; - StatusIconChangeTable[SC_ASPDPOTION3] = SI_ASPDPOTIONINFINITY; - StatusIconChangeTable[SC_SPEEDUP0] = SI_MOVHASTE_HORSE; - StatusIconChangeTable[SC_SPEEDUP1] = SI_SPEEDPOTION1; - StatusIconChangeTable[SC_INCSTR] = SI_INCSTR; - StatusIconChangeTable[SC_MIRACLE] = SI_SPIRIT; - StatusIconChangeTable[SC_INTRAVISION] = SI_INTRAVISION; - StatusIconChangeTable[SC_STRFOOD] = SI_FOODSTR; - StatusIconChangeTable[SC_AGIFOOD] = SI_FOODAGI; - StatusIconChangeTable[SC_VITFOOD] = SI_FOODVIT; - StatusIconChangeTable[SC_INTFOOD] = SI_FOODINT; - StatusIconChangeTable[SC_DEXFOOD] = SI_FOODDEX; - StatusIconChangeTable[SC_LUKFOOD] = SI_FOODLUK; - StatusIconChangeTable[SC_FLEEFOOD]= SI_FOODFLEE; - StatusIconChangeTable[SC_HITFOOD] = SI_FOODHIT; + StatusIconChangeTable[SC_WEIGHTOVER50] = SI_WEIGHTOVER50; + StatusIconChangeTable[SC_WEIGHTOVER90] = SI_WEIGHTOVER90; + StatusIconChangeTable[SC_ATTHASTE_POTION1] = SI_ATTHASTE_POTION1; + StatusIconChangeTable[SC_ATTHASTE_POTION2] = SI_ATTHASTE_POTION2; + StatusIconChangeTable[SC_ATTHASTE_POTION3] = SI_ATTHASTE_POTION3; + StatusIconChangeTable[SC_ATTHASTE_INFINITY] = SI_ATTHASTE_INFINITY; + StatusIconChangeTable[SC_MOVHASTE_HORSE] = SI_MOVHASTE_HORSE; + StatusIconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY; + StatusIconChangeTable[SC_CHASEWALK2] = SI_INCSTR; + StatusIconChangeTable[SC_MIRACLE] = SI_SOULLINK; + StatusIconChangeTable[SC_CLAIRVOYANCE] = SI_CLAIRVOYANCE; + StatusIconChangeTable[SC_FOOD_STR] = SI_FOOD_STR; + StatusIconChangeTable[SC_FOOD_AGI] = SI_FOOD_AGI; + StatusIconChangeTable[SC_FOOD_VIT] = SI_FOOD_VIT; + StatusIconChangeTable[SC_FOOD_INT] = SI_FOOD_INT; + StatusIconChangeTable[SC_FOOD_DEX] = SI_FOOD_DEX; + StatusIconChangeTable[SC_FOOD_LUK] = SI_FOOD_LUK; + StatusIconChangeTable[SC_FOOD_BASICAVOIDANCE]= SI_FOOD_BASICAVOIDANCE; + StatusIconChangeTable[SC_FOOD_BASICHIT] = SI_FOOD_BASICHIT; StatusIconChangeTable[SC_MANU_ATK] = SI_MANU_ATK; StatusIconChangeTable[SC_MANU_DEF] = SI_MANU_DEF; StatusIconChangeTable[SC_SPL_ATK] = SI_SPL_ATK; StatusIconChangeTable[SC_SPL_DEF] = SI_SPL_DEF; StatusIconChangeTable[SC_MANU_MATK] = SI_MANU_MATK; StatusIconChangeTable[SC_SPL_MATK] = SI_SPL_MATK; - StatusIconChangeTable[SC_ATKPOTION] = SI_PLUSATTACKPOWER; - StatusIconChangeTable[SC_MATKPOTION] = SI_PLUSMAGICPOWER; + StatusIconChangeTable[SC_PLUSATTACKPOWER] = SI_PLUSATTACKPOWER; + StatusIconChangeTable[SC_PLUSMAGICPOWER] = SI_PLUSMAGICPOWER; //Cash Items StatusIconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH; StatusIconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH; @@ -793,32 +809,32 @@ void initChangeTables(void) { StatusIconChangeTable[SC_FOOD_DEX_CASH] = SI_FOOD_DEX_CASH; StatusIconChangeTable[SC_FOOD_INT_CASH] = SI_FOOD_INT_CASH; StatusIconChangeTable[SC_FOOD_LUK_CASH] = SI_FOOD_LUK_CASH; - StatusIconChangeTable[SC_EXPBOOST] = SI_EXPBOOST; - StatusIconChangeTable[SC_ITEMBOOST] = SI_ITEMBOOST; - StatusIconChangeTable[SC_JEXPBOOST] = SI_CASH_PLUSONLYJOBEXP; - StatusIconChangeTable[SC_LIFEINSURANCE] = SI_LIFEINSURANCE; - StatusIconChangeTable[SC_BOSSMAPINFO] = SI_BOSSMAPINFO; - StatusIconChangeTable[SC_DEF_RATE] = SI_DEF_RATE; - StatusIconChangeTable[SC_MDEF_RATE] = SI_MDEF_RATE; - StatusIconChangeTable[SC_INCCRI] = SI_INCCRI; - StatusIconChangeTable[SC_INCFLEE2] = SI_PLUSAVOIDVALUE; - StatusIconChangeTable[SC_INCHEALRATE] = SI_INCHEALRATE; + StatusIconChangeTable[SC_CASH_PLUSEXP] = SI_CASH_PLUSEXP; + StatusIconChangeTable[SC_CASH_RECEIVEITEM] = SI_CASH_RECEIVEITEM; + StatusIconChangeTable[SC_CASH_PLUSONLYJOBEXP] = SI_CASH_PLUSONLYJOBEXP; + StatusIconChangeTable[SC_CASH_DEATHPENALTY] = SI_CASH_DEATHPENALTY; + StatusIconChangeTable[SC_CASH_BOSS_ALARM] = SI_CASH_BOSS_ALARM; + StatusIconChangeTable[SC_PROTECT_DEF] = SI_PROTECT_DEF; + StatusIconChangeTable[SC_PROTECT_MDEF] = SI_PROTECT_MDEF; + StatusIconChangeTable[SC_CRITICALPERCENT] = SI_CRITICALPERCENT; + StatusIconChangeTable[SC_PLUSAVOIDVALUE] = SI_PLUSAVOIDVALUE; + StatusIconChangeTable[SC_HEALPLUS] = SI_HEALPLUS; StatusIconChangeTable[SC_S_LIFEPOTION] = SI_S_LIFEPOTION; StatusIconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION; - StatusIconChangeTable[SC_SPCOST_RATE] = SI_ATKER_BLOOD; - StatusIconChangeTable[SC_COMMONSC_RESIST] = SI_TARGET_BLOOD; + StatusIconChangeTable[SC_ATKER_BLOOD] = SI_ATKER_BLOOD; + StatusIconChangeTable[SC_TARGET_BLOOD] = SI_TARGET_BLOOD; // Mercenary Bonus Effects - StatusIconChangeTable[SC_MERC_FLEEUP] = SI_MERC_FLEEUP; - StatusIconChangeTable[SC_MERC_ATKUP] = SI_MERC_ATKUP; - StatusIconChangeTable[SC_MERC_HPUP] = SI_MERC_HPUP; - StatusIconChangeTable[SC_MERC_SPUP] = SI_MERC_SPUP; - StatusIconChangeTable[SC_MERC_HITUP] = SI_MERC_HITUP; + StatusIconChangeTable[SC_MER_FLEE] = SI_MER_FLEE; + StatusIconChangeTable[SC_MER_ATK] = SI_MER_ATK; + StatusIconChangeTable[SC_MER_HP] = SI_MER_HP; + StatusIconChangeTable[SC_MER_SP] = SI_MER_SP; + StatusIconChangeTable[SC_MER_HIT] = SI_MER_HIT; // Warlock Spheres - StatusIconChangeTable[SC_SPHERE_1] = SI_SPHERE_1; - StatusIconChangeTable[SC_SPHERE_2] = SI_SPHERE_2; - StatusIconChangeTable[SC_SPHERE_3] = SI_SPHERE_3; - StatusIconChangeTable[SC_SPHERE_4] = SI_SPHERE_4; - StatusIconChangeTable[SC_SPHERE_5] = SI_SPHERE_5; + StatusIconChangeTable[SC_SUMMON1] = SI_SPHERE_1; + StatusIconChangeTable[SC_SUMMON2] = SI_SPHERE_2; + StatusIconChangeTable[SC_SUMMON3] = SI_SPHERE_3; + StatusIconChangeTable[SC_SUMMON4] = SI_SPHERE_4; + StatusIconChangeTable[SC_SUMMON5] = SI_SPHERE_5; // Warlock Preserved spells StatusIconChangeTable[SC_SPELLBOOK1] = SI_SPELLBOOK1; StatusIconChangeTable[SC_SPELLBOOK2] = SI_SPELLBOOK2; @@ -826,7 +842,7 @@ void initChangeTables(void) { StatusIconChangeTable[SC_SPELLBOOK4] = SI_SPELLBOOK4; StatusIconChangeTable[SC_SPELLBOOK5] = SI_SPELLBOOK5; StatusIconChangeTable[SC_SPELLBOOK6] = SI_SPELLBOOK6; - StatusIconChangeTable[SC_MAXSPELLBOOK] = SI_SPELLBOOK7; + StatusIconChangeTable[SC_SPELLBOOK7] = SI_SPELLBOOK7; StatusIconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER; StatusIconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER; @@ -856,7 +872,7 @@ void initChangeTables(void) { StatusIconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER; StatusIconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB; StatusIconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB; - StatusIconChangeTable[SC_BANANA_BOMB_SITDOWN] = SI_BANANA_BOMB_SITDOWN_POSTDELAY; + StatusIconChangeTable[SC_BANANA_BOMB_SITDOWN_POSTDELAY] = SI_BANANA_BOMB_SITDOWN_POSTDELAY; //Genetics New Food Items Status Icons StatusIconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK; @@ -897,19 +913,20 @@ void initChangeTables(void) { StatusIconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL; StatusIconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL; StatusIconChangeTable[SC_PUSH_CART] = SI_ON_PUSH_CART; + StatusIconChangeTable[SC_REBOUND] = SI_REBOUND; StatusIconChangeTable[SC_ALL_RIDING] = SI_ALL_RIDING; //Other SC which are not necessarily associated to skills. - StatusChangeFlagTable[SC_ASPDPOTION0] = SCB_ASPD; - StatusChangeFlagTable[SC_ASPDPOTION1] = SCB_ASPD; - StatusChangeFlagTable[SC_ASPDPOTION2] = SCB_ASPD; - StatusChangeFlagTable[SC_ASPDPOTION3] = SCB_ASPD; - StatusChangeFlagTable[SC_SPEEDUP0] = SCB_SPEED; - StatusChangeFlagTable[SC_SPEEDUP1] = SCB_SPEED; - StatusChangeFlagTable[SC_ATKPOTION] = SCB_BATK; - StatusChangeFlagTable[SC_MATKPOTION] = SCB_MATK; + StatusChangeFlagTable[SC_ATTHASTE_POTION1] = SCB_ASPD; + StatusChangeFlagTable[SC_ATTHASTE_POTION2] = SCB_ASPD; + StatusChangeFlagTable[SC_ATTHASTE_POTION3] = SCB_ASPD; + StatusChangeFlagTable[SC_ATTHASTE_INFINITY] = SCB_ASPD; + StatusChangeFlagTable[SC_MOVHASTE_HORSE] = SCB_SPEED; + StatusChangeFlagTable[SC_MOVHASTE_INFINITY] = SCB_SPEED; + StatusChangeFlagTable[SC_PLUSATTACKPOWER] = SCB_BATK; + StatusChangeFlagTable[SC_PLUSMAGICPOWER] = SCB_MATK; StatusChangeFlagTable[SC_INCALLSTATUS] |= SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK; - StatusChangeFlagTable[SC_INCSTR] |= SCB_STR; + StatusChangeFlagTable[SC_CHASEWALK2] |= SCB_STR; StatusChangeFlagTable[SC_INCAGI] |= SCB_AGI; StatusChangeFlagTable[SC_INCVIT] |= SCB_VIT; StatusChangeFlagTable[SC_INCINT] |= SCB_INT; @@ -919,9 +936,9 @@ void initChangeTables(void) { StatusChangeFlagTable[SC_INCHITRATE] |= SCB_HIT; StatusChangeFlagTable[SC_INCFLEE] |= SCB_FLEE; StatusChangeFlagTable[SC_INCFLEERATE] |= SCB_FLEE; - StatusChangeFlagTable[SC_INCCRI] |= SCB_CRI; + StatusChangeFlagTable[SC_CRITICALPERCENT] |= SCB_CRI; StatusChangeFlagTable[SC_INCASPDRATE] |= SCB_ASPD; - StatusChangeFlagTable[SC_INCFLEE2] |= SCB_FLEE2; + StatusChangeFlagTable[SC_PLUSAVOIDVALUE] |= SCB_FLEE2; StatusChangeFlagTable[SC_INCMHPRATE] |= SCB_MAXHP; StatusChangeFlagTable[SC_INCMSPRATE] |= SCB_MAXSP; StatusChangeFlagTable[SC_INCMHP] |= SCB_MAXHP; @@ -929,20 +946,20 @@ void initChangeTables(void) { StatusChangeFlagTable[SC_INCATKRATE] |= SCB_BATK|SCB_WATK; StatusChangeFlagTable[SC_INCMATKRATE] |= SCB_MATK; StatusChangeFlagTable[SC_INCDEFRATE] |= SCB_DEF; - StatusChangeFlagTable[SC_STRFOOD] |= SCB_STR; - StatusChangeFlagTable[SC_AGIFOOD] |= SCB_AGI; - StatusChangeFlagTable[SC_VITFOOD] |= SCB_VIT; - StatusChangeFlagTable[SC_INTFOOD] |= SCB_INT; - StatusChangeFlagTable[SC_DEXFOOD] |= SCB_DEX; - StatusChangeFlagTable[SC_LUKFOOD] |= SCB_LUK; - StatusChangeFlagTable[SC_HITFOOD] |= SCB_HIT; - StatusChangeFlagTable[SC_FLEEFOOD] |= SCB_FLEE; + StatusChangeFlagTable[SC_FOOD_STR] |= SCB_STR; + StatusChangeFlagTable[SC_FOOD_AGI] |= SCB_AGI; + StatusChangeFlagTable[SC_FOOD_VIT] |= SCB_VIT; + StatusChangeFlagTable[SC_FOOD_INT] |= SCB_INT; + StatusChangeFlagTable[SC_FOOD_DEX] |= SCB_DEX; + StatusChangeFlagTable[SC_FOOD_LUK] |= SCB_LUK; + StatusChangeFlagTable[SC_FOOD_BASICHIT] |= SCB_HIT; + StatusChangeFlagTable[SC_FOOD_BASICAVOIDANCE] |= SCB_FLEE; StatusChangeFlagTable[SC_BATKFOOD] |= SCB_BATK; StatusChangeFlagTable[SC_WATKFOOD] |= SCB_WATK; StatusChangeFlagTable[SC_MATKFOOD] |= SCB_MATK; - StatusChangeFlagTable[SC_ARMOR_ELEMENT] |= SCB_ALL; + StatusChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL; StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; - StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL; + StatusChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL; // Cash Items @@ -953,11 +970,11 @@ void initChangeTables(void) { StatusChangeFlagTable[SC_FOOD_INT_CASH] = SCB_INT; StatusChangeFlagTable[SC_FOOD_LUK_CASH] = SCB_LUK; // Mercenary Bonus Effects - StatusChangeFlagTable[SC_MERC_FLEEUP] |= SCB_FLEE; - StatusChangeFlagTable[SC_MERC_ATKUP] |= SCB_WATK; - StatusChangeFlagTable[SC_MERC_HPUP] |= SCB_MAXHP; - StatusChangeFlagTable[SC_MERC_SPUP] |= SCB_MAXSP; - StatusChangeFlagTable[SC_MERC_HITUP] |= SCB_HIT; + StatusChangeFlagTable[SC_MER_FLEE] |= SCB_FLEE; + StatusChangeFlagTable[SC_MER_ATK] |= SCB_WATK; + StatusChangeFlagTable[SC_MER_HP] |= SCB_MAXHP; + StatusChangeFlagTable[SC_MER_SP] |= SCB_MAXSP; + StatusChangeFlagTable[SC_MER_HIT] |= SCB_HIT; // Guillotine Cross Poison Effects StatusChangeFlagTable[SC_PARALYSE] |= SCB_ASPD|SCB_FLEE|SCB_SPEED; StatusChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN; @@ -978,30 +995,31 @@ void initChangeTables(void) { StatusChangeFlagTable[SC_EXTRACT_WHITE_POTION_Z] |= SCB_REGEN; StatusChangeFlagTable[SC_VITATA_500] |= SCB_REGEN; StatusChangeFlagTable[SC_EXTRACT_SALAMINE_JUICE] |= SCB_ASPD; + StatusChangeFlagTable[SC_REBOUND] |= SCB_SPEED|SCB_REGEN; StatusChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; /* StatusDisplayType Table [Ind/Hercules] */ StatusDisplayType[SC_ALL_RIDING] = true; StatusDisplayType[SC_PUSH_CART] = true; - StatusDisplayType[SC_SPHERE_1] = true; - StatusDisplayType[SC_SPHERE_2] = true; - StatusDisplayType[SC_SPHERE_3] = true; - StatusDisplayType[SC_SPHERE_4] = true; - StatusDisplayType[SC_SPHERE_5] = true; + StatusDisplayType[SC_SUMMON1] = true; + StatusDisplayType[SC_SUMMON2] = true; + StatusDisplayType[SC_SUMMON3] = true; + StatusDisplayType[SC_SUMMON4] = true; + StatusDisplayType[SC_SUMMON5] = true; StatusDisplayType[SC_CAMOUFLAGE] = true; StatusDisplayType[SC_DUPLELIGHT] = true; StatusDisplayType[SC_ORATIO] = true; - StatusDisplayType[SC_FREEZING] = true; + StatusDisplayType[SC_FROSTMISTY] = true; StatusDisplayType[SC_VENOMIMPRESS] = true; StatusDisplayType[SC_HALLUCINATIONWALK] = true; StatusDisplayType[SC_ROLLINGCUTTER] = true; StatusDisplayType[SC_BANDING] = true; StatusDisplayType[SC_CRYSTALIZE] = true; - StatusDisplayType[SC_DEEPSLEEP] = true; + StatusDisplayType[SC_DEEP_SLEEP] = true; StatusDisplayType[SC_CURSEDCIRCLE_ATKER]= true; StatusDisplayType[SC_CURSEDCIRCLE_TARGET]= true; - StatusDisplayType[SC_BLOODSUCKER] = true; + StatusDisplayType[SC_BLOOD_SUCKER] = true; StatusDisplayType[SC__SHADOWFORM] = true; StatusDisplayType[SC__MANHOLE] = true; @@ -1011,7 +1029,7 @@ void initChangeTables(void) { #endif if( !battle_config.display_hallucination ) //Disable Hallucination. - StatusIconChangeTable[SC_HALLUCINATION] = SI_BLANK; + StatusIconChangeTable[SC_ILLUSION] = SI_BLANK; } static void initDummyData(void) @@ -1147,7 +1165,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_STONE, INVALID_TIMER); status_change_end(target, SC_FREEZE, INVALID_TIMER); status_change_end(target, SC_SLEEP, INVALID_TIMER); - status_change_end(target, SC_WINKCHARM, INVALID_TIMER); + status_change_end(target, SC_DC_WINKCHARM, INVALID_TIMER); status_change_end(target, SC_CONFUSION, INVALID_TIMER); status_change_end(target, SC_TRICKDEAD, INVALID_TIMER); status_change_end(target, SC_HIDING, INVALID_TIMER); @@ -1155,8 +1173,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); status_change_end(target, SC__INVISIBILITY, INVALID_TIMER); - status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER); - if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { + status_change_end(target, SC_DEEP_SLEEP, INVALID_TIMER); + if ((sce=sc->data[SC_ENDURE]) && !sce->val4 && !sc->data[SC_LKCONCENTRATION]) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] if (src && src->type != BL_PC && !map_flag_gvg(target->m) && !map[target->m].flag.battleground && --(sce->val2) < 0) @@ -1192,8 +1210,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_BERSERK, INVALID_TIMER); if( sc->data[SC_RAISINGDRAGON] && status->hp <= 1000 ) status_change_end(target, SC_RAISINGDRAGON, INVALID_TIMER); - if (sc->data[SC_SATURDAYNIGHTFEVER] && status->hp <= 100) - status_change_end(target, SC_SATURDAYNIGHTFEVER, INVALID_TIMER); + if (sc->data[SC_SATURDAY_NIGHT_FEVER] && status->hp <= 100) + status_change_end(target, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); if (sc->data[SC__BLOODYLUST] && status->hp <= 100) status_change_end(target, SC__BLOODYLUST, INVALID_TIMER); } @@ -1576,9 +1594,9 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin ) return 0; - if (sc->data[SC_WINKCHARM] && target && !flag) { //Prevents skill usage + if (sc->data[SC_DC_WINKCHARM] && target && !flag) { //Prevents skill usage if( unit_bl2ud(src) && (unit_bl2ud(src))->walktimer == INVALID_TIMER ) - unit_walktobl(src, iMap->id2bl(sc->data[SC_WINKCHARM]->val2), 3, 1); + unit_walktobl(src, iMap->id2bl(sc->data[SC_DC_WINKCHARM]->val2), 3, 1); clif->emotion(src, E_LV); return 0; } @@ -1632,13 +1650,13 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin sc->data[SC__INVISIBILITY] || (sc->data[SC_CRYSTALIZE] && src->type != BL_MOB) || sc->data[SC__IGNORANCE] || - sc->data[SC_DEEPSLEEP] || - sc->data[SC_SATURDAYNIGHTFEVER] || + sc->data[SC_DEEP_SLEEP] || + sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC_CURSEDCIRCLE_TARGET] || - (sc->data[SC_MARIONETTE] && skill_id != CG_MARIONETTE) || //Only skill you can use is marionette again to cancel it - (sc->data[SC_MARIONETTE2] && skill_id == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another + (sc->data[SC_MARIONETTE_MASTER] && skill_id != CG_MARIONETTE) || //Only skill you can use is marionette again to cancel it + (sc->data[SC_MARIONETTE] && skill_id == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another (sc->data[SC_STASIS] && skill->block_check(src, SC_STASIS, skill_id)) || - (sc->data[SC_KAGEHUMI] && skill->block_check(src, SC_KAGEHUMI, skill_id)) + (sc->data[SC_KG_KAGEHUMI] && skill->block_check(src, SC_KG_KAGEHUMI, skill_id)) )) return 0; @@ -1882,17 +1900,18 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct str += dstr*dstr; if (bl->type == BL_PC) #ifdef RENEWAL - str = (rstr*10 + dex*10/5 + status->luk*10/3 + ((TBL_PC*)bl)->status.base_level*10/4)/10; + str = (int)(rstr + (float)dex/5 + (float)status->luk/3 + (float)((TBL_PC*)bl)->status.base_level/4); + else if(bl->type == BL_MOB) + str = rstr + ((TBL_MOB*)bl)->level; #else str+= dex/5 + status->luk/5; #endif return cap_value(str, 0, USHRT_MAX); } -#ifndef RENEWAL static inline unsigned short status_base_matk_min(const struct status_data* status){ return status->int_+(status->int_/7)*(status->int_/7); } static inline unsigned short status_base_matk_max(const struct status_data* status){ return status->int_+(status->int_/5)*(status->int_/5); } -#else +#ifdef RENEWAL unsigned short status_base_matk(const struct status_data* status, int level){ return status->int_+(status->int_/2)+(status->dex/5)+(status->luk/3)+(level/4); } #endif @@ -1907,11 +1926,11 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev status->cri = status->flee2 = 0; #ifdef RENEWAL // renewal formulas - status->matk_min = status->matk_max = status_base_matk(status, level); - status->hit += level + status->dex + status->luk/3 + 175; //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175 - status->flee += level + status->agi + status->luk/5 + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 - status->def2 += (int)(((float)level + status->vit)/2 + ((float)status->agi/5)); //base level + (every 2 vit = +1 def) + (every 5 agi = +1 def) - status->mdef2 += (int)(status->int_ + ((float)level/4) + ((float)status->dex/5) + ((float)status->vit/5)); //(every 4 base level = +1 mdef) + (every 1 int = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef) + status->matk_min = status->matk_max = bl->type == BL_PC ? status_base_matk(status, level) : level + status->int_; + status->hit += level + status->dex + (bl->type == BL_PC ? status->luk/3 + 175 : 150); //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175 + status->flee += level + status->agi + (bl->type == BL_PC ? status->luk/5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 + status->def2 += (int)(((float)level + status->vit)/2 + ( bl->type == BL_PC ? ((float)status->agi/5) : 0 )); //base level + (every 2 vit = +1 def) + (every 5 agi = +1 def) + status->mdef2 += (int)( bl->type == BL_PC ?(status->int_ + ((float)level/4) + ((float)(status->dex+status->vit)/5)):((float)(status->int_ + level)/4)); //(every 4 base level = +1 mdef) + (every 1 int = +1 mdef) + (every 5 dex = +1 mdef) + (every 5 vit = +1 mdef) #else status->matk_min = status_base_matk_min(status); status->matk_max = status_base_matk_max(status); @@ -1947,6 +1966,13 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev case BL_PC: //Players don't have a critical adjustment setting as of yet. break; + case BL_MER: +#ifdef RENEWAL + status->matk_min = status->matk_max = status_base_matk_max(status); + status->def2 = status->vit + level / 10 + status->vit / 5; + status->mdef2 = level / 10 + status->int_ / 5; +#endif + break; default: if(battle_config.critical_rate != 100) status->cri = status->cri*battle_config.critical_rate/100; @@ -2030,7 +2056,7 @@ int status_calc_mob_(struct mob_data* md, bool first) if (ud->skill_id == AM_SPHEREMINE) { status->max_hp = 2000 + 400*ud->skill_lv; } else if(ud->skill_id == KO_ZANZOU){ - status->max_hp = 3000 + 3000 * ud->skill_lv; + status->max_hp = 3000 + 3000 * ud->skill_lv + status_get_max_sp(battle->get_master(mbl)); } else { //AM_CANNIBALIZE status->max_hp = 1500 + 200*ud->skill_lv + 10*status_get_lv(mbl); status->mode|= MD_CANATTACK|MD_AGGRESSIVE; @@ -2352,8 +2378,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) memset (&sd->right_weapon.overrefine, 0, sizeof(sd->right_weapon) - sizeof(sd->right_weapon.atkmods)); memset (&sd->left_weapon.overrefine, 0, sizeof(sd->left_weapon) - sizeof(sd->left_weapon.atkmods)); - if (sd->special_state.intravision && !sd->sc.data[SC_INTRAVISION]) //Clear intravision as long as nothing else is using it - clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_INTRAVISION); + if (sd->special_state.intravision && !sd->sc.data[SC_CLAIRVOYANCE]) //Clear intravision as long as nothing else is using it + clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_CLAIRVOYANCE); memset(&sd->special_state,0,sizeof(sd->special_state)); memset(&status->max_hp, 0, sizeof(struct status_data)-(sizeof(status->hp)+sizeof(status->sp))); @@ -2365,7 +2391,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); status->size = (sd->class_&JOBL_BABY)?SZ_SMALL:SZ_MEDIUM; - if (battle_config.character_size && pc_isriding(sd)) { //[Lupus] + if (battle_config.character_size && (pc_isriding(sd) || pc_isridingdragon(sd)) ) { //[Lupus] if (sd->class_&JOBL_BABY) { if (battle_config.character_size&SZ_BIG) status->size++; @@ -2638,7 +2664,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->left_weapon.atkmods[1] = atkmods[1][sd->weapontype2]; sd->left_weapon.atkmods[2] = atkmods[2][sd->weapontype2]; - if(pc_isriding(sd) && + if( (pc_isriding(sd) || pc_isridingdragon(sd)) && (sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR)) { //When Riding with spear, damage modifier to mid-class becomes //same as versus large size. @@ -2704,8 +2730,10 @@ int status_calc_pc_(struct map_session_data* sd, bool first) if (sd->status.weapon < MAX_WEAPON_TYPE && sd->weapon_atk[sd->status.weapon]) status->batk += sd->weapon_atk[sd->status.weapon]; // Absolute modifiers from passive skills - if((skill=pc->checkskill(sd,BS_HILTBINDING))>0) +#ifndef RENEWAL + if((skill=pc->checkskill(sd,BS_HILTBINDING))>0) // it doesn't work in RE. status->batk += 4; +#endif // ----- HP MAX CALCULATION ----- @@ -2964,11 +2992,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) if((skill=pc->checkskill(sd,HP_MANARECHARGE))>0 ) sd->dsprate -= 4*skill; - if(sc->data[SC_SERVICE4U]) - sd->dsprate -= sc->data[SC_SERVICE4U]->val3; + if(sc->data[SC_SERVICEFORYOU]) + sd->dsprate -= sc->data[SC_SERVICEFORYOU]->val3; - if(sc->data[SC_SPCOST_RATE]) - sd->dsprate -= sc->data[SC_SPCOST_RATE]->val1; + if(sc->data[SC_ATKER_BLOOD]) + sd->dsprate -= sc->data[SC_ATKER_BLOOD]->val1; //Underflow protections. if(sd->dsprate < 0) @@ -3002,9 +3030,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) } if(sc->count){ - if(sc->data[SC_CONCENTRATE]) { //Update the card-bonus data - sc->data[SC_CONCENTRATE]->val3 = sd->param_bonus[1]; //Agi - sc->data[SC_CONCENTRATE]->val4 = sd->param_bonus[4]; //Dex + if(sc->data[SC_CONCENTRATION]) { //Update the card-bonus data + sc->data[SC_CONCENTRATION]->val3 = sd->param_bonus[1]; //Agi + sc->data[SC_CONCENTRATION]->val4 = sd->param_bonus[4]; //Dex } if(sc->data[SC_SIEGFRIED]){ i = sc->data[SC_SIEGFRIED]->val2; @@ -3022,11 +3050,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->subele[ELE_HOLY] += sc->data[SC_PROVIDENCE]->val2; sd->subrace[RC_DEMON] += sc->data[SC_PROVIDENCE]->val2; } - if(sc->data[SC_ARMOR_ELEMENT]) { //This status change should grant card-type elemental resist. - sd->subele[ELE_WATER] += sc->data[SC_ARMOR_ELEMENT]->val1; - sd->subele[ELE_EARTH] += sc->data[SC_ARMOR_ELEMENT]->val2; - sd->subele[ELE_FIRE] += sc->data[SC_ARMOR_ELEMENT]->val3; - sd->subele[ELE_WIND] += sc->data[SC_ARMOR_ELEMENT]->val4; + if(sc->data[SC_ARMORPROPERTY]) { //This status change should grant card-type elemental resist. + sd->subele[ELE_WATER] += sc->data[SC_ARMORPROPERTY]->val1; + sd->subele[ELE_EARTH] += sc->data[SC_ARMORPROPERTY]->val2; + sd->subele[ELE_FIRE] += sc->data[SC_ARMORPROPERTY]->val3; + sd->subele[ELE_WIND] += sc->data[SC_ARMORPROPERTY]->val4; } if(sc->data[SC_ARMOR_RESIST]) { // Undead Scroll sd->subele[ELE_WATER] += sc->data[SC_ARMOR_RESIST]->val1; @@ -3266,17 +3294,13 @@ static unsigned short status_calc_vit(struct block_list *,struct status_change * static unsigned short status_calc_int(struct block_list *,struct status_change *,int); static unsigned short status_calc_dex(struct block_list *,struct status_change *,int); static unsigned short status_calc_luk(struct block_list *,struct status_change *,int); -static unsigned short status_calc_batk(struct block_list *,struct status_change *,int); -static unsigned short status_calc_watk(struct block_list *,struct status_change *,int); -static unsigned short status_calc_matk(struct block_list *,struct status_change *,int); -static signed short status_calc_hit(struct block_list *,struct status_change *,int); -static signed short status_calc_critical(struct block_list *,struct status_change *,int); -static signed short status_calc_flee(struct block_list *,struct status_change *,int); -static signed short status_calc_flee2(struct block_list *,struct status_change *,int); -static defType status_calc_def(struct block_list *bl, struct status_change *sc, int); -static signed short status_calc_def2(struct block_list *,struct status_change *,int); -static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int); -static signed short status_calc_mdef2(struct block_list *,struct status_change *,int); +static unsigned short status_calc_batk(struct block_list *,struct status_change *,int,bool); +static unsigned short status_calc_watk(struct block_list *,struct status_change *,int,bool); +static unsigned short status_calc_matk(struct block_list *,struct status_change *,int,bool); +static signed short status_calc_hit(struct block_list *,struct status_change *,int,bool); +static signed short status_calc_critical(struct block_list *,struct status_change *,int,bool); +static signed short status_calc_flee(struct block_list *,struct status_change *,int,bool); +static signed short status_calc_flee2(struct block_list *,struct status_change *,int,bool); static unsigned short status_calc_speed(struct block_list *,struct status_change *,int); static short status_calc_aspd_rate(struct block_list *,struct status_change *,int); static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion); @@ -3430,18 +3454,18 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) || sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST] || sc->data[SC_TRICKDEAD] - || sc->data[SC_BLEEDING] + || sc->data[SC_BLOODING] || sc->data[SC_MAGICMUSHROOM] || sc->data[SC_RAISINGDRAGON] - || sc->data[SC_SATURDAYNIGHTFEVER] + || sc->data[SC_SATURDAY_NIGHT_FEVER] ) //No regen regen->flag = 0; if ( - sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] + sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] || sc->data[SC_REBOUND] || ( (bl->type == BL_PC && ((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK && - (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SPIRIT] || sc->data[SC_SPIRIT]->val2 != SL_MONK))) + (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SOULLINK] || sc->data[SC_SOULLINK]->val2 != SL_MONK))) ) ) //No natural SP regen regen->flag &=~RGN_SP; @@ -3458,9 +3482,9 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str regen->rate.hp += 1; regen->rate.sp += 1; } - if (sc->data[SC_REGENERATION]) + if (sc->data[SC_GDSKILL_REGENERATION]) { - const struct status_change_entry *sce = sc->data[SC_REGENERATION]; + const struct status_change_entry *sce = sc->data[SC_GDSKILL_REGENERATION]; if (!sce->val4) { regen->rate.hp += sce->val2; @@ -3468,8 +3492,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str } else regen->flag&=~sce->val4; //Remove regen as specified by val4 } - if(sc->data[SC_GT_REVITALIZE]){ - regen->hp = cap_value(regen->hp*sc->data[SC_GT_REVITALIZE]->val3/100, 1, SHRT_MAX); + if(sc->data[SC_GENTLETOUCH_REVITALIZE]){ + regen->hp = cap_value(regen->hp*sc->data[SC_GENTLETOUCH_REVITALIZE]->val3/100, 1, SHRT_MAX); regen->state.walk= 1; } if ((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) //if insignia lvl 1 @@ -3563,23 +3587,22 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) temp += status->batk; status->batk = cap_value(temp, 0, USHRT_MAX); } - status->batk = status_calc_batk(bl, sc, status->batk); + status->batk = status_calc_batk(bl, sc, status->batk, true); } - if(flag&SCB_WATK) { - - status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk); + if(flag&SCB_WATK) { + status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk, true); if (!sd) //Should not affect weapon refine bonus - status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2); + status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2, true); if(b_status->lhw.atk) { if (sd) { sd->state.lr_flag = 1; - status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk); + status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk, true); sd->state.lr_flag = 0; } else { - status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk); - status->lhw.atk2= status_calc_watk(bl, sc, b_status->lhw.atk2); + status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk, true); + status->lhw.atk2 = status_calc_watk(bl, sc, b_status->lhw.atk2, true); } } @@ -3598,13 +3621,13 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) && status->luk == b_status->luk #endif ) - status->hit = status_calc_hit(bl, sc, b_status->hit); + status->hit = status_calc_hit(bl, sc, b_status->hit, true); else status->hit = status_calc_hit(bl, sc, b_status->hit + (status->dex - b_status->dex) #ifdef RENEWAL + (status->luk/3 - b_status->luk/3) #endif - ); + , true); } if(flag&SCB_FLEE) { @@ -3613,18 +3636,18 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) && status->luk == b_status->luk #endif ) - status->flee = status_calc_flee(bl, sc, b_status->flee); + status->flee = status_calc_flee(bl, sc, b_status->flee, true); else status->flee = status_calc_flee(bl, sc, b_status->flee +(status->agi - b_status->agi) #ifdef RENEWAL + (status->luk/5 - b_status->luk/5) #endif - ); + , true); } if(flag&SCB_DEF) { - status->def = status_calc_def(bl, sc, b_status->def); + status->def = status_calc_def(bl, sc, b_status->def, true); if( bl->type&BL_HOM ) status->def += (status->vit/5 - b_status->vit/5); @@ -3636,7 +3659,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) && status->agi == b_status->agi #endif ) - status->def2 = status_calc_def2(bl, sc, b_status->def2); + status->def2 = status_calc_def2(bl, sc, b_status->def2, true); else status->def2 = status_calc_def2(bl, sc, b_status->def2 #ifdef RENEWAL @@ -3644,12 +3667,12 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) #else + (status->vit - b_status->vit) #endif - ); + , true); } if(flag&SCB_MDEF) { - status->mdef = status_calc_mdef(bl, sc, b_status->mdef); + status->mdef = status_calc_mdef(bl, sc, b_status->mdef, true); if( bl->type&BL_HOM ) status->mdef += (status->int_/5 - b_status->int_/5); @@ -3661,7 +3684,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) && status->dex == b_status->dex #endif ) - status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2); + status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2, true); else status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2 +(status->int_ - b_status->int_) #ifdef RENEWAL @@ -3669,7 +3692,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) #else + ((status->vit - b_status->vit)>>1) #endif - ); + , true); } if(flag&SCB_SPEED) { @@ -3693,9 +3716,9 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) if(flag&SCB_CRI && b_status->cri) { if (status->luk == b_status->luk) - status->cri = status_calc_critical(bl, sc, b_status->cri); + status->cri = status_calc_critical(bl, sc, b_status->cri, true); else - status->cri = status_calc_critical(bl, sc, b_status->cri + 3*(status->luk - b_status->luk)); + status->cri = status_calc_critical(bl, sc, b_status->cri + 3*(status->luk - b_status->luk), true); /** * after status_calc_critical so the bonus is applied despite if you have or not a sc bugreport:5240 **/ @@ -3706,9 +3729,9 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) if(flag&SCB_FLEE2 && b_status->flee2) { if (status->luk == b_status->luk) - status->flee2 = status_calc_flee2(bl, sc, b_status->flee2); + status->flee2 = status_calc_flee2(bl, sc, b_status->flee2, true); else - status->flee2 = status_calc_flee2(bl, sc, b_status->flee2 +(status->luk - b_status->luk)); + status->flee2 = status_calc_flee2(bl, sc, b_status->flee2 +(status->luk - b_status->luk), true); } if(flag&SCB_ATK_ELE) { @@ -3784,52 +3807,8 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } } - if(flag&SCB_MATK) { -#ifndef RENEWAL - status->matk_min = status_base_matk_min(status) + (sd?sd->bonus.ematk:0); - status->matk_max = status_base_matk_max(status) + (sd?sd->bonus.ematk:0); -#else - /** - * RE MATK Formula (from irowiki:http://irowiki.org/wiki/MATK) - * MATK = (sMATK + wMATK + eMATK) * Multiplicative Modifiers - **/ - status->matk_min = status->matk_max = status_base_matk(status, status_get_lv(bl)); - if( bl->type&BL_PC ){ - // Any +MATK you get from skills and cards, including cards in weapon, is added here. - if( sd->bonus.ematk > 0 ){ - status->matk_max += sd->bonus.ematk; - status->matk_min += sd->bonus.ematk; - } - status->matk_min = status_calc_ematk(bl, sc, status->matk_min); - status->matk_max = status_calc_ematk(bl, sc, status->matk_max); - //This is the only portion in MATK that varies depending on the weapon level and refinement rate. - if( status->rhw.matk > 0 ){ - int wMatk = status->rhw.matk; - int variance = wMatk * status->rhw.wlv / 10; - status->matk_min += wMatk - variance; - status->matk_max += wMatk + variance; - } - } -#endif - if (bl->type&BL_PC && sd->matk_rate != 100) { - status->matk_max = status->matk_max * sd->matk_rate/100; - status->matk_min = status->matk_min * sd->matk_rate/100; - } - - status->matk_min = status_calc_matk(bl, sc, status->matk_min); - status->matk_max = status_calc_matk(bl, sc, status->matk_max); - - if ((bl->type&BL_HOM && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk - || sc->data[SC_RECOGNIZEDSPELL]) - status->matk_min = status->matk_max; - -#ifdef RENEWAL - if( sd && sd->right_weapon.overrefine > 0){ - status->matk_min++; - status->matk_max += sd->right_weapon.overrefine - 1; - } -#endif - + if(flag&SCB_MATK) { + status_get_matk(bl, 0); } if(flag&SCB_ASPD) { @@ -3844,11 +3823,11 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) amotion = amotion*status->aspd_rate/1000; #else // aspd = baseaspd + floor(sqrt((agi^2/2) + (dex^2/5))/4 + (potskillbonus*agi/200)) - amotion -= (int)(sqrt( (pow(status->agi, 2) / 2) + (pow(status->dex, 2) / 5) ) / 4 + (status_calc_aspd(bl, sc, 1) * status->agi / 200)) * 10; + amotion -= (int)(sqrt( (pow(status->agi, 2) / 2) + (pow(status->dex, 2) / 5) ) / 4 + ((float)status_calc_aspd(bl, sc, 1) * status->agi / 200)) * 10; if( (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) != 0 ) // RE ASPD percertage modifier - amotion -= ( amotion - ((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd) ) - * (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) / 100; + amotion -= (( amotion - ((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd) ) + * (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) / 10 + 5) / 10; if(status->aspd_rate != 1000) // absolute percentage modifier amotion = ( 200 - (200-amotion/10) * status->aspd_rate / 1000 ) * 10; @@ -4102,38 +4081,38 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang str -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(str,0,USHRT_MAX); } - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && str < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && str < 50) return 50; if(sc->data[SC_INCALLSTATUS]) str += sc->data[SC_INCALLSTATUS]->val1; - if(sc->data[SC_INCSTR]) - str += sc->data[SC_INCSTR]->val1; - if(sc->data[SC_STRFOOD]) - str += sc->data[SC_STRFOOD]->val1; + if(sc->data[SC_CHASEWALK2]) + str += sc->data[SC_CHASEWALK2]->val1; + if(sc->data[SC_FOOD_STR]) + str += sc->data[SC_FOOD_STR]->val1; if(sc->data[SC_FOOD_STR_CASH]) str += sc->data[SC_FOOD_STR_CASH]->val1; - if(sc->data[SC_BATTLEORDERS]) + if(sc->data[SC_GDSKILL_BATTLEORDER]) str += 5; if(sc->data[SC_LEADERSHIP]) str += sc->data[SC_LEADERSHIP]->val1; - if(sc->data[SC_LOUD]) + if(sc->data[SC_SHOUT]) str += 4; if(sc->data[SC_TRUESIGHT]) str += 5; - if(sc->data[SC_SPURT]) + if(sc->data[SC_STRUP]) str += 10; - if(sc->data[SC_NEN]) - str += sc->data[SC_NEN]->val1; + if(sc->data[SC_NJ_NEN]) + str += sc->data[SC_NJ_NEN]->val1; if(sc->data[SC_BLESSING]){ if(sc->data[SC_BLESSING]->val2) str += sc->data[SC_BLESSING]->val2; else str >>= 1; } + if(sc->data[SC_MARIONETTE_MASTER]) + str -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>16)&0xFF; if(sc->data[SC_MARIONETTE]) - str -= ((sc->data[SC_MARIONETTE]->val3)>>16)&0xFF; - if(sc->data[SC_MARIONETTE2]) - str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF; + str += ((sc->data[SC_MARIONETTE]->val3)>>16)&0xFF; if(sc->data[SC_GIANTGROWTH]) str += 30; if(sc->data[SC_SAVAGE_STEAK]) @@ -4144,6 +4123,8 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang str -= sc->data[SC_STOMACHACHE]->val1; if(sc->data[SC_KYOUGAKU]) str -= sc->data[SC_KYOUGAKU]->val2; + if(sc->data[SC_FULL_THROTTLE]) + str += str * 20 / 100; return (unsigned short)cap_value(str,0,USHRT_MAX); } @@ -4157,36 +4138,36 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang agi -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(agi,0,USHRT_MAX); } - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && agi < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && agi < 50) return 50; - if(sc->data[SC_CONCENTRATE] && !sc->data[SC_QUAGMIRE]) - agi += (agi-sc->data[SC_CONCENTRATE]->val3)*sc->data[SC_CONCENTRATE]->val2/100; + if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE]) + agi += (agi-sc->data[SC_CONCENTRATION]->val3)*sc->data[SC_CONCENTRATION]->val2/100; if(sc->data[SC_INCALLSTATUS]) agi += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCAGI]) agi += sc->data[SC_INCAGI]->val1; - if(sc->data[SC_AGIFOOD]) - agi += sc->data[SC_AGIFOOD]->val1; + if(sc->data[SC_FOOD_AGI]) + agi += sc->data[SC_FOOD_AGI]->val1; if(sc->data[SC_FOOD_AGI_CASH]) agi += sc->data[SC_FOOD_AGI_CASH]->val1; if(sc->data[SC_SOULCOLD]) agi += sc->data[SC_SOULCOLD]->val1; if(sc->data[SC_TRUESIGHT]) agi += 5; - if(sc->data[SC_INCREASEAGI]) - agi += sc->data[SC_INCREASEAGI]->val2; - if(sc->data[SC_INCREASING]) + if(sc->data[SC_INC_AGI]) + agi += sc->data[SC_INC_AGI]->val2; + if(sc->data[SC_GS_ACCURACY]) agi += 4; // added based on skill updates [Reddozen] - if(sc->data[SC_DECREASEAGI]) - agi -= sc->data[SC_DECREASEAGI]->val2; + if(sc->data[SC_DEC_AGI]) + agi -= sc->data[SC_DEC_AGI]->val2; if(sc->data[SC_QUAGMIRE]) agi -= sc->data[SC_QUAGMIRE]->val2; - if(sc->data[SC_SUITON] && sc->data[SC_SUITON]->val3) - agi -= sc->data[SC_SUITON]->val2; + if(sc->data[SC_NJ_SUITON] && sc->data[SC_NJ_SUITON]->val3) + agi -= sc->data[SC_NJ_SUITON]->val2; + if(sc->data[SC_MARIONETTE_MASTER]) + agi -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>8)&0xFF; if(sc->data[SC_MARIONETTE]) - agi -= ((sc->data[SC_MARIONETTE]->val3)>>8)&0xFF; - if(sc->data[SC_MARIONETTE2]) - agi += ((sc->data[SC_MARIONETTE2]->val3)>>8)&0xFF; + agi += ((sc->data[SC_MARIONETTE]->val3)>>8)&0xFF; if(sc->data[SC_ADORAMUS]) agi -= sc->data[SC_ADORAMUS]->val2; if(sc->data[SC_DROCERA_HERB_STEAMED]) @@ -4198,6 +4179,11 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang if(sc->data[SC_KYOUGAKU]) agi -= sc->data[SC_KYOUGAKU]->val2; + if(sc->data[SC_MARSHOFABYSS]) + agi -= agi * sc->data[SC_MARSHOFABYSS]->val2 / 100; + if(sc->data[SC_FULL_THROTTLE]) + agi += agi * 20 / 100; + return (unsigned short)cap_value(agi,0,USHRT_MAX); } @@ -4210,26 +4196,26 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang vit -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(vit,0,USHRT_MAX); } - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && vit < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && vit < 50) return 50; if(sc->data[SC_INCALLSTATUS]) vit += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCVIT]) vit += sc->data[SC_INCVIT]->val1; - if(sc->data[SC_VITFOOD]) - vit += sc->data[SC_VITFOOD]->val1; + if(sc->data[SC_FOOD_VIT]) + vit += sc->data[SC_FOOD_VIT]->val1; if(sc->data[SC_FOOD_VIT_CASH]) vit += sc->data[SC_FOOD_VIT_CASH]->val1; - if(sc->data[SC_CHANGE]) - vit += sc->data[SC_CHANGE]->val2; + if(sc->data[SC_HLIF_CHANGE]) + vit += sc->data[SC_HLIF_CHANGE]->val2; if(sc->data[SC_GLORYWOUNDS]) vit += sc->data[SC_GLORYWOUNDS]->val1; if(sc->data[SC_TRUESIGHT]) vit += 5; + if(sc->data[SC_MARIONETTE_MASTER]) + vit -= sc->data[SC_MARIONETTE_MASTER]->val3&0xFF; if(sc->data[SC_MARIONETTE]) - vit -= sc->data[SC_MARIONETTE]->val3&0xFF; - if(sc->data[SC_MARIONETTE2]) - vit += sc->data[SC_MARIONETTE2]->val3&0xFF; + vit += sc->data[SC_MARIONETTE]->val3&0xFF; if(sc->data[SC_LAUDAAGNUS]) vit += 4 + sc->data[SC_LAUDAAGNUS]->val1; if(sc->data[SC_MINOR_BBQ]) @@ -4241,8 +4227,10 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang if(sc->data[SC_KYOUGAKU]) vit -= sc->data[SC_KYOUGAKU]->val2; - if(sc->data[SC_STRIPARMOR]) - vit -= vit * sc->data[SC_STRIPARMOR]->val2/100; + if(sc->data[SC_NOEQUIPARMOR]) + vit -= vit * sc->data[SC_NOEQUIPARMOR]->val2/100; + if(sc->data[SC_FULL_THROTTLE]) + vit += vit * 20 / 100; return (unsigned short)cap_value(vit,0,USHRT_MAX); } @@ -4256,19 +4244,19 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang int_ -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(int_,0,USHRT_MAX); } - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && int_ < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && int_ < 50) return 50; if(sc->data[SC_INCALLSTATUS]) int_ += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCINT]) int_ += sc->data[SC_INCINT]->val1; - if(sc->data[SC_INTFOOD]) - int_ += sc->data[SC_INTFOOD]->val1; + if(sc->data[SC_FOOD_INT]) + int_ += sc->data[SC_FOOD_INT]->val1; if(sc->data[SC_FOOD_INT_CASH]) int_ += sc->data[SC_FOOD_INT_CASH]->val1; - if(sc->data[SC_CHANGE]) - int_ += sc->data[SC_CHANGE]->val3; - if(sc->data[SC_BATTLEORDERS]) + if(sc->data[SC_HLIF_CHANGE]) + int_ += sc->data[SC_HLIF_CHANGE]->val3; + if(sc->data[SC_GDSKILL_BATTLEORDER]) int_ += 5; if(sc->data[SC_TRUESIGHT]) int_ += 5; @@ -4278,12 +4266,12 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang else int_ >>= 1; } - if(sc->data[SC_NEN]) - int_ += sc->data[SC_NEN]->val1; + if(sc->data[SC_NJ_NEN]) + int_ += sc->data[SC_NJ_NEN]->val1; + if(sc->data[SC_MARIONETTE_MASTER]) + int_ -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>16)&0xFF; if(sc->data[SC_MARIONETTE]) - int_ -= ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF; - if(sc->data[SC_MARIONETTE2]) - int_ += ((sc->data[SC_MARIONETTE2]->val4)>>16)&0xFF; + int_ += ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF; if(sc->data[SC_MANDRAGORA]) int_ -= 5 + 5 * sc->data[SC_MANDRAGORA]->val1; if(sc->data[SC_COCKTAIL_WARG_BLOOD]) @@ -4295,10 +4283,12 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang if(sc->data[SC_KYOUGAKU]) int_ -= sc->data[SC_KYOUGAKU]->val2; - if(sc->data[SC_STRIPHELM]) - int_ -= int_ * sc->data[SC_STRIPHELM]->val2/100; - if(sc->data[SC__STRIPACCESSORY]) - int_ -= int_ * sc->data[SC__STRIPACCESSORY]->val2 / 100; + if(sc->data[SC_NOEQUIPHELM]) + int_ -= int_ * sc->data[SC_NOEQUIPHELM]->val2/100; + if(sc->data[SC__STRIPACCESSARY]) + int_ -= int_ * sc->data[SC__STRIPACCESSARY]->val2 / 100; + if(sc->data[SC_FULL_THROTTLE]) + int_ += int_ * 20 / 100; return (unsigned short)cap_value(int_,0,USHRT_MAX); } @@ -4312,19 +4302,19 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang dex -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(dex,0,USHRT_MAX); } - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && dex < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && dex < 50) return 50; - if(sc->data[SC_CONCENTRATE] && !sc->data[SC_QUAGMIRE]) - dex += (dex-sc->data[SC_CONCENTRATE]->val4)*sc->data[SC_CONCENTRATE]->val2/100; + if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE]) + dex += (dex-sc->data[SC_CONCENTRATION]->val4)*sc->data[SC_CONCENTRATION]->val2/100; if(sc->data[SC_INCALLSTATUS]) dex += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCDEX]) dex += sc->data[SC_INCDEX]->val1; - if(sc->data[SC_DEXFOOD]) - dex += sc->data[SC_DEXFOOD]->val1; + if(sc->data[SC_FOOD_DEX]) + dex += sc->data[SC_FOOD_DEX]->val1; if(sc->data[SC_FOOD_DEX_CASH]) dex += sc->data[SC_FOOD_DEX_CASH]->val1; - if(sc->data[SC_BATTLEORDERS]) + if(sc->data[SC_GDSKILL_BATTLEORDER]) dex += 5; if(sc->data[SC_HAWKEYES]) dex += sc->data[SC_HAWKEYES]->val1; @@ -4338,12 +4328,12 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang else dex >>= 1; } - if(sc->data[SC_INCREASING]) + if(sc->data[SC_GS_ACCURACY]) dex += 4; // added based on skill updates [Reddozen] + if(sc->data[SC_MARIONETTE_MASTER]) + dex -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>8)&0xFF; if(sc->data[SC_MARIONETTE]) - dex -= ((sc->data[SC_MARIONETTE]->val4)>>8)&0xFF; - if(sc->data[SC_MARIONETTE2]) - dex += ((sc->data[SC_MARIONETTE2]->val4)>>8)&0xFF; + dex += ((sc->data[SC_MARIONETTE]->val4)>>8)&0xFF; if(sc->data[SC_SIROMA_ICE_TEA]) dex += sc->data[SC_SIROMA_ICE_TEA]->val1; if(sc->data[SC_INSPIRATION]) @@ -4353,8 +4343,12 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang if(sc->data[SC_KYOUGAKU]) dex -= sc->data[SC_KYOUGAKU]->val2; - if(sc->data[SC__STRIPACCESSORY]) - dex -= dex * sc->data[SC__STRIPACCESSORY]->val2 / 100; + if(sc->data[SC_MARSHOFABYSS]) + dex -= dex * sc->data[SC_MARSHOFABYSS]->val2 / 100; + if(sc->data[SC__STRIPACCESSARY]) + dex -= dex * sc->data[SC__STRIPACCESSARY]->val2 / 100; + if(sc->data[SC_FULL_THROTTLE]) + dex += dex * 20 / 100; return (unsigned short)cap_value(dex,0,USHRT_MAX); } @@ -4370,24 +4364,24 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang } if(sc->data[SC_CURSE]) return 0; - if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && luk < 50) + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && luk < 50) return 50; if(sc->data[SC_INCALLSTATUS]) luk += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCLUK]) luk += sc->data[SC_INCLUK]->val1; - if(sc->data[SC_LUKFOOD]) - luk += sc->data[SC_LUKFOOD]->val1; + if(sc->data[SC_FOOD_LUK]) + luk += sc->data[SC_FOOD_LUK]->val1; if(sc->data[SC_FOOD_LUK_CASH]) luk += sc->data[SC_FOOD_LUK_CASH]->val1; if(sc->data[SC_TRUESIGHT]) luk += 5; if(sc->data[SC_GLORIA]) luk += 30; + if(sc->data[SC_MARIONETTE_MASTER]) + luk -= sc->data[SC_MARIONETTE_MASTER]->val4&0xFF; if(sc->data[SC_MARIONETTE]) - luk -= sc->data[SC_MARIONETTE]->val4&0xFF; - if(sc->data[SC_MARIONETTE2]) - luk += sc->data[SC_MARIONETTE2]->val4&0xFF; + luk += sc->data[SC_MARIONETTE]->val4&0xFF; if(sc->data[SC_PUTTI_TAILS_NOODLES]) luk += sc->data[SC_PUTTI_TAILS_NOODLES]->val1; if(sc->data[SC_INSPIRATION]) @@ -4399,26 +4393,33 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang if(sc->data[SC_LAUDARAMUS]) luk += 4 + sc->data[SC_LAUDARAMUS]->val1; - if(sc->data[SC__STRIPACCESSORY]) - luk -= luk * sc->data[SC__STRIPACCESSORY]->val2 / 100; + if(sc->data[SC__STRIPACCESSARY]) + luk -= luk * sc->data[SC__STRIPACCESSARY]->val2 / 100; if(sc->data[SC_BANANA_BOMB]) luk -= luk * sc->data[SC_BANANA_BOMB]->val1 / 100; + if(sc->data[SC_FULL_THROTTLE]) + luk += luk * 20 / 100; return (unsigned short)cap_value(luk,0,USHRT_MAX); } -static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk) +static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk, bool viewable) { if(!sc || !sc->count) return cap_value(batk,0,USHRT_MAX); + + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (unsigned short)cap_value(batk,0,USHRT_MAX); + } - if(sc->data[SC_ATKPOTION]) - batk += sc->data[SC_ATKPOTION]->val1; + if(sc->data[SC_PLUSATTACKPOWER]) + batk += sc->data[SC_PLUSATTACKPOWER]->val1; if(sc->data[SC_BATKFOOD]) batk += sc->data[SC_BATKFOOD]->val1; - if(sc->data[SC_GATLINGFEVER]) - batk += sc->data[SC_GATLINGFEVER]->val3; - if(sc->data[SC_MADNESSCANCEL]) + if(sc->data[SC_GS_GATLINGFEVER]) + batk += sc->data[SC_GS_GATLINGFEVER]->val3; + if(sc->data[SC_GS_MADNESSCANCEL]) batk += 100; if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) batk += 50; @@ -4433,7 +4434,7 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk += sc->data[SC_FULL_SWING_K]->val1; if(sc->data[SC_ODINS_POWER]) batk += 70; - if(sc->data[SC_ASH] && (bl->type==BL_MOB)){ + if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_element(bl) == ELE_WATER) //water type batk /= 2; } @@ -4446,42 +4447,53 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk += batk * sc->data[SC_INCATKRATE]->val1/100; if(sc->data[SC_PROVOKE]) batk += batk * sc->data[SC_PROVOKE]->val3/100; - if(sc->data[SC_CONCENTRATION]) - batk += batk * sc->data[SC_CONCENTRATION]->val2/100; +#ifndef RENEWAL + if(sc->data[SC_LKCONCENTRATION]) + batk += batk * sc->data[SC_LKCONCENTRATION]->val2/100; +#endif if(sc->data[SC_SKE]) batk += batk * 3; - if(sc->data[SC_BLOODLUST]) - batk += batk * sc->data[SC_BLOODLUST]->val2/100; + if(sc->data[SC_HAMI_BLOODLUST]) + batk += batk * sc->data[SC_HAMI_BLOODLUST]->val2/100; if(sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST) batk -= batk * 25/100; if(sc->data[SC_CURSE]) batk -= batk * 25/100; + if( sc->data[SC_ZANGETSU] ) + batk += sc->data[SC_ZANGETSU]->val2; //Curse shouldn't effect on this? <- Curse OR Bleeding?? -// if(sc->data[SC_BLEEDING]) +// if(sc->data[SC_BLOODING]) // batk -= batk * 25/100; - if(sc->data[SC_FLEET]) - batk += batk * sc->data[SC_FLEET]->val3/100; + if(sc->data[SC_HLIF_FLEET]) + batk += batk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC__ENERVATION]) batk -= batk * sc->data[SC__ENERVATION]->val2 / 100; - if(sc->data[SC_RUSHWINDMILL]) - batk += batk * sc->data[SC_RUSHWINDMILL]->val2/100; - if(sc->data[SC_SATURDAYNIGHTFEVER]) - batk += 100 * sc->data[SC_SATURDAYNIGHTFEVER]->val1; + if(sc->data[SC_RUSH_WINDMILL]) + batk += batk * sc->data[SC_RUSH_WINDMILL]->val2/100; + if(sc->data[SC_SATURDAY_NIGHT_FEVER]) + batk += 100 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1; if(sc->data[SC_MELODYOFSINK]) batk -= batk * sc->data[SC_MELODYOFSINK]->val3/100; - if(sc->data[SC_BEYONDOFWARCRY]) - batk += batk * sc->data[SC_BEYONDOFWARCRY]->val3/100; - if( sc->data[SC_ZANGETSU] ) - batk += batk * sc->data[SC_ZANGETSU]->val2 / 100; + if(sc->data[SC_BEYOND_OF_WARCRY]) + batk += batk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; return (unsigned short)cap_value(batk,0,USHRT_MAX); } -static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk) +static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk, bool viewable) { if(!sc || !sc->count) return cap_value(watk,0,USHRT_MAX); + if( !viewable ){ + /* some statuses that are hidden in the status window */ + if(sc->data[SC_STRIKING]) + watk += sc->data[SC_STRIKING]->val2; + if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val2) + watk += sc->data[SC_GENTLETOUCH_CHANGE]->val2; + return (unsigned short)cap_value(watk,0,USHRT_MAX); + } + if(sc->data[SC_IMPOSITIO]) watk += sc->data[SC_IMPOSITIO]->val2; if(sc->data[SC_WATKFOOD]) @@ -4490,12 +4502,10 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += sc->data[SC_DRUMBATTLE]->val2; if(sc->data[SC_VOLCANO]) watk += sc->data[SC_VOLCANO]->val2; - if(sc->data[SC_MERC_ATKUP]) - watk += sc->data[SC_MERC_ATKUP]->val2; + if(sc->data[SC_MER_ATK]) + watk += sc->data[SC_MER_ATK]->val2; if(sc->data[SC_FIGHTINGSPIRIT]) watk += sc->data[SC_FIGHTINGSPIRIT]->val1; - if(sc->data[SC_STRIKING]) - watk += sc->data[SC_STRIKING]->val2; if(sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 3) watk += sc->data[SC_SHIELDSPELL_DEF]->val2; if(sc->data[SC_INSPIRATION]) @@ -4522,23 +4532,28 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += sc->data[SC_NIBELUNGEN]->val2; } } - +#ifndef RENEWAL + if(sc->data[SC_STRIKING]) + watk += sc->data[SC_STRIKING]->val2; + if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val2) + watk += sc->data[SC_GENTLETOUCH_CHANGE]->val2; + if(sc->data[SC_LKCONCENTRATION]) + watk += watk * sc->data[SC_LKCONCENTRATION]->val2/100; +#endif if(sc->data[SC_INCATKRATE]) watk += watk * sc->data[SC_INCATKRATE]->val1/100; if(sc->data[SC_PROVOKE]) watk += watk * sc->data[SC_PROVOKE]->val3/100; - if(sc->data[SC_CONCENTRATION]) - watk += watk * sc->data[SC_CONCENTRATION]->val2/100; if(sc->data[SC_SKE]) watk += watk * 3; if(sc->data[SC__ENERVATION]) watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; - if(sc->data[SC_FLEET]) - watk += watk * sc->data[SC_FLEET]->val3/100; + if(sc->data[SC_HLIF_FLEET]) + watk += watk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC_CURSE]) watk -= watk * 25/100; - if(sc->data[SC_STRIPWEAPON]) - watk -= watk * sc->data[SC_STRIPWEAPON]->val2/100; + if(sc->data[SC_NOEQUIPWEAPON]) + watk -= watk * sc->data[SC_NOEQUIPWEAPON]->val2/100; if(sc->data[SC__ENERVATION]) watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; if((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) @@ -4551,10 +4566,6 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += watk * sc->data[SC_TIDAL_WEAPON]->val2 / 100; if(sc->data[SC_ANGRIFFS_MODUS]) watk += watk * sc->data[SC_ANGRIFFS_MODUS]->val2/100; -#ifdef RENEWAL_EDP - if( sc->data[SC_EDP] ) - watk = watk * (100 + sc->data[SC_EDP]->val1 * 80) / 100; -#endif return (unsigned short)cap_value(watk,0,USHRT_MAX); } @@ -4564,8 +4575,8 @@ static unsigned short status_calc_ematk(struct block_list *bl, struct status_cha if (!sc || !sc->count) return cap_value(matk,0,USHRT_MAX); - if (sc->data[SC_MATKPOTION]) - matk += sc->data[SC_MATKPOTION]->val1; + if (sc->data[SC_PLUSMAGICPOWER]) + matk += sc->data[SC_PLUSMAGICPOWER]->val1; if (sc->data[SC_MATKFOOD]) matk += sc->data[SC_MATKFOOD]->val1; if(sc->data[SC_MANA_PLUS]) @@ -4581,18 +4592,24 @@ static unsigned short status_calc_ematk(struct block_list *bl, struct status_cha if(sc->data[SC_ODINS_POWER]) matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 if(sc->data[SC_IZAYOI]) - matk += 50 * sc->data[SC_IZAYOI]->val1; + matk += 25 * sc->data[SC_IZAYOI]->val1; return (unsigned short)cap_value(matk,0,USHRT_MAX); } #endif -static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk) +static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk, bool viewable) { if(!sc || !sc->count) return cap_value(matk,0,USHRT_MAX); + + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (unsigned short)cap_value(matk,0,USHRT_MAX); + } + #ifndef RENEWAL // take note fixed value first before % modifiers - if (sc->data[SC_MATKPOTION]) - matk += sc->data[SC_MATKPOTION]->val1; + if (sc->data[SC_PLUSMAGICPOWER]) + matk += sc->data[SC_PLUSMAGICPOWER]->val1; if (sc->data[SC_MATKFOOD]) matk += sc->data[SC_MATKFOOD]->val1; if (sc->data[SC_MANA_PLUS]) @@ -4608,33 +4625,38 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan if (sc->data[SC_ODINS_POWER]) matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 if (sc->data[SC_IZAYOI]) - matk += 50 * sc->data[SC_IZAYOI]->val1; + matk += 25 * sc->data[SC_IZAYOI]->val1; #endif + if( sc->data[SC_ZANGETSU] ) + matk += sc->data[SC_ZANGETSU]->val3; if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4) matk += matk * sc->data[SC_MAGICPOWER]->val3/100; if (sc->data[SC_MINDBREAKER]) matk += matk * sc->data[SC_MINDBREAKER]->val2/100; if (sc->data[SC_INCMATKRATE]) matk += matk * sc->data[SC_INCMATKRATE]->val1/100; - if (sc->data[SC_MOONLITSERENADE]) - matk += matk * sc->data[SC_MOONLITSERENADE]->val2/100; + if (sc->data[SC_MOONLIT_SERENADE]) + matk += matk * sc->data[SC_MOONLIT_SERENADE]->val2/100; if (sc->data[SC_MELODYOFSINK]) matk += matk * sc->data[SC_MELODYOFSINK]->val3/100; - if (sc->data[SC_BEYONDOFWARCRY]) - matk -= matk * sc->data[SC_BEYONDOFWARCRY]->val3/100; - if( sc->data[SC_ZANGETSU] ) - matk += matk * sc->data[SC_ZANGETSU]->val2 / 100; + if (sc->data[SC_BEYOND_OF_WARCRY]) + matk -= matk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } -static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical) { +static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical, bool viewable) { if(!sc || !sc->count) return cap_value(critical,10,SHRT_MAX); - if (sc->data[SC_INCCRI]) - critical += sc->data[SC_INCCRI]->val2; + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (short)cap_value(critical,10,SHRT_MAX); + } + + if (sc->data[SC_CRITICALPERCENT]) + critical += sc->data[SC_CRITICALPERCENT]->val2; if (sc->data[SC_EXPLOSIONSPIRITS]) critical += sc->data[SC_EXPLOSIONSPIRITS]->val2; if (sc->data[SC_FORTUNE]) @@ -4658,30 +4680,35 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch return (short)cap_value(critical,10,SHRT_MAX); } -static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit) +static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit, bool viewable) { if(!sc || !sc->count) return cap_value(hit,1,SHRT_MAX); + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (short)cap_value(hit,1,SHRT_MAX); + } + if(sc->data[SC_INCHIT]) hit += sc->data[SC_INCHIT]->val1; - if(sc->data[SC_HITFOOD]) - hit += sc->data[SC_HITFOOD]->val1; + if(sc->data[SC_FOOD_BASICHIT]) + hit += sc->data[SC_FOOD_BASICHIT]->val1; if(sc->data[SC_TRUESIGHT]) hit += sc->data[SC_TRUESIGHT]->val3; if(sc->data[SC_HUMMING]) hit += sc->data[SC_HUMMING]->val2; - if(sc->data[SC_CONCENTRATION]) - hit += sc->data[SC_CONCENTRATION]->val3; + if(sc->data[SC_LKCONCENTRATION]) + hit += sc->data[SC_LKCONCENTRATION]->val3; if(sc->data[SC_INSPIRATION]) hit += 5 * sc->data[SC_INSPIRATION]->val1; - if(sc->data[SC_ADJUSTMENT]) + if(sc->data[SC_GS_ADJUSTMENT]) hit -= 30; - if(sc->data[SC_INCREASING]) + if(sc->data[SC_GS_ACCURACY]) hit += 20; // RockmanEXE; changed based on updated [Reddozen] - if(sc->data[SC_MERC_HITUP]) - hit += sc->data[SC_MERC_HITUP]->val2; + if(sc->data[SC_MER_HIT]) + hit += sc->data[SC_MER_HIT]->val2; if(sc->data[SC_INCHITRATE]) hit += hit * sc->data[SC_INCHITRATE]->val1/100; @@ -4691,13 +4718,13 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change hit -= hit * sc->data[SC__GROOMY]->val3 / 100; if(sc->data[SC_FEAR]) hit -= hit * 20 / 100; - if (sc->data[SC_ASH]) + if (sc->data[SC_VOLCANIC_ASH]) hit /= 2; return (short)cap_value(hit,1,SHRT_MAX); } -static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee) +static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee, bool viewable) { if( bl->type == BL_PC ) { @@ -4710,10 +4737,15 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change if(!sc || !sc->count) return cap_value(flee,1,SHRT_MAX); + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (short)cap_value(flee,1,SHRT_MAX); + } + if(sc->data[SC_INCFLEE]) flee += sc->data[SC_INCFLEE]->val1; - if(sc->data[SC_FLEEFOOD]) - flee += sc->data[SC_FLEEFOOD]->val1; + if(sc->data[SC_FOOD_BASICAVOIDANCE]) + flee += sc->data[SC_FOOD_BASICAVOIDANCE]->val1; if(sc->data[SC_WHISTLE]) flee += sc->data[SC_WHISTLE]->val2; if(sc->data[SC_WINDWALK]) @@ -4722,28 +4754,26 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += sc->data[SC_VIOLENTGALE]->val2; if(sc->data[SC_MOON_COMFORT]) //SG skill [Komurka] flee += sc->data[SC_MOON_COMFORT]->val2; - if(sc->data[SC_CLOSECONFINE]) + if(sc->data[SC_RG_CCONFINE_M]) flee += 10; if (sc->data[SC_ANGRIFFS_MODUS]) flee -= sc->data[SC_ANGRIFFS_MODUS]->val3; if (sc->data[SC_OVERED_BOOST]) flee = max(flee,sc->data[SC_OVERED_BOOST]->val2); - if(sc->data[SC_ADJUSTMENT]) + if(sc->data[SC_GS_ADJUSTMENT]) flee += 30; - if(sc->data[SC_SPEED]) - flee += 10 + sc->data[SC_SPEED]->val1 * 10; - if(sc->data[SC_GATLINGFEVER]) - flee -= sc->data[SC_GATLINGFEVER]->val4; + if(sc->data[SC_HLIF_SPEED]) + flee += 10 + sc->data[SC_HLIF_SPEED]->val1 * 10; + if(sc->data[SC_GS_GATLINGFEVER]) + flee -= sc->data[SC_GS_GATLINGFEVER]->val4; if(sc->data[SC_PARTYFLEE]) flee += sc->data[SC_PARTYFLEE]->val1 * 10; - if(sc->data[SC_MERC_FLEEUP]) - flee += sc->data[SC_MERC_FLEEUP]->val2; + if(sc->data[SC_MER_FLEE]) + flee += sc->data[SC_MER_FLEE]->val2; if( sc->data[SC_HALLUCINATIONWALK] ) flee += sc->data[SC_HALLUCINATIONWALK]->val2; if( sc->data[SC_WATER_BARRIER] ) flee -= sc->data[SC_WATER_BARRIER]->val3; - if( sc->data[SC_MARSHOFABYSS] ) - flee -= (9 * sc->data[SC_MARSHOFABYSS]->val3 / 10 + sc->data[SC_MARSHOFABYSS]->val2 / 10) * (bl->type == BL_MOB ? 2 : 1); #ifdef RENEWAL if( sc->data[SC_SPEARQUICKEN] ) flee += 2 * sc->data[SC_SPEARQUICKEN]->val1; @@ -4767,13 +4797,13 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee -= flee * sc->data[SC__LAZINESS]->val3 / 100; if( sc->data[SC_GLOOMYDAY] ) flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100; - if( sc->data[SC_SATURDAYNIGHTFEVER] ) - flee -= flee * (40 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100; + if( sc->data[SC_SATURDAY_NIGHT_FEVER] ) + flee -= flee * (40 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if( sc->data[SC_WIND_STEP_OPTION] ) flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100; if( sc->data[SC_ZEPHYR] ) flee += flee * sc->data[SC_ZEPHYR]->val2 / 100; - if(sc->data[SC_ASH] && (bl->type==BL_MOB)){ //mob + if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ //mob if(status_get_element(bl) == ELE_WATER) //water type flee /= 2; } @@ -4781,13 +4811,18 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change return (short)cap_value(flee,1,SHRT_MAX); } -static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2) +static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2, bool viewable) { if(!sc || !sc->count) return cap_value(flee2,10,SHRT_MAX); - if(sc->data[SC_INCFLEE2]) - flee2 += sc->data[SC_INCFLEE2]->val2; + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (short)cap_value(flee2,10,SHRT_MAX); + } + + if(sc->data[SC_PLUSAVOIDVALUE]) + flee2 += sc->data[SC_PLUSAVOIDVALUE]->val2; if(sc->data[SC_WHISTLE]) flee2 += sc->data[SC_WHISTLE]->val3*10; if(sc->data[SC__UNLUCKY]) @@ -4795,11 +4830,20 @@ static signed short status_calc_flee2(struct block_list *bl, struct status_chang return (short)cap_value(flee2,10,SHRT_MAX); } -static defType status_calc_def(struct block_list *bl, struct status_change *sc, int def) { +defType status_calc_def(struct block_list *bl, struct status_change *sc, int def, bool viewable) { if(!sc || !sc->count) return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); + if( !viewable ){ + /* some statuses that are hidden in the status window */ + if( sc && sc->data[SC_CAMOUFLAGE] ) + def -= def * 5 * (10-sc->data[SC_CAMOUFLAGE]->val4) / 100; + if( sc && sc->data[SC_GENTLETOUCH_REVITALIZE] && sc->data[SC_GENTLETOUCH_REVITALIZE]->val4 ) + def += 2 * sc->data[SC_GENTLETOUCH_REVITALIZE]->val4; + return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); + } + if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) return 0; if(sc->data[SC_SKA]) @@ -4813,12 +4857,12 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, return 90; #endif - if(sc->data[SC_ARMORCHANGE]) - def += sc->data[SC_ARMORCHANGE]->val2; + if(sc->data[SC_STONESKIN]) + def += sc->data[SC_STONESKIN]->val2; if(sc->data[SC_DRUMBATTLE]) def += sc->data[SC_DRUMBATTLE]->val3; - if(sc->data[SC_DEFENCE]) //[orn] - def += sc->data[SC_DEFENCE]->val2 ; + if(sc->data[SC_HAMI_DEFENCE]) //[orn] + def += sc->data[SC_HAMI_DEFENCE]->val2 ; if(sc->data[SC_INCDEFRATE]) def += def * sc->data[SC_INCDEFRATE]->val1/100; if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) @@ -4833,28 +4877,24 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, def >>=1; if(sc->data[SC_FREEZE]) def >>=1; - if(sc->data[SC_SIGNUMCRUCIS]) - def -= def * sc->data[SC_SIGNUMCRUCIS]->val2/100; - if(sc->data[SC_CONCENTRATION]) - def -= def * sc->data[SC_CONCENTRATION]->val4/100; + if(sc->data[SC_CRUCIS]) + def -= def * sc->data[SC_CRUCIS]->val2/100; + if(sc->data[SC_LKCONCENTRATION]) + def -= def * sc->data[SC_LKCONCENTRATION]->val4/100; if(sc->data[SC_SKE]) def >>=1; if(sc->data[SC_PROVOKE] && bl->type != BL_PC) // Provoke doesn't alter player defense-> def -= def * sc->data[SC_PROVOKE]->val4/100; - if(sc->data[SC_STRIPSHIELD]) - def -= def * sc->data[SC_STRIPSHIELD]->val2/100; + if(sc->data[SC_NOEQUIPSHIELD]) + def -= def * sc->data[SC_NOEQUIPSHIELD]->val2/100; if (sc->data[SC_FLING]) def -= def * (sc->data[SC_FLING]->val2)/100; - if( sc->data[SC_FREEZING] ) - def -= def * 10 / 100; - if( sc->data[SC_MARSHOFABYSS] ) - def -= def * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100; if( sc->data[SC_ANALYZE] ) def -= def * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; if( sc->data[SC_FORCEOFVANGUARD] ) def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; - if(sc->data[SC_SATURDAYNIGHTFEVER]) - def -= def * (10 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100; + if(sc->data[SC_SATURDAY_NIGHT_FEVER]) + def -= def * (10 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if(sc->data[SC_EARTHDRIVE]) def -= def * 25 / 100; if( sc->data[SC_ROCK_CRUSHER] ) @@ -4863,15 +4903,17 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100; if( sc->data[SC_PRESTIGE] ) def += def * sc->data[SC_PRESTIGE]->val1 / 100; - if(sc->data[SC_ASH] && (bl->type==BL_MOB)){ + if( sc->data[SC_FROSTMISTY] ) + def -= def * 10 / 100; + if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_race(bl)==RC_PLANT) def /= 2; } - return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX);; + return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } -static signed short status_calc_def2(struct block_list *bl, struct status_change *sc, int def2) +signed short status_calc_def2(struct block_list *bl, struct status_change *sc, int def2, bool viewable) { if(!sc || !sc->count) #ifdef RENEWAL @@ -4880,6 +4922,21 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change return (short)cap_value(def2,1,SHRT_MAX); #endif + if( !viewable ){ + /* some statuses that are hidden in the status window */ +#ifdef RENEWAL + if( sc && sc->data[SC_ASSUMPTIO] ) + def2 <<= 1; +#endif + if( sc && sc->data[SC_CAMOUFLAGE] ) + def2 -= def2 * 5 * (10-sc->data[SC_CAMOUFLAGE]->val4) / 100; +#ifdef RENEWAL + return (short)cap_value(def2,SHRT_MIN,SHRT_MAX); +#else + return (short)cap_value(def2,1,SHRT_MAX); +#endif + } + if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) return 0; if(sc->data[SC_ETERNALCHAOS]) @@ -4896,9 +4953,9 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change def2 += status_get_vit(bl) / 2 * sc->data[SC_ANGELUS]->val2/100; #else def2 += def2 * sc->data[SC_ANGELUS]->val2/100; + if(sc->data[SC_LKCONCENTRATION]) + def2 -= def2 * sc->data[SC_LKCONCENTRATION]->val4/100; #endif - if(sc->data[SC_CONCENTRATION]) - def2 -= def2 * sc->data[SC_CONCENTRATION]->val4/100; if(sc->data[SC_POISON]) def2 -= def2 * 25/100; if(sc->data[SC_DPOISON]) @@ -4912,18 +4969,16 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100; if(sc->data[SC_FLING]) def2 -= def2 * (sc->data[SC_FLING]->val3)/100; - if( sc->data[SC_FREEZING] ) - def2 -= def2 * 3 / 10; if(sc->data[SC_ANALYZE]) def2 -= def2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; if( sc->data[SC_ECHOSONG] ) def2 += def2 * sc->data[SC_ECHOSONG]->val2/100; - if(sc->data[SC_ASH] && (bl->type==BL_MOB)){ + if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_race(bl)==RC_PLANT) def2 /= 2; } - if (sc->data[SC_PARALYSIS]) - def2 -= def2 * sc->data[SC_PARALYSIS]->val2 / 100; + if (sc->data[SC_NEEDLE_OF_PARALYZE]) + def2 -= def2 * sc->data[SC_NEEDLE_OF_PARALYZE]->val2 / 100; #ifdef RENEWAL return (short)cap_value(def2,SHRT_MIN,SHRT_MAX); @@ -4933,11 +4988,16 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change } -static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef) { +defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef, bool viewable) { if(!sc || !sc->count) return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); + if( !viewable ){ + /* some statuses that are hidden in the status window */ + return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); + } + if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) return 0; if(sc->data[SC_BARRIER]) @@ -4948,15 +5008,13 @@ static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, return 90; #endif - if(sc->data[SC_ARMORCHANGE]) - mdef += sc->data[SC_ARMORCHANGE]->val3; + if(sc->data[SC_STONESKIN]) + mdef += sc->data[SC_STONESKIN]->val3; if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 3) mdef += 50; if(sc->data[SC_ENDURE])// It has been confirmed that eddga card grants 1 MDEF, not 0, not 10, but 1. mdef += (sc->data[SC_ENDURE]->val4 == 0) ? sc->data[SC_ENDURE]->val1 : 1; - if(sc->data[SC_CONCENTRATION]) - mdef += 1; //Skill info says it adds a fixed 1 Mdef point. - if(sc->data[SC_STONEHARDSKIN]) + if(sc->data[SC_STONEHARDSKIN])// Final MDEF increase divided by 10 since were using classic (pre-renewal) mechanics. [Rytech] mdef += sc->data[SC_STONEHARDSKIN]->val1; if(sc->data[SC_WATER_BARRIER]) mdef += sc->data[SC_WATER_BARRIER]->val2; @@ -4964,21 +5022,21 @@ static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, mdef += 25*mdef/100; if(sc->data[SC_FREEZE]) mdef += 25*mdef/100; - if( sc->data[SC_MARSHOFABYSS] ) - mdef -= mdef * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100; if(sc->data[SC_ANALYZE]) mdef -= mdef * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; - if(sc->data[SC_SYMPHONYOFLOVER]) - mdef += mdef * sc->data[SC_SYMPHONYOFLOVER]->val2 / 100; - if(sc->data[SC_GT_CHANGE] && sc->data[SC_GT_CHANGE]->val4) - mdef -= mdef * sc->data[SC_GT_CHANGE]->val4 / 100; + if(sc->data[SC_SYMPHONY_LOVE]) + mdef += mdef * sc->data[SC_SYMPHONY_LOVE]->val2 / 100; + if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val4) + mdef -= mdef * sc->data[SC_GENTLETOUCH_CHANGE]->val4 / 100; if (sc->data[SC_ODINS_POWER]) mdef -= 20 * sc->data[SC_ODINS_POWER]->val1; + if(sc->data[SC_BURNING]) + mdef -= mdef *25 / 100; return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); } -static signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, int mdef2) +signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, int mdef2, bool viewable) { if(!sc || !sc->count) #ifdef RENEWAL @@ -4987,6 +5045,16 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang return (short)cap_value(mdef2,1,SHRT_MAX); #endif + if( !viewable ){ + /* some statuses that are hidden in the status window */ +#ifdef RENEWAL + if(sc && sc->data[SC_ASSUMPTIO]) + mdef2 <<= 1; + return (short)cap_value(mdef2,SHRT_MIN,SHRT_MAX); +#else + return (short)cap_value(mdef2,1,SHRT_MAX); +#endif + } if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) return 0; @@ -5063,9 +5131,9 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 50 - 10 * sc->data[SC_LONGING]->val1 ); else if( sd && sc->data[SC_DANCING] ) - val = max( val, 500 - (40 + 10 * (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)) * pc->checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) ); + val = max( val, 500 - (40 + 10 * (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) * pc->checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) ); - if( sc->data[SC_DECREASEAGI] ) + if( sc->data[SC_DEC_AGI] ) val = max( val, 25 ); if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] || (sc->data[SC_GLOOMYDAY] && sc->data[SC_GLOOMYDAY]->val4) ) val = max( val, 50 ); @@ -5085,16 +5153,14 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 75 ); if( sc->data[SC_SLOWDOWN] ) // Slow Potion val = max( val, 100 ); - if( sc->data[SC_GATLINGFEVER] ) + if( sc->data[SC_GS_GATLINGFEVER] ) val = max( val, 100 ); - if( sc->data[SC_SUITON] ) - val = max( val, sc->data[SC_SUITON]->val3 ); + if( sc->data[SC_NJ_SUITON] ) + val = max( val, sc->data[SC_NJ_SUITON]->val3 ); if( sc->data[SC_SWOO] ) val = max( val, 300 ); - if( sc->data[SC_FREEZING] ) - val = max( val, 70 ); - if( sc->data[SC_MARSHOFABYSS] ) - val = max( val, 40 + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); + if( sc->data[SC_FROSTMISTY] ) + val = max( val, 50 ); if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); if( sc->data[SC__GROOMY] ) @@ -5109,6 +5175,9 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 ); if( sc->data[SC_MELON_BOMB] ) val = max( val, sc->data[SC_MELON_BOMB]->val1 ); + + if( sc->data[SC_MARSHOFABYSS] ) // It stacks to other statuses so always put this at the end. + val = max( 50, val + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // permanent item-based speedup val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate ); @@ -5121,9 +5190,9 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha { int val = 0; - if( sc->data[SC_SPEEDUP1] ) //FIXME: used both by NPC_AGIUP and Speed Potion script + if( sc->data[SC_MOVHASTE_INFINITY] ) //FIXME: used both by NPC_AGIUP and Speed Potion script val = max( val, 50 ); - if( sc->data[SC_INCREASEAGI] ) + if( sc->data[SC_INC_AGI] ) val = max( val, 25 ); if( sc->data[SC_WINDWALK] ) val = max( val, 2 * sc->data[SC_WINDWALK]->val1 ); @@ -5137,8 +5206,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 25 ); if( sc->data[SC_RUN] ) val = max( val, 55 ); - if( sc->data[SC_AVOID] ) - val = max( val, 10 * sc->data[SC_AVOID]->val1 ); + if( sc->data[SC_HLIF_AVOID] ) + val = max( val, 10 * sc->data[SC_HLIF_AVOID]->val1 ); if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) val = max( val, 75 ); if( sc->data[SC_CLOAKINGEXCEED] ) @@ -5147,13 +5216,14 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 10 ); if( sc->data[SC_GN_CARTBOOST] ) val = max( val, sc->data[SC_GN_CARTBOOST]->val2 ); - if( sc->data[SC_SWINGDANCE] ) - val = max( val, sc->data[SC_SWINGDANCE]->val2 ); + if( sc->data[SC_SWING] ) + val = max( val, sc->data[SC_SWING]->val2 ); if( sc->data[SC_WIND_STEP_OPTION] ) val = max( val, sc->data[SC_WIND_STEP_OPTION]->val2 ); - + if( sc->data[SC_FULL_THROTTLE] ) + val = max( val, 30); //FIXME: official items use a single bonus for this [ultramage] - if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup + if( sc->data[SC_MOVHASTE_HORSE] ) // temporary item-based speedup val = max( val, 25 ); if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate < 0 ) // permanent item-based speedup val = max( val, -(sd->bonus.speed_rate + sd->bonus.speed_add_rate) ); @@ -5171,6 +5241,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha speed += speed * (50 - 5 * pc->checkskill(sd,MC_PUSHCART)) / 100; if( sc->data[SC_PARALYSE] ) speed += speed * 50 / 100; + if( sc->data[SC_REBOUND] ) + speed += max(speed, 100); if( speed_rate != 100 ) speed = speed * speed_rate / 100; if( sc->data[SC_STEELBODY] ) @@ -5179,6 +5251,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha speed = max(speed, 200); if( sc->data[SC_WALKSPEED] && sc->data[SC_WALKSPEED]->val1 > 0 ) // ChangeSpeed speed = speed * 100 / sc->data[SC_WALKSPEED]->val1; + } return (short)cap_value(speed,10,USHRT_MAX); @@ -5194,22 +5267,19 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s if(!sc || !sc->count) return 0; - if(sc->data[i=SC_ASPDPOTION3] || - sc->data[i=SC_ASPDPOTION2] || - sc->data[i=SC_ASPDPOTION1] || - sc->data[i=SC_ASPDPOTION0]) + if(sc->data[i=SC_ATTHASTE_INFINITY] || + sc->data[i=SC_ATTHASTE_POTION3] || + sc->data[i=SC_ATTHASTE_POTION2] || + sc->data[i=SC_ATTHASTE_POTION1]) pots += sc->data[i]->val1; if( !sc->data[SC_QUAGMIRE] ){ - if(sc->data[SC_STAR_COMFORT]) - skills1 = 5; // needs more info - if(sc->data[SC_TWOHANDQUICKEN] && skills1 < 7) skills1 = 7; - if(sc->data[SC_ONEHAND] && skills1 < 7) skills1 = 7; + if(sc->data[SC_ONEHANDQUICKEN] && skills1 < 7) skills1 = 7; - if(sc->data[SC_MERC_QUICKEN] && skills1 < 7) // needs more info + if(sc->data[SC_MER_QUICKEN] && skills1 < 7) // needs more info skills1 = 7; if(sc->data[SC_ADRENALINE2] && skills1 < 6) @@ -5221,48 +5291,25 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s if(sc->data[SC_SPEARQUICKEN] && skills1 < 7) skills1 = 7; - if(sc->data[SC_GATLINGFEVER] && skills1 < 9) // needs more info - skills1 = 9; - - if(sc->data[SC_FLEET] && skills1 < 5) + if(sc->data[SC_HLIF_FLEET] && skills1 < 5) skills1 = 5; - - if(sc->data[SC_ASSNCROS] && - skills1 < 5+1*sc->data[SC_ASSNCROS]->val1) // needs more info - { - if (bl->type!=BL_PC) - skills1 = 4+1*sc->data[SC_ASSNCROS]->val1; - else - switch(((TBL_PC*)bl)->status.weapon) - { - case W_BOW: - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - case W_GRENADE: - break; - default: - skills1 = 5+1*sc->data[SC_ASSNCROS]->val1; - } - } } if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) && skills1 < 15) skills1 = 15; - else if(sc->data[SC_MADNESSCANCEL] && skills1 < 15) // needs more info - skills1 = 15; + else if(sc->data[SC_GS_MADNESSCANCEL] && skills1 < 20) + skills1 = 20; if(sc->data[SC_DONTFORGETME]) - skills2 -= sc->data[SC_DONTFORGETME]->val2; // needs more info + skills2 -= sc->data[SC_DONTFORGETME]->val2; if(sc->data[SC_LONGING]) - skills2 -= sc->data[SC_LONGING]->val2; // needs more info + skills2 -= sc->data[SC_LONGING]->val2; if(sc->data[SC_STEELBODY]) skills2 -= 25; if(sc->data[SC_SKA]) skills2 -= 25; if(sc->data[SC_DEFENDER]) - skills2 -= sc->data[SC_DEFENDER]->val4; // needs more info + skills2 -= sc->data[SC_DEFENDER]->val4 / 10; if(sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY) // needs more info skills2 -= 25; if(sc->data[SC_GRAVITATION]) @@ -5273,8 +5320,8 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ) skills2 -= 10; } - if( sc->data[SC_FREEZING] ) - skills2 -= 30; + if( sc->data[SC_FROSTMISTY] ) + skills2 -= 15; if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] ) skills2 -= 50; if( sc->data[SC_PARALYSE] ) @@ -5285,25 +5332,46 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s skills2 -= sc->data[SC__INVISIBILITY]->val2 ; if( sc->data[SC__GROOMY] ) skills2 -= sc->data[SC__GROOMY]->val2; - if( sc->data[SC_SWINGDANCE] ) - skills2 += sc->data[SC_SWINGDANCE]->val2; - if( sc->data[SC_DANCEWITHWUG] ) - skills2 += sc->data[SC_DANCEWITHWUG]->val3; if( sc->data[SC_GLOOMYDAY] ) skills2 -= sc->data[SC_GLOOMYDAY]->val3; if( sc->data[SC_EARTHDRIVE] ) skills2 -= 25; - if( sc->data[SC_GT_CHANGE] ) - skills2 += sc->data[SC_GT_CHANGE]->val3; if( sc->data[SC_MELON_BOMB] ) skills2 -= sc->data[SC_MELON_BOMB]->val1; + + if( sc->data[SC_SWING] ) + skills2 += sc->data[SC_SWING]->val2; + if( sc->data[SC_DANCE_WITH_WUG] ) + skills2 += sc->data[SC_DANCE_WITH_WUG]->val3; + if( sc->data[SC_GENTLETOUCH_CHANGE] ) + skills2 += sc->data[SC_GENTLETOUCH_CHANGE]->val3; if( sc->data[SC_BOOST500] ) skills2 += sc->data[SC_BOOST500]->val1; if( sc->data[SC_EXTRACT_SALAMINE_JUICE] ) skills2 += sc->data[SC_EXTRACT_SALAMINE_JUICE]->val1; if( sc->data[SC_INCASPDRATE] ) skills2 += sc->data[SC_INCASPDRATE]->val1; - + if( sc->data[SC_GS_GATLINGFEVER] ) + skills2 += sc->data[SC_GS_GATLINGFEVER]->val1; + if( sc->data[SC_STAR_COMFORT] ) + skills2 += 3 * sc->data[SC_STAR_COMFORT]->val1; + if( sc->data[SC_ASSNCROS] && !skills1){ + if (bl->type!=BL_PC) + skills2 += sc->data[SC_ASSNCROS]->val2; + else + switch(((TBL_PC*)bl)->status.weapon) + { + case W_BOW: + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + case W_GRENADE: + break; + default: + skills2 += sc->data[SC_ASSNCROS]->val2; + } + } return ( flag&1? (skills1 + pots) : skills2 ); } #endif @@ -5344,13 +5412,13 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * max < sc->data[SC_TWOHANDQUICKEN]->val2) max = sc->data[SC_TWOHANDQUICKEN]->val2; - if(sc->data[SC_ONEHAND] && - max < sc->data[SC_ONEHAND]->val2) - max = sc->data[SC_ONEHAND]->val2; + if(sc->data[SC_ONEHANDQUICKEN] && + max < sc->data[SC_ONEHANDQUICKEN]->val2) + max = sc->data[SC_ONEHANDQUICKEN]->val2; - if(sc->data[SC_MERC_QUICKEN] && - max < sc->data[SC_MERC_QUICKEN]->val2) - max = sc->data[SC_MERC_QUICKEN]->val2; + if(sc->data[SC_MER_QUICKEN] && + max < sc->data[SC_MER_QUICKEN]->val2) + max = sc->data[SC_MER_QUICKEN]->val2; if(sc->data[SC_ADRENALINE2] && max < sc->data[SC_ADRENALINE2]->val3) @@ -5364,13 +5432,13 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * max < sc->data[SC_SPEARQUICKEN]->val2) max = sc->data[SC_SPEARQUICKEN]->val2; - if(sc->data[SC_GATLINGFEVER] && - max < sc->data[SC_GATLINGFEVER]->val2) - max = sc->data[SC_GATLINGFEVER]->val2; + if(sc->data[SC_GS_GATLINGFEVER] && + max < sc->data[SC_GS_GATLINGFEVER]->val2) + max = sc->data[SC_GS_GATLINGFEVER]->val2; - if(sc->data[SC_FLEET] && - max < sc->data[SC_FLEET]->val2) - max = sc->data[SC_FLEET]->val2; + if(sc->data[SC_HLIF_FLEET] && + max < sc->data[SC_HLIF_FLEET]->val2) + max = sc->data[SC_HLIF_FLEET]->val2; if(sc->data[SC_ASSNCROS] && max < sc->data[SC_ASSNCROS]->val2) @@ -5395,14 +5463,14 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) aspd_rate -= 300; - else if(sc->data[SC_MADNESSCANCEL]) + else if(sc->data[SC_GS_MADNESSCANCEL]) aspd_rate -= 200; } - if( sc->data[i=SC_ASPDPOTION3] || - sc->data[i=SC_ASPDPOTION2] || - sc->data[i=SC_ASPDPOTION1] || - sc->data[i=SC_ASPDPOTION0] ) + if( sc->data[i=SC_ATTHASTE_INFINITY] || + sc->data[i=SC_ATTHASTE_POTION3] || + sc->data[i=SC_ATTHASTE_POTION2] || + sc->data[i=SC_ATTHASTE_POTION1] ) aspd_rate -= sc->data[i]->val2; if(sc->data[SC_DONTFORGETME]) @@ -5425,8 +5493,8 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ) aspd_rate += 100; } - if( sc->data[SC_FREEZING] ) - aspd_rate += 300; + if( sc->data[SC_FROSTMISTY] ) + aspd_rate += 150; if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] ) aspd_rate += 500; if( sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 ) @@ -5439,16 +5507,16 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * aspd_rate += sc->data[SC__INVISIBILITY]->val2 * 10 ; if( sc->data[SC__GROOMY] ) aspd_rate += sc->data[SC__GROOMY]->val2 * 10; - if( sc->data[SC_SWINGDANCE] ) - aspd_rate -= sc->data[SC_SWINGDANCE]->val2 * 10; - if( sc->data[SC_DANCEWITHWUG] ) - aspd_rate -= sc->data[SC_DANCEWITHWUG]->val3 * 10; + if( sc->data[SC_SWING] ) + aspd_rate -= sc->data[SC_SWING]->val2 * 10; + if( sc->data[SC_DANCE_WITH_WUG] ) + aspd_rate -= sc->data[SC_DANCE_WITH_WUG]->val3 * 10; if( sc->data[SC_GLOOMYDAY] ) aspd_rate += sc->data[SC_GLOOMYDAY]->val3 * 10; if( sc->data[SC_EARTHDRIVE] ) aspd_rate += 250; - if( sc->data[SC_GT_CHANGE] ) - aspd_rate -= sc->data[SC_GT_CHANGE]->val3 * 10; + if( sc->data[SC_GENTLETOUCH_CHANGE] ) + aspd_rate -= sc->data[SC_GENTLETOUCH_CHANGE]->val3 * 10; if( sc->data[SC_MELON_BOMB] ) aspd_rate += sc->data[SC_MELON_BOMB]->val1 * 10; if( sc->data[SC_BOOST500] ) @@ -5474,8 +5542,6 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c **/ if( sc->data[SC_ENDURE] || ( bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS) ) ) return 0; - if( sc->data[SC_CONCENTRATION] ) - return 0; if( sc->data[SC_RUN] || sc->data[SC_WUGDASH] ) return 0; @@ -5497,7 +5563,7 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp += maxhp * sc->data[SC_DELUGE]->val2/100; if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) maxhp += maxhp * 2; - if(sc->data[SC_MARIONETTE]) + if(sc->data[SC_MARIONETTE_MASTER]) maxhp -= 1000; if(sc->data[SC_SOLID_SKIN_OPTION]) maxhp += 2000;// Fix amount. @@ -5506,8 +5572,8 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) maxhp += 500; - if(sc->data[SC_MERC_HPUP]) - maxhp += maxhp * sc->data[SC_MERC_HPUP]->val2/100; + if(sc->data[SC_MER_HP]) + maxhp += maxhp * sc->data[SC_MER_HP]->val2/100; if(sc->data[SC_EPICLESIS]) maxhp += maxhp * 5 * sc->data[SC_EPICLESIS]->val1 / 100; @@ -5515,18 +5581,18 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp -= maxhp * 15 / 100; if(sc->data[SC__WEAKNESS]) maxhp -= maxhp * sc->data[SC__WEAKNESS]->val2 / 100; - if(sc->data[SC_LERADSDEW]) - maxhp += maxhp * sc->data[SC_LERADSDEW]->val3 / 100; + if(sc->data[SC_LERADS_DEW]) + maxhp += maxhp * sc->data[SC_LERADS_DEW]->val3 / 100; if(sc->data[SC_FORCEOFVANGUARD]) maxhp += maxhp * 3 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; if(sc->data[SC_INSPIRATION]) //Custom value. maxhp += maxhp * 3 * sc->data[SC_INSPIRATION]->val1 / 100; if(sc->data[SC_RAISINGDRAGON]) maxhp += maxhp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; - if(sc->data[SC_GT_CHANGE]) // Max HP decrease: [Skill Level x 4] % - maxhp -= maxhp * (4 * sc->data[SC_GT_CHANGE]->val1) / 100; - if(sc->data[SC_GT_REVITALIZE])// Max HP increase: [Skill Level x 2] % - maxhp += maxhp * (2 * sc->data[SC_GT_REVITALIZE]->val1) / 100; + if(sc->data[SC_GENTLETOUCH_CHANGE]) // Max HP decrease: [Skill Level x 4] % + maxhp -= maxhp * (4 * sc->data[SC_GENTLETOUCH_CHANGE]->val1) / 100; + if(sc->data[SC_GENTLETOUCH_REVITALIZE])// Max HP increase: [Skill Level x 2] % + maxhp += maxhp * (2 * sc->data[SC_GENTLETOUCH_REVITALIZE]->val1) / 100; if(sc->data[SC_MUSTLE_M]) maxhp += maxhp * sc->data[SC_MUSTLE_M]->val1/100; if(sc->data[SC_MYSTERIOUS_POWDER]) @@ -5537,6 +5603,8 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp += maxhp * 5 * sc->data[SC_ANGRIFFS_MODUS]->val1 /100; if (sc->data[SC_GOLDENE_FERSE]) maxhp += maxhp * sc->data[SC_GOLDENE_FERSE]->val2 / 100; + if(sc->data[SC_FRIGG_SONG]) + maxhp += maxhp * sc->data[SC_FRIGG_SONG]->val2 / 100; return (unsigned int)cap_value(maxhp,1,UINT_MAX); } @@ -5550,10 +5618,10 @@ static unsigned int status_calc_maxsp(struct block_list *bl, struct status_chang maxsp += maxsp * sc->data[SC_INCMSPRATE]->val1/100; if(sc->data[SC_INCMSP]) maxsp += (sc->data[SC_INCMSP]->val1); - if(sc->data[SC_SERVICE4U]) - maxsp += maxsp * sc->data[SC_SERVICE4U]->val2/100; - if(sc->data[SC_MERC_SPUP]) - maxsp += maxsp * sc->data[SC_MERC_SPUP]->val2/100; + if(sc->data[SC_SERVICEFORYOU]) + maxsp += maxsp * sc->data[SC_SERVICEFORYOU]->val2/100; + if(sc->data[SC_MER_SP]) + maxsp += maxsp * sc->data[SC_MER_SP]->val2/100; if(sc->data[SC_RAISINGDRAGON]) maxsp += maxsp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; if(sc->data[SC_LIFE_FORCE_F]) @@ -5575,10 +5643,10 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch return ELE_EARTH; if(sc->data[SC_BENEDICTIO]) return ELE_HOLY; - if(sc->data[SC_CHANGEUNDEAD]) + if(sc->data[SC_PROPERTYUNDEAD]) return ELE_UNDEAD; - if(sc->data[SC_ELEMENTALCHANGE]) - return sc->data[SC_ELEMENTALCHANGE]->val2; + if(sc->data[SC_ARMOR_PROPERTY]) + return sc->data[SC_ARMOR_PROPERTY]->val2; if(sc->data[SC_SHAPESHIFT]) return sc->data[SC_SHAPESHIFT]->val2; @@ -5596,10 +5664,10 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status return 1; if(sc->data[SC_BENEDICTIO]) return 1; - if(sc->data[SC_CHANGEUNDEAD]) + if(sc->data[SC_PROPERTYUNDEAD]) return 1; - if(sc->data[SC_ELEMENTALCHANGE]) - return sc->data[SC_ELEMENTALCHANGE]->val1; + if(sc->data[SC_ARMOR_PROPERTY]) + return sc->data[SC_ARMOR_PROPERTY]->val1; if(sc->data[SC_SHAPESHIFT]) return 1; if(sc->data[SC__INVISIBILITY]) @@ -5615,25 +5683,25 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch return element; if(sc->data[SC_ENCHANTARMS]) return sc->data[SC_ENCHANTARMS]->val2; - if(sc->data[SC_WATERWEAPON] + if(sc->data[SC_PROPERTYWATER] || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) ) return ELE_WATER; - if(sc->data[SC_EARTHWEAPON] + if(sc->data[SC_PROPERTYGROUND] || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) ) return ELE_EARTH; - if(sc->data[SC_FIREWEAPON] + if(sc->data[SC_PROPERTYFIRE] || (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) ) return ELE_FIRE; - if(sc->data[SC_WINDWEAPON] + if(sc->data[SC_PROPERTYWIND] || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) ) return ELE_WIND; - if(sc->data[SC_ENCPOISON]) + if(sc->data[SC_ENCHANTPOISON]) return ELE_POISON; if(sc->data[SC_ASPERSIO]) return ELE_HOLY; - if(sc->data[SC_SHADOWWEAPON]) + if(sc->data[SC_PROPERTYDARK]) return ELE_DARK; - if(sc->data[SC_GHOSTWEAPON] || sc->data[SC__INVISIBILITY]) + if(sc->data[SC_PROPERTYTELEKINESIS] || sc->data[SC__INVISIBILITY]) return ELE_GHOST; if(sc->data[SC_TIDAL_WEAPON_OPTION] || sc->data[SC_TIDAL_WEAPON] ) return ELE_WATER; @@ -6119,14 +6187,14 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Status that are blocked by Golden Thief Bug card or Wand of Hermod if (status_isimmune(bl)) switch (type) { - case SC_DECREASEAGI: + case SC_DEC_AGI: case SC_SILENCE: case SC_COMA: - case SC_INCREASEAGI: + case SC_INC_AGI: case SC_BLESSING: case SC_SLOWPOISON: case SC_IMPOSITIO: - case SC_AETERNA: + case SC_LEXAETERNA: case SC_SUFFRAGIUM: case SC_BENEDICTIO: case SC_PROVIDENCE: @@ -6137,11 +6205,11 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti case SC_GLORIA: case SC_WINDWALK: case SC_MAGICROD: - case SC_HALLUCINATION: + case SC_ILLUSION: case SC_STONE: case SC_QUAGMIRE: - case SC_SUITON: - case SC_SWINGDANCE: + case SC_NJ_SUITON: + case SC_SWING: case SC__ENERVATION: case SC__GROOMY: case SC__IGNORANCE: @@ -6164,7 +6232,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti return tick; case SC_DPOISON: case SC_SILENCE: - case SC_BLEEDING: + case SC_BLOODING: sc_def = status->vit*100; sc_def2 = status->luk*10; break; @@ -6172,11 +6240,11 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def = status->int_*100; sc_def2 = status->luk*10; break; - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: sc_def = status->int_*50; tick_def = status->int_*10 + status_get_lv(bl) * 65 / 10; //Seems to be -1 sec every 10 int and -5% chance every 10 int. break; - case SC_DECREASEAGI: + case SC_DEC_AGI: case SC_ADORAMUS: //Arch Bishop if (sd) tick>>=1; //Half duration for players. case SC_STONE: @@ -6205,13 +6273,13 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def = (status->str + status->int_)*50; sc_def2 = status->luk*10; break; - case SC_ANKLE: + case SC_ANKLESNARE: if(status->mode&MD_BOSS) // Lasts 5 times less on bosses tick /= 5; sc_def = status->agi*50; break; case SC_MAGICMIRROR: - case SC_ARMORCHANGE: + case SC_STONESKIN: if (sd) //Duration greatly reduced for players. tick /= 15; sc_def2 = status_get_lv(bl)*20 + status->vit*25 + status->agi*10; // Lineal Reduction of Rate @@ -6231,21 +6299,20 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti tick -= (status->vit + status->luk) / 20 * 1000; break; case SC_BURNING: - // From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583 - tick -= 50*status->luk + 60*status->int_ + 170*status->vit; - tick = max(tick,10000); // Minimum Duration 10s. + tick -= 75 * status->luk + 125 * status->agi; + tick = max(tick,5000); // Minimum Duration 5s. break; - case SC_FREEZING: + case SC_FROSTMISTY: tick -= 1000 * ((status->vit + status->dex) / 20); - tick = max(tick,10000); // Minimum Duration 10s. + tick = max(tick,6000); // Minimum Duration 10s. break; case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT) sc_def = 100 - ( 100 - status->int_* 8 / 10 ); sc_def = max(sc_def, 5); // minimum of 5% break; - case SC_BITE: // {(Base Success chance) - (Target's AGI / 4)} - rate -= status->agi*1000/4; - rate = max(rate,50000); // minimum of 50% + case SC_WUGBITE: // {(Base Success chance) - (Target's AGI / 4)} + rate -= status->agi*100/4; + rate = max(rate,5000); // minimum of 50% break; case SC_ELECTRICSHOCKER: if( bl->type == BL_MOB ) @@ -6258,11 +6325,11 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def = (status->vit+status->luk)/5; break; case SC_KYOUGAKU: - tick -= 30*status->int_; + tick -= 1000 * status_get_int(bl) / 20; break; - case SC_PARALYSIS: - tick -= 50 * (status->vit + status->luk); //(1000/20); - break; + case SC_NEEDLE_OF_PARALYZE: + tick -= 50 * (status->vit + status->luk); //(1000/20); + break; default: //Effect that cannot be reduced? Likely a buff. if (!(rnd()%10000 < rate)) @@ -6320,7 +6387,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum chances switch (type) { - case SC_BITE: + case SC_WUGBITE: rate = max(rate, 5000); //Minimum of 50% break; } @@ -6330,8 +6397,8 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti { if( sd->reseff[type-SC_COMMON_MIN] > 0 ) rate -= rate*sd->reseff[type-SC_COMMON_MIN]/10000; - if( sd->sc.data[SC_COMMONSC_RESIST] ) - rate -= rate*sd->sc.data[SC_COMMONSC_RESIST]->val1/100; + if( sd->sc.data[SC_TARGET_BLOOD] ) + rate -= rate*sd->sc.data[SC_TARGET_BLOOD]->val1/100; } } @@ -6350,13 +6417,13 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum durations switch (type) { - case SC_ANKLE: + case SC_ANKLESNARE: case SC_MARSHOFABYSS: case SC_STASIS: tick = max(tick, 5000); //Minimum duration 5s break; case SC_BURNING: - case SC_FREEZING: + case SC_FROSTMISTY: tick = max(tick, 10000); //Minimum duration 10s break; default: @@ -6460,9 +6527,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; // Immune to status ailements switch( type ) { case SC_QUAGMIRE://Tester said it protects against this and decrease agi. - case SC_DECREASEAGI: + case SC_DEC_AGI: case SC_BURNING: - case SC_FREEZING: + case SC_FROSTMISTY: //case SC_WHITEIMPRISON://Need confirm. Protected against this in the past. [Rytech] case SC_MARSHOFABYSS: case SC_TOXIN: @@ -6474,7 +6541,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_OBLIVIONCURSE: case SC_LEECHESEND: case SC_CRYSTALIZE: ////08/31/2011 - Class Balance Changes - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: case SC_MANDRAGORA: return 0; } @@ -6483,8 +6550,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX ) return 0; // Immune to status ailements switch( type ) { - case SC_DEEPSLEEP: - case SC_SATURDAYNIGHTFEVER: + case SC_DEEP_SLEEP: + case SC_SATURDAY_NIGHT_FEVER: case SC_PYREXIA: case SC_DEATHHURT: case SC_MAGICMUSHROOM: @@ -6528,14 +6595,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //Undead are immune to Freeze/Stone if (undead_flag && !(flag&1)) return 0; - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: case SC_SLEEP: case SC_STUN: - case SC_FREEZING: + case SC_FROSTMISTY: case SC_CRYSTALIZE: if (sc->opt1) return 0; //Cannot override other opt1 status changes. [Skotlex] - if((type == SC_FREEZE || type == SC_FREEZING || type == SC_CRYSTALIZE) && sc->data[SC_WARMER]) + if((type == SC_FREEZE || type == SC_FROSTMISTY || type == SC_CRYSTALIZE) && sc->data[SC_WARMER]) return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] break; @@ -6543,23 +6610,23 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC__BLOODYLUST: if(!sd) return 0; //should only affect player case SC_BERSERK: - if (((type == SC_BERSERK) && (sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC__BLOODYLUST])) - || ((type == SC__BLOODYLUST) && (sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC_BERSERK])) + if (((type == SC_BERSERK) && (sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC__BLOODYLUST])) + || ((type == SC__BLOODYLUST) && (sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC_BERSERK])) ) return 0; break; case SC_BURNING: - if(sc->opt1 || sc->data[SC_FREEZING]) + if(sc->opt1 || sc->data[SC_FROSTMISTY]) return 0; break; - case SC_SIGNUMCRUCIS: + case SC_CRUCIS: //Only affects demons and undead element (but not players) if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC) return 0; break; - case SC_AETERNA: + case SC_LEXAETERNA: if( (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_FREEZE] ) return 0; break; @@ -6568,9 +6635,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; break; case SC_OVERTHRUST: - if (sc->data[SC_MAXOVERTHRUST]) + if (sc->data[SC_OVERTHRUSTMAX]) return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] - case SC_MAXOVERTHRUST: + case SC_OVERTHRUSTMAX: if( sc->option&OPTION_MADOGEAR ) return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] break; @@ -6578,7 +6645,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE))) return 0; if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DECREASEAGI] || + sc->data[SC_DEC_AGI] || sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] ) return 0; @@ -6587,27 +6654,27 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE2))) return 0; if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DECREASEAGI] + sc->data[SC_DEC_AGI] ) return 0; break; case SC_MAGNIFICAT: - if( sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat + if( sc->data[SC_OFFERTORIUM] || sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat return 0; break; - case SC_ONEHAND: - case SC_MERC_QUICKEN: + case SC_ONEHANDQUICKEN: + case SC_MER_QUICKEN: case SC_TWOHANDQUICKEN: - if(sc->data[SC_DECREASEAGI]) + if(sc->data[SC_DEC_AGI]) return 0; - case SC_INCREASEAGI: + case SC_INC_AGI: if(sd && pc_issit(sd)){ pc->setstand(sd); clif->standing(&sd->bl); } - case SC_CONCENTRATE: + case SC_CONCENTRATION: case SC_SPEARQUICKEN: case SC_TRUESIGHT: case SC_WINDWALK: @@ -6648,7 +6715,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } break; //Strip skills, need to divest something or it fails. - case SC_STRIPWEAPON: + case SC_NOEQUIPWEAPON: if (sd && !(flag&4)) { //apply sc anyway if loading saved sc_data int i; opt_flag = 0; //Reuse to check success condition. @@ -6664,7 +6731,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_STRIPSHIELD: + case SC_NOEQUIPSHIELD: if( val2 == 1 ) val2 = 0; //GX effect. Do not take shield off.. else if (sd && !(flag&4)) { @@ -6678,7 +6745,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_STRIPARMOR: + case SC_NOEQUIPARMOR: if (sd && !(flag&4)) { int i; if(sd->bonus.unstripable_equip&EQP_ARMOR) @@ -6690,7 +6757,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_STRIPHELM: + case SC_NOEQUIPHELM: if (sd && !(flag&4)) { int i; if(sd->bonus.unstripable_equip&EQP_HELM) @@ -6702,67 +6769,67 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC break; - case SC_MERC_FLEEUP: - case SC_MERC_ATKUP: - case SC_MERC_HPUP: - case SC_MERC_SPUP: - case SC_MERC_HITUP: + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HP: + case SC_MER_SP: + case SC_MER_HIT: if( bl->type != BL_MER ) return 0; // Stats only for Mercenaries break; - case SC_STRFOOD: + case SC_FOOD_STR: if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1) return 0; break; - case SC_AGIFOOD: + case SC_FOOD_AGI: if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1) return 0; break; - case SC_VITFOOD: + case SC_FOOD_VIT: if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1) return 0; break; - case SC_INTFOOD: + case SC_FOOD_INT: if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1) return 0; break; - case SC_DEXFOOD: + case SC_FOOD_DEX: if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1) return 0; break; - case SC_LUKFOOD: + case SC_FOOD_LUK: if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1) return 0; break; case SC_FOOD_STR_CASH: - if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > val1) + if (sc->data[SC_FOOD_STR] && sc->data[SC_FOOD_STR]->val1 > val1) return 0; break; case SC_FOOD_AGI_CASH: - if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > val1) + if (sc->data[SC_FOOD_AGI] && sc->data[SC_FOOD_AGI]->val1 > val1) return 0; break; case SC_FOOD_VIT_CASH: - if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > val1) + if (sc->data[SC_FOOD_VIT] && sc->data[SC_FOOD_VIT]->val1 > val1) return 0; break; case SC_FOOD_INT_CASH: - if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > val1) + if (sc->data[SC_FOOD_INT] && sc->data[SC_FOOD_INT]->val1 > val1) return 0; break; case SC_FOOD_DEX_CASH: - if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > val1) + if (sc->data[SC_FOOD_DEX] && sc->data[SC_FOOD_DEX]->val1 > val1) return 0; break; case SC_FOOD_LUK_CASH: - if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1) + if (sc->data[SC_FOOD_LUK] && sc->data[SC_FOOD_LUK]->val1 > val1) return 0; break; case SC_CAMOUFLAGE: if( sd && pc->checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill->check_camouflage(bl,NULL) ) return 0; break; - case SC__STRIPACCESSORY: + case SC__STRIPACCESSARY: if( sd ) { int i = -1; if( !(sd->bonus.unstripable_equip&EQI_ACC_L) ) { @@ -6793,10 +6860,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if(sc->data[i]) return 0; } break; - case SC_SATURDAYNIGHTFEVER: + case SC_SATURDAY_NIGHT_FEVER: if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION] || sc->data[SC__BLOODYLUST]) return 0; break; + case SC_OFFERTORIUM: + if (sc->data[SC_MAGNIFICAT]) + return 0; + break; } //Check for BOSS resistances @@ -6805,20 +6876,20 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; switch (type) { case SC_BLESSING: - case SC_DECREASEAGI: + case SC_DEC_AGI: case SC_PROVOKE: case SC_COMA: case SC_GRAVITATION: - case SC_SUITON: + case SC_NJ_SUITON: case SC_RICHMANKIM: case SC_ROKISWEIL: case SC_FOGWALL: - case SC_FREEZING: + case SC_FROSTMISTY: case SC_BURNING: case SC_MARSHOFABYSS: case SC_ADORAMUS: - case SC_PARALYSIS: - case SC_DEEPSLEEP: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEEP_SLEEP: case SC_CRYSTALIZE: // Exploit prevention - kRO Fix @@ -6832,7 +6903,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_LEECHESEND: // Ranger Effects - case SC_BITE: + case SC_WUGBITE: case SC_ELECTRICSHOCKER: case SC_MAGNETICFIELD: @@ -6851,35 +6922,35 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl, SC_STONE, INVALID_TIMER); } break; - case SC_INCREASEAGI: - status_change_end(bl, SC_DECREASEAGI, INVALID_TIMER); + case SC_INC_AGI: + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); break; case SC_QUAGMIRE: - status_change_end(bl, SC_CONCENTRATE, INVALID_TIMER); + status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); status_change_end(bl, SC_WINDWALK, INVALID_TIMER); //Also blocks the ones below... - case SC_DECREASEAGI: + case SC_DEC_AGI: status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); //Also blocks the ones below... case SC_DONTFORGETME: - status_change_end(bl, SC_INCREASEAGI, INVALID_TIMER); + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ONEHAND, INVALID_TIMER); - status_change_end(bl, SC_MERC_QUICKEN, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); break; - case SC_ONEHAND: + case SC_ONEHANDQUICKEN: //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] - status_change_end(bl, SC_ASPDPOTION0, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION1, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION2, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); break; - case SC_MAXOVERTHRUST: + case SC_OVERTHRUSTMAX: //Cancels Normal Overthrust. [Skotlex] status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); break; @@ -6896,18 +6967,18 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl, SC_GOSPEL, INVALID_TIMER); break; case SC_HIDING: - status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); - status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); break; case SC__BLOODYLUST: case SC_BERSERK: if(battle_config.berserk_cancels_buffs) { - status_change_end(bl, SC_ONEHAND, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); status_change_end(bl, SC_PARRYING, INVALID_TIMER); status_change_end(bl, SC_AURABLADE, INVALID_TIMER); - status_change_end(bl, SC_MERC_QUICKEN, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); } #ifdef RENEWAL else { @@ -6923,61 +6994,65 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); break; case SC_CARTBOOST: - if(sc->data[SC_DECREASEAGI]) + if(sc->data[SC_DEC_AGI]) { //Cancel Decrease Agi, but take no further effect [Skotlex] - status_change_end(bl, SC_DECREASEAGI, INVALID_TIMER); + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); return 0; } break; case SC_FUSION: - status_change_end(bl, SC_SPIRIT, INVALID_TIMER); + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; - case SC_ADJUSTMENT: - status_change_end(bl, SC_MADNESSCANCEL, INVALID_TIMER); + case SC_GS_ADJUSTMENT: + status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); break; - case SC_MADNESSCANCEL: - status_change_end(bl, SC_ADJUSTMENT, INVALID_TIMER); + case SC_GS_MADNESSCANCEL: + status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); break; //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up - case SC_CHANGEUNDEAD: + case SC_PROPERTYUNDEAD: status_change_end(bl, SC_BLESSING, INVALID_TIMER); - status_change_end(bl, SC_INCREASEAGI, INVALID_TIMER); + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); break; - case SC_STRFOOD: + case SC_FOOD_STR: status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); break; - case SC_AGIFOOD: + case SC_FOOD_AGI: status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); break; - case SC_VITFOOD: + case SC_FOOD_VIT: status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); break; - case SC_INTFOOD: + case SC_FOOD_INT: status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); break; - case SC_DEXFOOD: + case SC_FOOD_DEX: status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); break; - case SC_LUKFOOD: + case SC_FOOD_LUK: status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); break; case SC_FOOD_STR_CASH: - status_change_end(bl, SC_STRFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); break; case SC_FOOD_AGI_CASH: - status_change_end(bl, SC_AGIFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); break; case SC_FOOD_VIT_CASH: - status_change_end(bl, SC_VITFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); break; case SC_FOOD_INT_CASH: - status_change_end(bl, SC_INTFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); break; case SC_FOOD_DEX_CASH: - status_change_end(bl, SC_DEXFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); break; case SC_FOOD_LUK_CASH: - status_change_end(bl, SC_LUKFOOD, INVALID_TIMER); + status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); + break; + case SC_ENDURE: + if( val4 ) + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); break; case SC_FIGHTINGSPIRIT: status_change_end(bl, type, INVALID_TIMER); // Remove previous one. @@ -6985,57 +7060,57 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_MARSHOFABYSS: status_change_end(bl, SC_INCAGI, INVALID_TIMER); status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION0, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION1, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION2, INVALID_TIMER); - status_change_end(bl, SC_ASPDPOTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); break; - case SC_SWINGDANCE: - case SC_SYMPHONYOFLOVER: - case SC_MOONLITSERENADE: - case SC_RUSHWINDMILL: + case SC_SWING: + case SC_SYMPHONY_LOVE: + case SC_MOONLIT_SERENADE: + case SC_RUSH_WINDMILL: case SC_ECHOSONG: case SC_HARMONIZE: //group A doesn't overlap - if (type != SC_SWINGDANCE) status_change_end(bl, SC_SWINGDANCE, INVALID_TIMER); - if (type != SC_SYMPHONYOFLOVER) status_change_end(bl, SC_SYMPHONYOFLOVER, INVALID_TIMER); - if (type != SC_MOONLITSERENADE) status_change_end(bl, SC_MOONLITSERENADE, INVALID_TIMER); - if (type != SC_RUSHWINDMILL) status_change_end(bl, SC_RUSHWINDMILL, INVALID_TIMER); + if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); + if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); break; - case SC_VOICEOFSIREN: - case SC_DEEPSLEEP: + case SC_SIREN: + case SC_DEEP_SLEEP: case SC_GLOOMYDAY: - case SC_SONGOFMANA: - case SC_DANCEWITHWUG: - case SC_SATURDAYNIGHTFEVER: - case SC_LERADSDEW: + case SC_SONG_OF_MANA: + case SC_DANCE_WITH_WUG: + case SC_SATURDAY_NIGHT_FEVER: + case SC_LERADS_DEW: case SC_MELODYOFSINK: - case SC_BEYONDOFWARCRY: - case SC_UNLIMITEDHUMMINGVOICE: //group B - if (type != SC_VOICEOFSIREN) status_change_end(bl, SC_VOICEOFSIREN, INVALID_TIMER); - if (type != SC_DEEPSLEEP) status_change_end(bl, SC_DEEPSLEEP, INVALID_TIMER); - if (type != SC_LERADSDEW) status_change_end(bl, SC_LERADSDEW, INVALID_TIMER); + case SC_BEYOND_OF_WARCRY: + case SC_UNLIMITED_HUMMING_VOICE: //group B + if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); + if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - if (type != SC_BEYONDOFWARCRY) status_change_end(bl, SC_BEYONDOFWARCRY, INVALID_TIMER); - if (type != SC_UNLIMITEDHUMMINGVOICE) status_change_end(bl, SC_UNLIMITEDHUMMINGVOICE, INVALID_TIMER); + if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); if (type != SC_GLOOMYDAY) { status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); status_change_end(bl, SC_GLOOMYDAY_SK, INVALID_TIMER); } - if (type != SC_SONGOFMANA) status_change_end(bl, SC_SONGOFMANA, INVALID_TIMER); - if (type != SC_DANCEWITHWUG) status_change_end(bl, SC_DANCEWITHWUG, INVALID_TIMER); - if (type != SC_SATURDAYNIGHTFEVER) { - if (sc->data[SC_SATURDAYNIGHTFEVER]) { - sc->data[SC_SATURDAYNIGHTFEVER]->val2 = 0; //mark to not lose hp - status_change_end(bl, SC_SATURDAYNIGHTFEVER, INVALID_TIMER); + if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + if (type != SC_SATURDAY_NIGHT_FEVER) { + if (sc->data[SC_SATURDAY_NIGHT_FEVER]) { + sc->data[SC_SATURDAY_NIGHT_FEVER]->val2 = 0; //mark to not lose hp + status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); } } break; case SC_REFLECTSHIELD: - status_change_end(bl, SC_REFLECTDAMAGE, INVALID_TIMER); + status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); break; - case SC_REFLECTDAMAGE: + case SC_LG_REFLECTDAMAGE: status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); break; case SC_SHIELDSPELL_DEF: @@ -7049,15 +7124,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( type != SC_SHIELDSPELL_REF ) status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); break; - case SC_GT_ENERGYGAIN: - case SC_GT_CHANGE: - case SC_GT_REVITALIZE: - if( type != SC_GT_REVITALIZE ) - status_change_end(bl, SC_GT_REVITALIZE, INVALID_TIMER); - if( type != SC_GT_ENERGYGAIN ) - status_change_end(bl, SC_GT_ENERGYGAIN, INVALID_TIMER); - if( type != SC_GT_CHANGE ) - status_change_end(bl, SC_GT_CHANGE, INVALID_TIMER); + case SC_GENTLETOUCH_ENERGYGAIN: + case SC_GENTLETOUCH_CHANGE: + case SC_GENTLETOUCH_REVITALIZE: + if( type != SC_GENTLETOUCH_REVITALIZE ) + status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); + if( type != SC_GENTLETOUCH_ENERGYGAIN ) + status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); + if( type != SC_GENTLETOUCH_CHANGE ) + status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); break; case SC_INVINCIBLE: status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); @@ -7073,24 +7148,24 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //Check for overlapping fails if( (sce = sc->data[type]) ) { switch( type ) { - case SC_MERC_FLEEUP: - case SC_MERC_ATKUP: - case SC_MERC_HPUP: - case SC_MERC_SPUP: - case SC_MERC_HITUP: + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HP: + case SC_MER_SP: + case SC_MER_HIT: if( sce->val1 > val1 ) val1 = sce->val1; break; case SC_ADRENALINE: case SC_ADRENALINE2: - case SC_WEAPONPERFECTION: + case SC_WEAPONPERFECT: case SC_OVERTHRUST: if (sce->val2 > val2) return 0; break; case SC_S_LIFEPOTION: case SC_L_LIFEPOTION: - case SC_BOSSMAPINFO: + case SC_CASH_BOSS_ALARM: case SC_STUN: case SC_SLEEP: case SC_POISON: @@ -7098,13 +7173,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SILENCE: case SC_CONFUSION: case SC_BLIND: - case SC_BLEEDING: + case SC_BLOODING: case SC_DPOISON: - case SC_CLOSECONFINE2: //Can't be re-closed in. + case SC_RG_CCONFINE_S: //Can't be re-closed in. + case SC_MARIONETTE_MASTER: case SC_MARIONETTE: - case SC_MARIONETTE2: case SC_NOCHAT: - case SC_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. + case SC_HLIF_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. case SC__INVISIBILITY: case SC__ENERVATION: case SC__GROOMY: @@ -7113,17 +7188,17 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC__WEAKNESS: case SC__UNLUCKY: return 0; - case SC_COMBO: + case SC_COMBOATTACK: case SC_DANCING: case SC_DEVOTION: - case SC_ASPDPOTION0: - case SC_ASPDPOTION1: - case SC_ASPDPOTION2: - case SC_ASPDPOTION3: - case SC_ATKPOTION: - case SC_MATKPOTION: + case SC_ATTHASTE_POTION1: + case SC_ATTHASTE_POTION2: + case SC_ATTHASTE_POTION3: + case SC_ATTHASTE_INFINITY: + case SC_PLUSATTACKPOWER: + case SC_PLUSMAGICPOWER: case SC_ENCHANTARMS: - case SC_ARMOR_ELEMENT: + case SC_ARMORPROPERTY: case SC_ARMOR_RESIST: break; case SC_GOSPEL: @@ -7153,7 +7228,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = sce->val3; val4 = sce->val4; break; - case SC_LERADSDEW: + case SC_LERADS_DEW: if (sc && (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) return 0; case SC_SHAPESHIFT: @@ -7178,8 +7253,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val calc_flag = StatusChangeFlagTable[type]; if(!(flag&4)) { //&4 - Do not parse val settings when loading SCs switch(type) { - case SC_DECREASEAGI: - case SC_INCREASEAGI: + case SC_DEC_AGI: + case SC_INC_AGI: val2 = 2 + val1; //Agi change break; case SC_ENDURE: @@ -7209,7 +7284,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sc_start4(bl,SC_PROVOKE,100,10,1,0,0,60000); tick = -1; break; - case SC_SIGNUMCRUCIS: + case SC_CRUCIS: val2 = 10 + 4*val1; //Def reduction tick = -1; clif->emotion(bl,E_SWT); @@ -7220,7 +7295,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_EDP: // [Celest] val2 = val1 + 2; //Chance to Poison enemies. - #ifndef RENEWAL_EDP + #ifdef RENEWAL_EDP + val3 = 50*(val1+3); + val4 = 100 * ((val1 + 1)/2 + 2); + #else val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) #endif if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds @@ -7247,18 +7325,18 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 5; //Lasts 5 hits tick = -1; break; - case SC_ENCPOISON: + case SC_ENCHANTPOISON: val2= 250+50*val1; //Poisoning Chance (2.5+0.5%) in 1/10000 rate case SC_ASPERSIO: - case SC_FIREWEAPON: - case SC_WATERWEAPON: - case SC_WINDWEAPON: - case SC_EARTHWEAPON: - case SC_SHADOWWEAPON: - case SC_GHOSTWEAPON: + case SC_PROPERTYFIRE: + case SC_PROPERTYWATER: + case SC_PROPERTYWIND: + case SC_PROPERTYGROUND: + case SC_PROPERTYDARK: + case SC_PROPERTYTELEKINESIS: skill->enchant_elemental_end(bl,type); break; - case SC_ELEMENTALCHANGE: + case SC_ARMOR_PROPERTY: // val1 : Element Lvl (if called by skill lvl 1, takes random value between 1 and 4) // val2 : Element (When no element, random one is picked) // val3 : 0 = called by skill 1 = called by script (fixed level) @@ -7291,19 +7369,19 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } break; - case SC_STRIPWEAPON: + case SC_NOEQUIPWEAPON: if (!sd) //Watk reduction val2 = 25; break; - case SC_STRIPSHIELD: + case SC_NOEQUIPSHIELD: if (!sd) //Def reduction val2 = 15; break; - case SC_STRIPARMOR: + case SC_NOEQUIPARMOR: if (!sd) //Vit reduction val2 = 40; break; - case SC_STRIPHELM: + case SC_NOEQUIPHELM: if (!sd) //Int reduction val2 = 40; break; @@ -7334,7 +7412,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 0; #endif break; - case SC_SUITON: + case SC_NJ_SUITON: if (!val2 || (sd && (sd->class_&MAPID_BASEMASK) == MAPID_NINJA)) { //No penalties. val2 = 0; //Agi penalty @@ -7345,13 +7423,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 3*((val1+1)/3); if (val1 > 4) val2--; break; - case SC_ONEHAND: + case SC_ONEHANDQUICKEN: case SC_TWOHANDQUICKEN: val2 = 300; if (val1 > 10) //For boss casted skills [Skotlex] val2 += 20*(val1-10); break; - case SC_MERC_QUICKEN: + case SC_MER_QUICKEN: val2 = 300; break; #ifndef RENEWAL_ASPD @@ -7365,24 +7443,28 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //val3 : Brings the skill_lv (merged into val1 here) //val4 : Partner if (val1 == CG_MOONLIT) - clif->status_change(bl,SI_MOONLIT,1,tick,0, 0, 0); + clif->status_change(bl,SI_MOON,1,tick,0, 0, 0); val1|= (val3<<16); val3 = tick/1000; //Tick duration tick_time = 1000; // [GodLesZ] tick time break; case SC_LONGING: + #ifdef RENEWAL + val2 = 50 + 10 * val1; + #else val2 = 500-100*val1; //Aspd penalty. + #endif break; case SC_EXPLOSIONSPIRITS: val2 = 75 + 25*val1; //Cri bonus break; - case SC_ASPDPOTION0: - case SC_ASPDPOTION1: - case SC_ASPDPOTION2: - case SC_ASPDPOTION3: - val2 = 50*(2+type-SC_ASPDPOTION0); - break; + case SC_ATTHASTE_POTION1: + case SC_ATTHASTE_POTION2: + case SC_ATTHASTE_POTION3: + case SC_ATTHASTE_INFINITY: + val2 = 50*(2+type-SC_ATTHASTE_POTION1); + break; case SC_WEDDING: case SC_XMAS: @@ -7407,7 +7489,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = tick/1000; //Petrified HP-damage iterations. if(val3 < 1) val3 = 1; tick = val4; //Petrifying time. - tick = max(tick, 1000); //Min time + if(val4 > 500) // not with WL_SIENNAEXECRATE + tick = max(tick, 1000); //Min time calc_flag = 0; //Actual status changes take effect on petrified state. break; @@ -7439,7 +7522,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CONFUSION: clif->emotion(bl,E_WHAT); break; - case SC_BLEEDING: + case SC_BLOODING: val4 = tick/10000; if (!val4) val4 = 1; tick_time = 10000; // [GodLesZ] tick time @@ -7455,7 +7538,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = 1; tick_time = val2 * 1000; // [GodLesZ] tick time break; - case SC_BOSSMAPINFO: + case SC_CASH_BOSS_ALARM: if( sd != NULL ) { struct mob_data *boss_md = iMap->getmob_boss(bl->m); // Search for Boss on this Map @@ -7479,7 +7562,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CHASEWALK: val2 = tick>0?tick:10000; //Interval at which SP is drained. val3 = 35 - 5 * val1; //Speed adjustment. - if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE) + if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE) val3 -= 40; val4 = 10+val1*2; //SP cost. if (map_flag_gvg(bl->m) || map[bl->m].flag.battleground) val4 *= 5; @@ -7500,24 +7583,24 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_SIGHT: /* splash status */ case SC_RUWACH: - case SC_SIGHTBLASTER: + case SC_WZ_SIGHTBLASTER: val3 = skill->get_splash(val2, val1); //Val2 should bring the skill-id. val2 = tick/250; tick_time = 10; // [GodLesZ] tick time break; //Permanent effects. - case SC_AETERNA: + case SC_LEXAETERNA: case SC_MODECHANGE: - case SC_WEIGHT50: - case SC_WEIGHT90: + case SC_WEIGHTOVER50: + case SC_WEIGHTOVER90: case SC_BROKENWEAPON: case SC_BROKENARMOR: - case SC_READYSTORM: - case SC_READYDOWN: - case SC_READYCOUNTER: - case SC_READYTURN: - case SC_DODGE: + case SC_STORMKICK_READY: + case SC_DOWNKICK_READY: + case SC_COUNTERKICK_READY: + case SC_TURNKICK_READY: + case SC_DODGE_READY: case SC_PUSH_CART: case SC_ALL_RIDING: tick = -1; @@ -7591,7 +7674,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_JOINTBEAT: if( val2&BREAK_NECK ) - sc_start2(bl,SC_BLEEDING,100,val1,val3,skill->get_time2(status_sc2skill(type),val1)); + sc_start2(bl,SC_BLOODING,100,val1,val3,skill->get_time2(status_sc2skill(type),val1)); break; case SC_BERSERK: @@ -7614,7 +7697,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } break; - case SC_MARIONETTE: + case SC_MARIONETTE_MASTER: { int stat; @@ -7628,13 +7711,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val stat = ( sd ? sd->status.luk : status_get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF); break; } - case SC_MARIONETTE2: + case SC_MARIONETTE: { int stat,max_stat; // fetch caster information struct block_list *pbl = iMap->id2bl(val1); struct status_change *psc = pbl?status_get_sc(pbl):NULL; - struct status_change_entry *psce = psc?psc->data[SC_MARIONETTE]:NULL; + struct status_change_entry *psce = psc?psc->data[SC_MARIONETTE_MASTER]:NULL; // fetch target's stats struct status_data* status = status_get_status_data(bl); // battle status @@ -7652,7 +7735,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - status->luk ); val4 |= cap_value(stat,0,0xFF); break; } - case SC_REJECTSWORD: + case SC_SWORDREJECT: val2 = 15*val1; //Reflect chance val3 = 3; //Reflections tick = -1; @@ -7667,7 +7750,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 50*val1; //aspd reduction break; - case SC_REGENERATION: + case SC_GDSKILL_REGENERATION: if (val1 == 1) val2 = 2; else @@ -7706,18 +7789,18 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_zap(bl, status->hp-1, val2?0:status->sp); return 1; break; - case SC_CLOSECONFINE2: + case SC_RG_CCONFINE_S: { struct block_list *src = val2?iMap->id2bl(val2):NULL; struct status_change *sc2 = src?status_get_sc(src):NULL; - struct status_change_entry *sce2 = sc2?sc2->data[SC_CLOSECONFINE]:NULL; + struct status_change_entry *sce2 = sc2?sc2->data[SC_RG_CCONFINE_M]:NULL; if (src && sc2) { if (!sce2) //Start lock on caster. - sc_start4(src,SC_CLOSECONFINE,100,val1,1,0,0,tick+1000); + sc_start4(src,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000); else { //Increase count of locked enemies and refresh time. (sce2->val2)++; iTimer->delete_timer(sce2->timer, status_change_timer); - sce2->timer = iTimer->add_timer(iTimer->gettick()+tick+1000, status_change_timer, src->id, SC_CLOSECONFINE); + sce2->timer = iTimer->add_timer(iTimer->gettick()+tick+1000, status_change_timer, src->id, SC_RG_CCONFINE_M); } } else //Status failed. return 0; @@ -7742,7 +7825,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } break; - case SC_COMBO: { + case SC_COMBOATTACK: { //val1: Skill ID //val2: When given, target (for autotargetting skills) //val3: When set, this combo time should NOT delay attack/movement @@ -7780,7 +7863,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (vd) vd->dead_sit = 1; tick = -1; break; - case SC_CONCENTRATE: + case SC_CONCENTRATION: val2 = 2 + val1; if (sd) { //Store the card-bonus data that should not count in the % val3 = sd->param_bonus[1]; //Agi @@ -7789,7 +7872,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = val4 = 0; } break; - case SC_MAXOVERTHRUST: + case SC_OVERTHRUSTMAX: val2 = 20*val1; //Power increase break; case SC_OVERTHRUST: @@ -7801,14 +7884,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ADRENALINE2: case SC_ADRENALINE: val3 = (val2) ? 300 : 200; // aspd increase - case SC_WEAPONPERFECTION: + case SC_WEAPONPERFECT: if(sd && pc->checkskill(sd,BS_HILTBINDING)>0) tick += tick / 10; break; - case SC_CONCENTRATION: + case SC_LKCONCENTRATION: val2 = 5*val1; //Batk/Watk Increase val3 = 10*val1; //Hit Increase val4 = 5*val1; //Def reduction + sc_start(bl, SC_ENDURE, 100, 1, tick); //Endure effect break; case SC_ANGELUS: val2 = 5*val1; //def increase @@ -7838,7 +7922,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; // gs_something1 [Vicious] - case SC_GATLINGFEVER: + case SC_GS_GATLINGFEVER: val2 = 20*val1; //Aspd increase val3 = 20+10*val1; //Batk increase val4 = 5*val1; //Flee decrease @@ -7856,18 +7940,18 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = 2+3*val1; //Atk increase val4 = 5+5*val1; //Def reduction. break; - case SC_AVOID: + case SC_HLIF_AVOID: //val2 = 10*val1; //Speed change rate. break; - case SC_DEFENCE: + case SC_HAMI_DEFENCE: val2 = 2*val1; //Def bonus break; - case SC_BLOODLUST: + case SC_HAMI_BLOODLUST: val2 = 20+10*val1; //Atk rate change. val3 = 3*val1; //Leech chance val4 = 20; //Leech percent break; - case SC_FLEET: + case SC_HLIF_FLEET: val2 = 30*val1; //Aspd change val3 = 5+5*val1; //bAtk/wAtk rate change break; @@ -7901,14 +7985,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } } break; - case SC_UTSUSEMI: + case SC_NJ_UTSUSEMI: val2=(val1+1)/2; // number of hits blocked val3=skill->get_blewcount(NJ_UTSUSEMI, val1); //knockback value. break; - case SC_BUNSINJYUTSU: + case SC_NJ_BUNSINJYUTSU: val2=(val1+1)/2; // number of hits blocked break; - case SC_CHANGE: + case SC_HLIF_CHANGE: val2= 30*val1; //Vit increase val3= 20*val1; //Int increase break; @@ -7944,7 +8028,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 20*val1; //Magic reflection/cast rate break; - case SC_ARMORCHANGE: + case SC_STONESKIN: if (val2 == NPC_ANTIMAGIC) { //Boost mdef val2 =-20; @@ -7956,32 +8040,32 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2*=val1; //20% per level val3*=val1; break; - case SC_EXPBOOST: - case SC_JEXPBOOST: + case SC_CASH_PLUSEXP: + case SC_CASH_PLUSONLYJOBEXP: if (val1 < 0) val1 = 0; break; - case SC_INCFLEE2: - case SC_INCCRI: + case SC_PLUSAVOIDVALUE: + case SC_CRITICALPERCENT: val2 = val1*10; //Actual boost (since 100% = 1000) break; case SC_SUFFRAGIUM: val2 = 15 * val1; //Speed cast decrease break; - case SC_INCHEALRATE: + case SC_HEALPLUS: if (val1 < 1) val1 = 1; break; - case SC_HALLUCINATION: + case SC_ILLUSION: val2 = 5+val1; //Factor by which displayed damage is increased by break; - case SC_DOUBLECAST: + case SC_DOUBLECASTING: val2 = 30+10*val1; //Trigger rate break; case SC_KAIZEL: val2 = 10*val1; //% of life to be revived with break; - // case SC_ARMOR_ELEMENT: + // case SC_ARMORPROPERTY: // case SC_ARMOR_RESIST: // Mod your resistance against elements: // val1 = water | val2 = earth | val3 = fire | val4 = wind @@ -7991,13 +8075,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //associated, and yet are not wrong/unknown. [Skotlex] //break; - case SC_MERC_FLEEUP: - case SC_MERC_ATKUP: - case SC_MERC_HITUP: + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HIT: val2 = 15 * val1; break; - case SC_MERC_HPUP: - case SC_MERC_SPUP: + case SC_MER_HP: + case SC_MER_SP: val2 = 5 * val1; break; case SC_REBIRTH: @@ -8023,8 +8107,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; // [GodLesZ] tick time break; case SC_BURNING: - val4 = tick / 2000; // Total Ticks to Burn!! - tick_time = 2000; // [GodLesZ] tick time + val4 = tick / 3000; // Total Ticks to Burn!! + tick_time = 3000; // [GodLesZ] tick time break; /** * Rune Knight @@ -8110,24 +8194,27 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_WHITEIMPRISON: status_change_end(bl, SC_BURNING, INVALID_TIMER); - status_change_end(bl, SC_FREEZING, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); status_change_end(bl, SC_FREEZE, INVALID_TIMER); status_change_end(bl, SC_STONE, INVALID_TIMER); break; - case SC_FREEZING: + case SC_MARSHOFABYSS: + val2 = 6 * val1; + if( sd ) // half on players + val2 >>= 1; + break; + case SC_FROSTMISTY: status_change_end(bl, SC_BURNING, INVALID_TIMER); break; case SC_READING_SB: // val2 = sp reduction per second tick_time = 5000; // [GodLesZ] tick time break; - case SC_SPHERE_1: - case SC_SPHERE_2: - case SC_SPHERE_3: - case SC_SPHERE_4: - case SC_SPHERE_5: - if( !sd ) - return 0; // Should only work on players. + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: val4 = tick / 1000; if( val4 < 1 ) val4 = 1; @@ -8168,7 +8255,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; // [GodLesZ] tick time } break; - case SC__STRIPACCESSORY: + case SC__STRIPACCESSARY: if (!sd) val2 = 20; break; @@ -8212,8 +8299,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 10 * val1; val_flag |= 1|2; // bypasses coating protection and MADO - sc_start(bl,SC_STRIPWEAPON,100,val1,tick); - sc_start(bl,SC_STRIPSHIELD,100,val1,tick); + sc_start(bl,SC_NOEQUIPWEAPON,100,val1,tick); + sc_start(bl,SC_NOEQUIPSHIELD,100,val1,tick); break; break; case SC_GN_CARTBOOST: @@ -8230,7 +8317,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_WARMER: status_change_end(bl, SC_FREEZE, INVALID_TIMER); - status_change_end(bl, SC_FREEZING, INVALID_TIMER); + status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); break; case SC_STRIKING: @@ -8238,36 +8325,42 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = tick / 1000; tick_time = 1000; // [GodLesZ] tick time break; - case SC_BLOODSUCKER: - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time + case SC_BLOOD_SUCKER: + { + struct block_list *src = iMap->id2bl(sce->val2); + val3 = 1; + if(src) + val3 = 200 + 100 * sce->val1 + status_get_int(src); + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + } break; case SC_VACUUM_EXTREME: tick -= (status->str / 20) * 1000; val4 = val3 = tick / 100; tick_time = 100; // [GodLesZ] tick time break; - case SC_SWINGDANCE: + case SC_SWING: val2 = 4 * val1; // Walk speed and aspd reduction. break; - case SC_SYMPHONYOFLOVER: - case SC_RUSHWINDMILL: + case SC_SYMPHONY_LOVE: + case SC_RUSH_WINDMILL: case SC_ECHOSONG: val2 = 6 * val1; val2 += val3; //Adding 1% * Lesson Bonus val2 += (int)(val4*2/10); //Adding 0.2% per JobLevel break; - case SC_MOONLITSERENADE: + case SC_MOONLIT_SERENADE: val2 = 10 * val1; break; case SC_HARMONIZE: val2 = 5 + 5 * val1; break; - case SC_VOICEOFSIREN: + case SC_SIREN: val4 = tick / 2000; tick_time = 2000; // [GodLesZ] tick time break; - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: val4 = tick / 2000; tick_time = 2000; // [GodLesZ] tick time break; @@ -8277,12 +8370,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = tick / 1000; tick_time = 1000; // [GodLesZ] tick time break; - case SC_SONGOFMANA: + case SC_SONG_OF_MANA: val3 = 10 + (2 * val2); val4 = tick/3000; tick_time = 3000; // [GodLesZ] tick time break; - case SC_SATURDAYNIGHTFEVER: + case SC_SATURDAY_NIGHT_FEVER: if (!val4) val4 = skill->get_time2(status_sc2skill(type),val1); if (!val4) val4 = 3000; val3 = tick/val4; @@ -8302,7 +8395,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 15 + rand()%( (sd?pc->checkskill(sd, WM_LESSON)*5:0) + val1*10 ); break; case SC_SITDOWN_FORCE: - case SC_BANANA_BOMB_SITDOWN: + case SC_BANANA_BOMB_SITDOWN_POSTDELAY: if( sd && !pc_issit(sd) ) { pc_setsit(sd); @@ -8310,19 +8403,19 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val clif->sitting(bl); } break; - case SC_DANCEWITHWUG: + case SC_DANCE_WITH_WUG: val3 = (5 * val1) + (1 * val2); //Still need official value. break; - case SC_LERADSDEW: + case SC_LERADS_DEW: val3 = (5 * val1) + (1 * val2); break; case SC_MELODYOFSINK: val3 = (5 * val1) + (1 * val2); break; - case SC_BEYONDOFWARCRY: + case SC_BEYOND_OF_WARCRY: val3 = (5 * val1) + (1 * val2); break; - case SC_UNLIMITEDHUMMINGVOICE: + case SC_UNLIMITED_HUMMING_VOICE: { struct unit_data *ud = unit_bl2ud(bl); if( ud == NULL ) return 0; @@ -8330,7 +8423,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = 15 - (2 * val2); } break; - case SC_REFLECTDAMAGE: + case SC_LG_REFLECTDAMAGE: val2 = 15 + 5 * val1; val3 = (val1==5)?20:(val1+4)*2; // SP consumption val4 = tick/10000; @@ -8398,15 +8491,17 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = tick / 5000; tick_time = 5000; // [GodLesZ] tick time break; - case SC_GT_CHANGE: + case SC_GENTLETOUCH_CHANGE: {// take note there is no def increase as skill desc says. [malufett] struct block_list * src; val3 = status->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % - if( (src = iMap->id2bl(val2)) ) + if( (src = iMap->id2bl(val2)) ){ val4 = ( 200/status_get_int(src) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] + val2 = ( status_get_dex(src)/4 + status_get_str(src)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] + } } break; - case SC_GT_REVITALIZE: + case SC_GENTLETOUCH_REVITALIZE: {// take note there is no vit,aspd,speed increase as skill desc says. [malufett] struct block_list * src; val3 = val1 * 30 + 150; // Natural HP recovery increase: [(Skill Level x 30) + 50] % @@ -8519,8 +8614,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 10000; // [GodLesZ] tick time break; case SC_KYOUGAKU: - val2 = 2*val1 + rand()%val1; - clif->status_change(bl,SI_ACTIVE_MONSTER_TRANSFORM,1,0,1002,0,0); + val2 = 2*val1 + rand()%(3 * val1); + clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise break; case SC_KAGEMUSYA: val3 = val1 * 2; @@ -8529,80 +8624,100 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; break; case SC_ZANGETSU: - if( (status_get_hp(bl)+status_get_sp(bl)) % 2 == 0) - val2 = status_get_lv(bl) / 2 + 50; - else - val2 -= 50; + val2 = status_get_lv(bl) / 3 + 20 * val1; + val3 = status_get_lv(bl) / 2 + 30 * val1; + val2 = (!(status_get_hp(bl)%2) ? val2 : -val3); + val3 = (!(status_get_sp(bl)%2) ? val2 : -val3); break; case SC_GENSOU: { - int hp = status_get_hp(bl), lv = 5; - short per = 100 / (status_get_max_hp(bl) / hp); - - if( per <= 15 ) - lv = 1; - else if( per <= 30 ) - lv = 2; - else if( per <= 50 ) - lv = 3; - else if( per <= 75 ) - lv = 4; - if( hp % 2 == 0) - status_heal(bl, hp * (6-lv) * 4 / 100, status_get_sp(bl) * (6-lv) * 3 / 100, 1); - else - status_zap(bl, hp * (lv*4) / 100, status_get_sp(bl) * (lv*3) / 100); + int hp = status_get_hp(bl), sp = status_get_sp(bl), lv = 5; + #define PER( a ) { if( a <= 15 )lv = 1;else if( a <= 30 )lv = 2;else if( a <= 50 )lv = 3;else if( a <= 75 )lv = 4;} + + if( rand()%100 > (25 + 10 * val1) - status_get_int(bl) / 2) + return 0; + + PER( 100 / (status_get_max_hp(bl) / hp) ); + status_heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + + PER( 100 / (status_get_max_sp(bl) / sp) ); + status_heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); } break; - case SC_ANGRIFFS_MODUS: - val2 = 50 + 20 * val1; //atk bonus - val3 = 40 + 20 * val1; // Flee reduction. - val4 = tick/1000; // hp/sp reduction timer - tick_time = 1000; - break; - case SC_NEUTRALBARRIER: - tick_time = tick; - tick = -1; - break; - case SC_GOLDENE_FERSE: - val2 = 10 + 10*val1; //max hp bonus - val3 = 6 + 4 * val1; // Aspd Bonus - val4 = 2 + 2 * val1; // Chance of holy attack - break; - case SC_OVERED_BOOST: - val2 = 300 + 40*val1; //flee bonus - val3 = 179 + 2*val1; //aspd bonus - break; - case SC_GRANITIC_ARMOR: - val2 = 2*val1; //dmg reduction - val3 = 6*val1; //dmg on status end - break; - case SC_MAGMA_FLOW: - val2 = 3*val1; //activation chance - break; - case SC_PYROCLASTIC: - val2 += 10*val1; //atk bonus - break; - case SC_PARALYSIS: //[Lighta] need real info - val2 = 2*val1; //def reduction - val3 = 500*val1; //varcast augmentation - break; - case SC_PAIN_KILLER: //[Lighta] need real info - val2 = 2*val1; //aspd reduction % - val3 = 2*val1; //dmg reduction % - if(sc->data[SC_PARALYSIS]) - sc_start(bl, SC_ENDURE, 100, val1, tick); //start endure for same duration - break; - case SC_STYLE_CHANGE: //[Lighta] need real info - tick = -1; - if(val2 == MH_MD_FIGHTING) val2 = MH_MD_GRAPPLING; - else val2 = MH_MD_FIGHTING; - break; - default: - if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 ) - { //Status change with no calc, no icon, and no skill associated...? - ShowError("UnknownStatusChange [%d]\n", type); - return 0; - } + case SC_ANGRIFFS_MODUS: + val2 = 50 + 20 * val1; //atk bonus + val3 = 40 + 20 * val1; // Flee reduction. + val4 = tick/1000; // hp/sp reduction timer + tick_time = 1000; + break; + case SC_NEUTRALBARRIER: + tick_time = tick; + tick = -1; + break; + case SC_GOLDENE_FERSE: + val2 = 10 + 10*val1; //max hp bonus + val3 = 6 + 4 * val1; // Aspd Bonus + val4 = 2 + 2 * val1; // Chance of holy attack + break; + case SC_OVERED_BOOST: + val2 = 300 + 40*val1; //flee bonus + val3 = 179 + 2*val1; //aspd bonus + break; + case SC_GRANITIC_ARMOR: + val2 = 2*val1; //dmg reduction + val3 = 6*val1; //dmg on status end + break; + case SC_MAGMA_FLOW: + val2 = 3*val1; //activation chance + break; + case SC_PYROCLASTIC: + val2 += 10*val1; //atk bonus + break; + case SC_NEEDLE_OF_PARALYZE: //[Lighta] need real info + val2 = 2*val1; //def reduction + val3 = 500*val1; //varcast augmentation + break; + case SC_PAIN_KILLER: //[Lighta] need real info + val2 = 2*val1; //aspd reduction % + val3 = 2*val1; //dmg reduction % + if(sc->data[SC_NEEDLE_OF_PARALYZE]) + sc_start(bl, SC_ENDURE, 100, val1, tick); //start endure for same duration + break; + case SC_STYLE_CHANGE: //[Lighta] need real info + tick = -1; + if(val2 == MH_MD_FIGHTING) val2 = MH_MD_GRAPPLING; + else val2 = MH_MD_FIGHTING; + break; + case SC_FULL_THROTTLE: + status_percent_heal(bl,100,0); + val2 = 7 - val1; + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_KINGS_GRACE: + val2 = 3 + val1; + tick_time = 1000; + val4 = tick / tick_time; + break; + case SC_TELEKINESIS_INTENSE: + val2 = 10 * val1; + val3 = 40 * val1; + break; + case SC_OFFERTORIUM: + val2 = 30 * val1; + break; + case SC_FRIGG_SONG: + val2 = 5 * val1; + val3 = 1000 + 100 * val1; + tick_time = 10000; + val4 = tick / tick_time; + break; + default: + if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 ) + { //Status change with no calc, no icon, and no skill associated...? + ShowError("UnknownStatusChange [%d]\n", type); + return 0; + } } } else { //Special considerations when loading SC data. switch( type ) { @@ -8619,6 +8734,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_KAAHI: val4 = INVALID_TIMER; break; + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + val_flag |= 1; + break; } } @@ -8642,7 +8764,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_STUN: case SC_SLEEP: case SC_STONE: - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: if (sd && pc_issit(sd)) //Avoid sprite sync problems. pc->setstand(sd); case SC_TRICKDEAD: @@ -8654,12 +8776,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val unit_stop_attack(bl); case SC_STOP: case SC_CONFUSION: - case SC_CLOSECONFINE: - case SC_CLOSECONFINE2: + case SC_RG_CCONFINE_M: + case SC_RG_CCONFINE_S: case SC_SPIDERWEB: case SC_ELECTRICSHOCKER: - case SC_BITE: - case SC_THORNSTRAP: + case SC_WUGBITE: + case SC_THORNS_TRAP: case SC__MANHOLE: case SC_CRYSTALIZE: case SC_CURSEDCIRCLE_ATKER: @@ -8668,10 +8790,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_NETHERWORLD: case SC_MEIKYOUSISUI: case SC_KYOUGAKU: - case SC_PARALYSIS: + case SC_NEEDLE_OF_PARALYZE: + case SC_DEATHBOUND: unit_stop_walking(bl,1); break; - case SC_ANKLE: + case SC_ANKLESNARE: if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) unit_stop_walking(bl,1); break; @@ -8679,9 +8802,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CLOAKING: case SC_CLOAKINGEXCEED: case SC_CHASEWALK: - case SC_WEIGHT90: + case SC_WEIGHTOVER90: case SC_CAMOUFLAGE: - case SC_VOICEOFSIREN: + case SC_SIREN: unit_stop_attack(bl); break; case SC_SILENCE: @@ -8697,7 +8820,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; case SC_STUN: sc->opt1 = OPT1_STUN; break; - case SC_DEEPSLEEP: opt_flag = 0; + case SC_DEEP_SLEEP: opt_flag = 0; case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil] case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break; @@ -8707,24 +8830,24 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; case SC_SILENCE: sc->opt2 |= OPT2_SILENCE; break; - case SC_SIGNUMCRUCIS: + case SC_CRUCIS: sc->opt2 |= OPT2_SIGNUMCRUCIS; break; case SC_BLIND: sc->opt2 |= OPT2_BLIND; break; case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break; - case SC_BLEEDING: sc->opt2 |= OPT2_BLEEDING; break; + case SC_BLOODING: sc->opt2 |= OPT2_BLEEDING; break; case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break; //OPT3 case SC_TWOHANDQUICKEN: - case SC_ONEHAND: + case SC_ONEHANDQUICKEN: case SC_SPEARQUICKEN: - case SC_CONCENTRATION: - case SC_MERC_QUICKEN: + case SC_LKCONCENTRATION: + case SC_MER_QUICKEN: sc->opt3 |= OPT3_QUICKEN; opt_flag = 0; break; - case SC_MAXOVERTHRUST: + case SC_OVERTHRUSTMAX: case SC_OVERTHRUST: case SC_SWOO: //Why does it shares the same opt as Overthrust? Perhaps we'll never know... sc->opt3 |= OPT3_OVERTHRUST; @@ -8772,8 +8895,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sc->opt3 |= OPT3_MOONLIT; opt_flag = 0; break; + case SC_MARIONETTE_MASTER: case SC_MARIONETTE: - case SC_MARIONETTE2: sc->opt3 |= OPT3_MARIONETTE; opt_flag = 0; break; @@ -8789,15 +8912,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sc->opt3 |= OPT3_KAITE; opt_flag = 0; break; - case SC_BUNSINJYUTSU: + case SC_NJ_BUNSINJYUTSU: sc->opt3 |= OPT3_BUNSIN; opt_flag = 0; break; - case SC_SPIRIT: + case SC_SOULLINK: sc->opt3 |= OPT3_SOULLINK; opt_flag = 0; break; - case SC_CHANGEUNDEAD: + case SC_PROPERTYUNDEAD: sc->opt3 |= OPT3_UNDEAD; opt_flag = 0; break; @@ -8911,7 +9034,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } sce->val2 = 5 * status->max_hp / 100; break; - case SC_CHANGE: + case SC_HLIF_CHANGE: status_percent_heal(bl, 100, 100); break; case SC_RUN: @@ -8921,13 +9044,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val ud->state.running = unit_run(bl); } break; - case SC_BOSSMAPINFO: + case SC_CASH_BOSS_ALARM: clif->bossmapinfo(sd->fd, iMap->id2boss(sce->val1), 0); // First Message break; - case SC_MERC_HPUP: + case SC_MER_HP: status_percent_heal(bl, 100, 0); // Recover Full HP break; - case SC_MERC_SPUP: + case SC_MER_SP: status_percent_heal(bl, 0, 100); // Recover Full SP break; /** @@ -8940,7 +9063,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val ud->state.running = unit_wugdash(bl, sd); } break; - case SC_COMBO: + case SC_COMBOATTACK: switch (sce->val1) { case TK_STORMKICK: clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); @@ -9008,68 +9131,25 @@ int status_change_clear(struct block_list* bl, int type) { for(i = 0; i < SC_MAX; i++) { if(!sc->data[i]) continue; - - if(type == 0) { - switch (i) { //Type 0: PC killed -> Place here statuses that do not dispel on death. - case SC_ELEMENTALCHANGE://Only when its Holy or Dark that it doesn't dispell on death - if( sc->data[i]->val2 != ELE_HOLY && sc->data[i]->val2 != ELE_DARK ) - break; - case SC_WEIGHT50: - case SC_WEIGHT90: - case SC_EDP: - case SC_MELTDOWN: - case SC_XMAS: - case SC_SUMMER: - case SC_HANBOK: - case SC_NOCHAT: - case SC_FUSION: - case SC_EARTHSCROLL: - case SC_READYSTORM: - case SC_READYDOWN: - case SC_READYCOUNTER: - case SC_READYTURN: - case SC_DODGE: - case SC_JAILED: - case SC_EXPBOOST: - case SC_ITEMBOOST: - case SC_HELLPOWER: - case SC_JEXPBOOST: - case SC_AUTOTRADE: - case SC_WHISTLE: - case SC_ASSNCROS: - case SC_POEMBRAGI: - case SC_APPLEIDUN: - case SC_HUMMING: - case SC_DONTFORGETME: - case SC_FORTUNE: - case SC_SERVICE4U: - case SC_FOOD_STR_CASH: - case SC_FOOD_AGI_CASH: - case SC_FOOD_VIT_CASH: - case SC_FOOD_DEX_CASH: - case SC_FOOD_INT_CASH: - case SC_FOOD_LUK_CASH: - case SC_DEF_RATE: - case SC_MDEF_RATE: - case SC_INCHEALRATE: - case SC_INCFLEE2: - case SC_INCHIT: - case SC_ATKPOTION: - case SC_MATKPOTION: - case SC_S_LIFEPOTION: - case SC_L_LIFEPOTION: - case SC_PUSH_CART: - case SC_ALL_RIDING: - continue; + + if(type == 0){ + if( status_get_sc_type(i)&SC_NO_REM_DEATH ){ + switch (i) { + case SC_ARMOR_PROPERTY://Only when its Holy or Dark that it doesn't dispell on death + if( sc->data[i]->val2 != ELE_HOLY && sc->data[i]->val2 != ELE_DARK ) + break; + default: + continue; + } } } - if( type == 3 ) { switch (i) {// TODO: This list may be incomplete - case SC_WEIGHT50: - case SC_WEIGHT90: + case SC_WEIGHTOVER50: + case SC_WEIGHTOVER90: case SC_NOCHAT: case SC_PUSH_CART: + case SC_JAILED: case SC_ALL_RIDING: continue; } @@ -9094,6 +9174,7 @@ int status_change_clear(struct block_list* bl, int type) { #ifndef RENEWAL sc->sg_counter = 0; #endif + if( type == 0 || type == 2 ) clif->changeoption(bl); @@ -9188,7 +9269,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const DIFF_TICK(iTimer->gettick(), sce->val4) <= 1000 && (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) ) - sc_start(bl,SC_SPURT,100,sce->val1,skill->get_time2(status_sc2skill(type), sce->val1)); + sc_start(bl,SC_STRUP,100,sce->val1,skill->get_time2(status_sc2skill(type), sce->val1)); } break; case SC_AUTOBERSERK: @@ -9307,7 +9388,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } if((sce->val1&0xFFFF) == CG_MOONLIT) - clif->sc_end(bl,bl->id,AREA,SI_MOONLIT); + clif->sc_end(bl,bl->id,AREA,SI_MOON); status_change_end(bl, SC_LONGING, INVALID_TIMER); } @@ -9328,18 +9409,18 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const skill->castend_damage_id(src, bl, sce->val2, sce->val1, iTimer->gettick(), SD_LEVEL ); } break; - case SC_CLOSECONFINE2: + case SC_RG_CCONFINE_S: { struct block_list *src = sce->val2?iMap->id2bl(sce->val2):NULL; struct status_change *sc2 = src?status_get_sc(src):NULL; - if (src && sc2 && sc2->data[SC_CLOSECONFINE]) { + if (src && sc2 && sc2->data[SC_RG_CCONFINE_M]) { //If status was already ended, do nothing. //Decrease count - if (--(sc2->data[SC_CLOSECONFINE]->val1) <= 0) //No more holds, free him up. - status_change_end(src, SC_CLOSECONFINE, INVALID_TIMER); + if (--(sc2->data[SC_RG_CCONFINE_M]->val1) <= 0) //No more holds, free him up. + status_change_end(src, SC_RG_CCONFINE_M, INVALID_TIMER); } } - case SC_CLOSECONFINE: + case SC_RG_CCONFINE_M: if (sce->val2 > 0) { //Caster has been unlocked... nearby chars need to be unlocked. int range = 1 @@ -9349,7 +9430,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,iTimer->gettick()); } break; - case SC_COMBO: + case SC_COMBOATTACK: if( sd ) switch (sce->val1) { case MO_COMBOFINISH: @@ -9371,11 +9452,11 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; - case SC_MARIONETTE: - case SC_MARIONETTE2: /// Marionette target + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: /// Marionette target if (sce->val1) { // check for partner and end their marionette status as well - enum sc_type type2 = (type == SC_MARIONETTE) ? SC_MARIONETTE2 : SC_MARIONETTE; + enum sc_type type2 = (type == SC_MARIONETTE_MASTER) ? SC_MARIONETTE : SC_MARIONETTE_MASTER; struct block_list *pbl = iMap->id2bl(sce->val1); struct status_change* sc2 = pbl?status_get_sc(pbl):NULL; @@ -9388,7 +9469,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_BERSERK: - case SC_SATURDAYNIGHTFEVER: + case SC_SATURDAY_NIGHT_FEVER: //If val2 is removed, no HP penalty (dispelled?) [Skotlex] if (status->hp > 100 && sce->val2) status_set_hp(bl, 100, 0); @@ -9398,8 +9479,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status_change_end(bl, SC_ENDURE, INVALID_TIMER); } case SC__BLOODYLUST: - sc_start4(bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); - if( type == SC_SATURDAYNIGHTFEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. + sc_start4(bl, SC_GDSKILL_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); + if( type == SC_SATURDAY_NIGHT_FEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. sc_start(bl,SC_SITDOWN_FORCE,100,sce->val1,skill->get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); break; case SC_GOSPEL: @@ -9440,7 +9521,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if(sd && sd->mapindex == sce->val2) pc->setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT); break; //guess hes not in jail :P - case SC_CHANGE: + case SC_HLIF_CHANGE: if (tid == INVALID_TIMER) break; // "lose almost all their HP and SP" on natural expiration. @@ -9466,6 +9547,9 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status_change_end(tbl, SC_STOP, INVALID_TIMER); } break; + case SC_LKCONCENTRATION: + status_change_end(bl, SC_ENDURE, INVALID_TIMER); + break; /** * 3rd Stuff **/ @@ -9552,7 +9636,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } } break; - case SC_BLOODSUCKER: + case SC_BLOOD_SUCKER: if( sce->val2 ){ struct block_list *src = iMap->id2bl(sce->val2); if(src){ @@ -9565,10 +9649,13 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_KYOUGAKU); clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_ACTIVE_MONSTER_TRANSFORM); break; - case SC_INTRAVISION: + case SC_CLAIRVOYANCE: calc_flag = SCB_ALL;/* required for overlapping */ break; - } + case SC_FULL_THROTTLE: + sc_start(bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); + break; + } opt_flag = 1; switch(type){ @@ -9576,7 +9663,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_FREEZE: case SC_STUN: case SC_SLEEP: - case SC_DEEPSLEEP: + case SC_DEEP_SLEEP: case SC_BURNING: case SC_WHITEIMPRISON: case SC_CRYSTALIZE: @@ -9592,7 +9679,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_DPOISON: sc->opt2 &= ~OPT2_DPOISON; break; - case SC_SIGNUMCRUCIS: + case SC_CRUCIS: sc->opt2 &= ~OPT2_SIGNUMCRUCIS; break; @@ -9641,15 +9728,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; //opt3 case SC_TWOHANDQUICKEN: - case SC_ONEHAND: + case SC_ONEHANDQUICKEN: case SC_SPEARQUICKEN: case SC_CONCENTRATION: - case SC_MERC_QUICKEN: + case SC_MER_QUICKEN: sc->opt3 &= ~OPT3_QUICKEN; opt_flag = 0; break; case SC_OVERTHRUST: - case SC_MAXOVERTHRUST: + case SC_OVERTHRUSTMAX: case SC_SWOO: sc->opt3 &= ~OPT3_OVERTHRUST; if( type == SC_SWOO ) @@ -9700,7 +9787,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const opt_flag = 0; break; case SC_MARIONETTE: - case SC_MARIONETTE2: + case SC_MARIONETTE_MASTER: sc->opt3 &= ~OPT3_MARIONETTE; opt_flag = 0; break; @@ -9716,15 +9803,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->opt3 &= ~OPT3_KAITE; opt_flag = 0; break; - case SC_BUNSINJYUTSU: + case SC_NJ_BUNSINJYUTSU: sc->opt3 &= ~OPT3_BUNSIN; opt_flag = 0; break; - case SC_SPIRIT: + case SC_SOULLINK: sc->opt3 &= ~OPT3_SOULLINK; opt_flag = 0; break; - case SC_CHANGEUNDEAD: + case SC_PROPERTYUNDEAD: sc->opt3 &= ~OPT3_UNDEAD; opt_flag = 0; break; @@ -9861,9 +9948,9 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) if(!status_charge(bl, 0, sce->val4)) break; //Not enough SP to continue. - if (!sc->data[SC_INCSTR]) { - sc_start(bl, SC_INCSTR,100,1<<(sce->val1-1), - (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration + if (!sc->data[SC_CHASEWALK2]) { + sc_start(bl, SC_CHASEWALK2,100,1<<(sce->val1-1), + (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration *skill->get_time2(status_sc2skill(type),sce->val1)); } sc_timer_next(sce->val2+tick, status_change_timer, bl->id, data); @@ -9891,8 +9978,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) case SC_SIGHT: case SC_RUWACH: - case SC_SIGHTBLASTER: - if(type == SC_SIGHTBLASTER) + case SC_WZ_SIGHTBLASTER: + if(type == SC_WZ_SIGHTBLASTER) iMap->foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); else iMap->foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); @@ -9970,7 +10057,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_BLEEDING: + case SC_BLOODING: if (--(sce->val4) >= 0) { int hp = rnd()%600 + 200; struct block_list* src = iMap->id2bl(sce->val2); @@ -10005,7 +10092,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_BOSSMAPINFO: + case SC_CASH_BOSS_ALARM: if( sd && --(sce->val4) >= 0 ) { struct mob_data *boss_md = iMap->id2boss(sce->val1); @@ -10112,8 +10199,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; + case SC_MARIONETTE_MASTER: case SC_MARIONETTE: - case SC_MARIONETTE2: { struct block_list *pbl = iMap->id2bl(sce->val1); if( pbl && check_distance_bl(bl, pbl, 7) ) @@ -10160,7 +10247,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_PYREXIA: - if( --(sce->val4) >= 0 ) { + if( --(sce->val4) > 0 ) { iMap->freeblock_lock(); clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); status_fix_damage(NULL,bl,100,0); @@ -10173,7 +10260,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_LEECHESEND: - if( --(sce->val4) >= 0 ) { + if( --(sce->val4) > 0 ) { int damage = status->max_hp/100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) damage += status->vit * (sce->val1 - 3); unit_skillcastcancel(bl,2); @@ -10188,7 +10275,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_MAGICMUSHROOM: - if( --(sce->val4) >= 0 ) { + if( --(sce->val4) > 0 ) { bool flag = 0; int damage = status->max_hp * 3 / 100; if( status->hp <= damage ) @@ -10233,7 +10320,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_TOXIN: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { //Damage is every 10 seconds including 3%sp drain. iMap->freeblock_lock(); clif->damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0); @@ -10247,7 +10334,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_OBLIVIONCURSE: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { clif->emotion(bl,E_WHAT); sc_timer_next(3000 + tick, status_change_timer, bl->id, data ); @@ -10256,7 +10343,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_WEAPONBLOCKING: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( !status_charge(bl,0,3) ) break; @@ -10272,7 +10359,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; case SC_RENOVATIO: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { int heal = status->max_hp * 3 / 100; if( sc && sc->data[SC_AKAITSUKI] && heal ) @@ -10284,7 +10371,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_BURNING: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { struct block_list *src = iMap->id2bl(sce->val3); int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) @@ -10294,7 +10381,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) status_damage(src, bl, damage, 0, 0, 1); if( sc->data[type]){ // Target still lives. [LimitLine] - sc_timer_next(2000 + tick, status_change_timer, bl->id, data); + sc_timer_next(3000 + tick, status_change_timer, bl->id, data); } iMap->freeblock_unlock(); return 0; @@ -10302,7 +10389,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_FEAR: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( sce->val2 > 0 ) sce->val2--; @@ -10311,12 +10398,12 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_SPHERE_1: - case SC_SPHERE_2: - case SC_SPHERE_3: - case SC_SPHERE_4: - case SC_SPHERE_5: - if( --(sce->val4) >= 0 ) + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + if( --(sce->val4) > 0 ) { if( !status_charge(bl, 0, 1) ) break; @@ -10328,7 +10415,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) case SC_READING_SB: if( !status_charge(bl, 0, sce->val2) ){ int i; - for(i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) // Also remove stored spell as well. + for(i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) // Also remove stored spell as well. status_change_end(bl, (sc_type)i, INVALID_TIMER); break; } @@ -10336,7 +10423,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; case SC_ELECTRICSHOCKER: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { status_charge(bl, 0, status->max_sp / 100 * sce->val1 ); sc_timer_next(1000 + tick, status_change_timer, bl->id, data); @@ -10359,7 +10446,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; case SC__SHADOWFORM: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( !status_charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) break; @@ -10369,7 +10456,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC__INVISIBILITY: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( !status_charge(bl, 0, (status->sp * 6 - sce->val1) / 100) )// 6% - skill_lv. break; @@ -10379,7 +10466,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_STRIKING: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( !status_charge(bl,0, sce->val1 ) ) break; @@ -10388,19 +10475,19 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; case SC_VACUUM_EXTREME: - if( --(sce->val4) >= 0 ){ + if( --(sce->val4) > 0 ){ sc_timer_next(100 + tick, status_change_timer, bl->id, data); return 0; } break; - case SC_BLOODSUCKER: - if( --(sce->val4) >= 0 ) { + case SC_BLOOD_SUCKER: + if( --(sce->val4) > 0 ) { struct block_list *src = iMap->id2bl(sce->val2); int damage; if( !src || (src && (status_isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) break; iMap->freeblock_lock(); - damage = 200 + 100 * sce->val1 + status_get_int(src); + damage = sce->val3; status_damage(src, bl, damage, 0, clif->damage(bl,bl,tick,status->amotion,status->dmotion+200,damage,1,0,0), 1); unit_skillcastcancel(bl,1); if ( sc->data[type] ) { @@ -10412,8 +10499,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_VOICEOFSIREN: - if( --(sce->val4) >= 0 ) + case SC_SIREN: + if( --(sce->val4) > 0 ) { clif->emotion(bl,E_LV); sc_timer_next(2000 + tick, status_change_timer, bl->id, data); @@ -10421,8 +10508,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_DEEPSLEEP: - if( --(sce->val4) >= 0 ) + case SC_DEEP_SLEEP: + if( --(sce->val4) > 0 ) { // Recovers 1% HP/SP every 2 seconds. status_heal(bl, status->max_hp / 100, status->max_sp / 100, 2); sc_timer_next(2000 + tick, status_change_timer, bl->id, data); @@ -10431,7 +10518,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_SIRCLEOFNATURE: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { if( !status_charge(bl,0,sce->val2) ) break; @@ -10441,8 +10528,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_SONGOFMANA: - if( --(sce->val4) >= 0 ) + case SC_SONG_OF_MANA: + if( --(sce->val4) > 0 ) { status_heal(bl,0,sce->val3,3); sc_timer_next(3000 + tick, status_change_timer, bl->id, data); @@ -10451,9 +10538,9 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; - case SC_SATURDAYNIGHTFEVER: + case SC_SATURDAY_NIGHT_FEVER: // 1% HP/SP drain every val4 seconds [Jobbie] - if( --(sce->val3) >= 0 ) + if( --(sce->val3) > 0 ) { int hp = status->hp / 100; int sp = status->sp / 100; @@ -10465,7 +10552,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_CRYSTALIZE: - if( --(sce->val4) >= 0 ) + if( --(sce->val4) > 0 ) { // Drains 2% of HP and 1% of SP every seconds. if( bl->type != BL_MOB) // doesn't work on mobs status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100); @@ -10489,8 +10576,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; - case SC_REFLECTDAMAGE: - if( --(sce->val4) >= 0 ) { + case SC_LG_REFLECTDAMAGE: + if( --(sce->val4) > 0 ) { if( !status_charge(bl,0,sce->val3) ) break; sc_timer_next(10000 + tick, status_change_timer, bl->id, data); @@ -10538,7 +10625,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_INSPIRATION: - if(--(sce->val4) >= 0) + if(--(sce->val4) > 0) { int hp = status->max_hp * (7-sce->val1) / 100; int sp = status->max_sp * (9-sce->val1) / 100; @@ -10615,12 +10702,36 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } break; case SC_ANGRIFFS_MODUS: - if(--(sce->val4) >= 0) { //drain hp/sp + if(--(sce->val4) > 0) { //drain hp/sp if( !status_charge(bl,100,20) ) break; sc_timer_next(1000+tick,status_change_timer,bl->id, data); return 0; } break; + case SC_FULL_THROTTLE: + if( --(sce->val4) > 0 ) + { + status_percent_damage(bl, bl, sce->val2, 0, false); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + case SC_KINGS_GRACE: + if( --(sce->val4) > 0 ) + { + status_percent_heal(bl, sce->val2, 0); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; + case SC_FRIGG_SONG: + if( --(sce->val4) > 0 ) + { + status_heal(bl, sce->val3, 0, 0); + sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; } // default for all non-handled control paths is to end the status @@ -10650,7 +10761,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - case SC_CONCENTRATE: + case SC_CONCENTRATION: status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); @@ -10673,7 +10784,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); break; - case SC_SIGHTBLASTER: + case SC_WZ_SIGHTBLASTER: if (battle->check_target( src, bl, BCT_ENEMY ) > 0 && status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2)) { @@ -10683,11 +10794,11 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) } } break; - case SC_CLOSECONFINE: + case SC_RG_CCONFINE_M: //Lock char has released the hold on everyone... - if (tsc && tsc->data[SC_CLOSECONFINE2] && tsc->data[SC_CLOSECONFINE2]->val2 == src->id) { - tsc->data[SC_CLOSECONFINE2]->val2 = 0; - status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); + if (tsc && tsc->data[SC_RG_CCONFINE_S] && tsc->data[SC_RG_CCONFINE_S]->val2 == src->id) { + tsc->data[SC_RG_CCONFINE_S]->val2 = 0; + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); } break; case SC_CURSEDCIRCLE_TARGET: @@ -10700,6 +10811,131 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) return 0; } +#ifdef RENEWAL +int status_get_total_def(struct block_list *src){ return status_get_status_data(src)->def2 + (short)status_get_def(src); } +int status_get_total_mdef(struct block_list *src){ return status_get_status_data(src)->mdef2 + (short)status_get_mdef(src); } +int status_get_weapon_atk(struct block_list *bl, struct weapon_atk *watk, int flag){ + int min = 0, max = 0, dstr; + float strdex_bonus, variance; + struct status_change *sc = status_get_sc(bl); + struct status_data *status = status_get_status_data(bl); + + if ( bl->type == BL_PC && watk->atk ){ + if ( flag&16 ) + dstr = status_get_dex(bl); + else + dstr = status_get_str(bl); + + variance = 5.0f * watk->atk * watk->wlv / 100.0f; + strdex_bonus = watk->atk * dstr / 200.0f; + + min = (watk->atk - (int)(variance + strdex_bonus)) + watk->atk2; + max = (watk->atk + (int)(variance + strdex_bonus)) + watk->atk2; + }else if( watk->atk ){ + min = watk->atk * 80 / 100; + max = watk->atk * 120 / 100; + } + + if( !(flag&1) ){ + if( max > min ) + max = min + rnd()%(max - min); + else + max = min; + } + + if( bl->type == BL_PC && ((TBL_PC*)bl)->right_weapon.overrefine > 0) + max += rnd()%((TBL_PC*)bl)->right_weapon.overrefine + 1; + + max = status_calc_watk(bl, sc, max, false); + + return max; +} +#endif + +#define GETRANDMATK(){\ + if( status->matk_max > status->matk_min )\ + return status->matk_min + rnd()%(status->matk_max - status->matk_min);\ + else\ + return status->matk_min;\ +} + +/*========================================== + * flag [malufett] + * 0 - update matk values + * 1 - get matk w/o SC bonuses + * 2 - get modified matk + * 3 - get matk w/o eatk & SC bonuses + *------------------------------------------*/ +int status_get_matk(struct block_list *bl, int flag){ + struct status_data *status; + struct status_change *sc; + struct map_session_data *sd; + + if( bl == NULL ) + return 1; + + status = status_get_status_data(bl); + sc = status_get_sc(bl); + sd = BL_CAST(BL_PC, bl); + + if( flag == 2 ) // just get matk + GETRANDMATK(); + +#ifndef RENEWAL + status->matk_min = status_base_matk_min(status) + (sd?sd->bonus.ematk:0); + status->matk_max = status_base_matk_max(status) + (sd?sd->bonus.ematk:0); +#else + /** + * RE MATK Formula (from irowiki:http://irowiki.org/wiki/MATK) + * MATK = (sMATK + wMATK + eMATK) * Multiplicative Modifiers + **/ + status->matk_min = status_base_matk(status, status_get_lv(bl)); + + // Any +MATK you get from skills and cards, including cards in weapon, is added here. + if( sd && sd->bonus.ematk > 0 && flag != 3 ) + status->matk_min += sd->bonus.ematk; + if( flag != 3 ) + status->matk_min = status_calc_ematk(bl, sc, status->matk_min); + + status->matk_max = status->matk_min; + + //This is the only portion in MATK that varies depending on the weapon level and refinement rate. + if( bl->type&BL_PC && (status->rhw.matk + status->lhw.matk) > 0 ){ + int wMatk = status->rhw.matk + status->lhw.matk; // Left and right matk stacks + int variance = wMatk * status->rhw.wlv / 10; // Only use right hand weapon level + status->matk_min += wMatk - variance; + status->matk_max += wMatk + variance; + }else if( bl->type&BL_MOB ){ + status->matk_min = status->matk_max = status_get_int(bl) + status_get_lv(bl); + status->matk_min += 70 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; + status->matk_max += 130 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; + } +#endif + if (bl->type&BL_PC && sd->matk_rate != 100) { + status->matk_max = status->matk_max * sd->matk_rate/100; + status->matk_min = status->matk_min * sd->matk_rate/100; + } + + if ((bl->type&BL_HOM && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk + || sc->data[SC_RECOGNIZEDSPELL]) + status->matk_min = status->matk_max; + +#ifdef RENEWAL + if( sd && sd->right_weapon.overrefine > 0){ + status->matk_min++; + status->matk_max += sd->right_weapon.overrefine - 1; + } +#endif + + if( flag ) // get unmodified from sc matk + GETRANDMATK(); + + status->matk_min = status_calc_matk(bl, sc, status->matk_min, true); + status->matk_max = status_calc_matk(bl, sc, status->matk_max, true); + + return 0; +} + /*========================================== * Clears buffs/debuffs of a character. * type&1 -> buffs, type&2 -> debuffs @@ -10719,70 +10955,18 @@ int status_change_clear_buffs (struct block_list* bl, int type) for( i = SC_COMMON_MAX+1; i < SC_MAX; i++ ) { - if(!sc->data[i]) + if( !sc->data[i] || !status_get_sc_type(i) ) continue; - switch (i) { - //Stuff that cannot be removed - case SC_WEIGHT50: - case SC_WEIGHT90: - case SC_COMBO: - case SC_SMA: - case SC_DANCING: - case SC_LEADERSHIP: - case SC_GLORYWOUNDS: - case SC_SOULCOLD: - case SC_HAWKEYES: - case SC_GUILDAURA: - case SC_SAFETYWALL: - case SC_PNEUMA: - case SC_NOCHAT: - case SC_JAILED: - case SC_ANKLE: - case SC_BLADESTOP: - case SC_CP_WEAPON: - case SC_CP_SHIELD: - case SC_CP_ARMOR: - case SC_CP_HELM: - case SC_STRFOOD: - case SC_AGIFOOD: - case SC_VITFOOD: - case SC_INTFOOD: - case SC_DEXFOOD: - case SC_LUKFOOD: - case SC_HITFOOD: - case SC_FLEEFOOD: - case SC_BATKFOOD: - case SC_WATKFOOD: - case SC_MATKFOOD: - case SC_FOOD_STR_CASH: - case SC_FOOD_AGI_CASH: - case SC_FOOD_VIT_CASH: - case SC_FOOD_DEX_CASH: - case SC_FOOD_INT_CASH: - case SC_FOOD_LUK_CASH: - case SC_EXPBOOST: - case SC_JEXPBOOST: - case SC_ITEMBOOST: - case SC_ELECTRICSHOCKER: - case SC__MANHOLE: - case SC_GIANTGROWTH: - case SC_MILLENNIUMSHIELD: - case SC_REFRESH: - case SC_STONEHARDSKIN: - case SC_VITALITYACTIVATION: - case SC_FIGHTINGSPIRIT: - case SC_ABUNDANCE: - case SC_CURSEDCIRCLE_ATKER: - case SC_CURSEDCIRCLE_TARGET: - case SC_PUSH_CART: - case SC_ALL_RIDING: - continue; + if( type&1 && !(status_get_sc_type(i)&SC_BUFF) ) + continue; - //Debuffs that can be removed. - case SC_DEEPSLEEP: - case SC_BURNING: - case SC_FREEZING: + if( type&2 && !(status_get_sc_type(i)&SC_DEBUFF) ) + continue; + + switch (i) { + case SC_DEEP_SLEEP: + case SC_FROSTMISTY: case SC_CRYSTALIZE: case SC_TOXIN: case SC_PARALYSE: @@ -10797,40 +10981,13 @@ int status_change_clear_buffs (struct block_list* bl, int type) if(!(type&4)) continue; break; - case SC_HALLUCINATION: - case SC_QUAGMIRE: - case SC_SIGNUMCRUCIS: - case SC_DECREASEAGI: - case SC_SLOWDOWN: - case SC_MINDBREAKER: - case SC_WINKCHARM: - case SC_STOP: - case SC_ORCISH: - case SC_STRIPWEAPON: - case SC_STRIPSHIELD: - case SC_STRIPARMOR: - case SC_STRIPHELM: - case SC_BITE: - case SC_ADORAMUS: - case SC_VACUUM_EXTREME: - case SC_FEAR: - case SC_MAGNETICFIELD: - case SC_NETHERWORLD: - if (!(type&2)) - continue; - break; - //The rest are buffs that can be removed. case SC__BLOODYLUST: case SC_BERSERK: - case SC_SATURDAYNIGHTFEVER: - if (!(type&1)) + case SC_SATURDAY_NIGHT_FEVER: + if(type&4) continue; sc->data[i]->val2 = 0; break; - default: - if (!(type&1)) - continue; - break; } status_change_end(bl, (sc_type)i, INVALID_TIMER); } @@ -10861,21 +11018,21 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { case SC_CONFUSION: case SC_BLIND: case SC_NOCHAT: - case SC_HALLUCINATION: - case SC_SIGNUMCRUCIS: - case SC_DECREASEAGI: + case SC_ILLUSION: + case SC_CRUCIS: + case SC_DEC_AGI: case SC_SLOWDOWN: case SC_MINDBREAKER: - case SC_WINKCHARM: + case SC_DC_WINKCHARM: case SC_STOP: case SC_ORCISH: - //case SC_STRIPWEAPON://Omg I got infected and had the urge to strip myself physically. - //case SC_STRIPSHIELD://No this is stupid and shouldnt be spreadable at all. - //case SC_STRIPARMOR:// Disabled until I can confirm if it does or not. [Rytech] - //case SC_STRIPHELM: - //case SC__STRIPACCESSORY: - case SC_BITE: - case SC_FREEZING: + //case SC_NOEQUIPWEAPON://Omg I got infected and had the urge to strip myself physically. + //case SC_NOEQUIPSHIELD://No this is stupid and shouldnt be spreadable at all. + //case SC_NOEQUIPARMOR:// Disabled until I can confirm if it does or not. [Rytech] + //case SC_NOEQUIPHELM: + //case SC__STRIPACCESSARY: + case SC_WUGBITE: + case SC_FROSTMISTY: case SC_VENOMBLEED: case SC_DEATHHURT: case SC_PARALYSE: @@ -10907,7 +11064,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { data.tick = sc->data[i]->val4 * 4000; break; case SC_TOXIN: - case SC_BLEEDING: + case SC_BLOODING: data.tick = sc->data[i]->val4 * 10000; break; default: @@ -11142,6 +11299,13 @@ int status_get_refine_chance(enum refine_type wlv, int refine) { return refine_info[wlv].chance[refine]; } +int status_get_sc_type(sc_type type) { + + if( type <= SC_NONE || type >= SC_MAX ) + return 0; + + return sc_conf[type]; +} /*------------------------------------------ * DB reading. @@ -11244,6 +11408,20 @@ static bool status_readdb_refine(char* fields[], int columns, int current) return true; } +static bool status_readdb_scconfig(char* fields[], int columns, int current) +{ + int val = 0; + char* type = fields[0]; + + if( !script_get_constant(type, &val) ){ + ShowWarning("status_readdb_sc_conf: Invalid status type %s specified.\n", type); + return false; + } + + sc_conf[val] = (int)strtol(fields[1], NULL, 0); + + return true; +} /* * Read status db * job1.txt @@ -11295,6 +11473,7 @@ int status_readdb(void) sv->readdb(iMap->db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2); sv->readdb(iMap->db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix); sv->readdb(iMap->db_path, DBPATH"refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(refine_info), &status_readdb_refine); + sv->readdb(iMap->db_path, "sc_config.txt", ',', 2, 2, SC_MAX, &status_readdb_scconfig); return 0; } diff --git a/src/map/status.h b/src/map/status.h index 4a7af884e..617cd9572 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -31,6 +31,16 @@ enum refine_type { REFINE_TYPE_MAX = 5 }; +typedef enum sc_conf_type { + SC_NO_REM_DEATH = 0x1, + SC_NO_SAVE = 0x2, + SC_NO_DISPELL = 0x4, + SC_NO_CLEARANCE = 0x8, + SC_BUFF = 0x10, + SC_DEBUFF = 0x20, + SC_MADO_NO_RESET = 0x40 +} sc_conf_type; + int status_get_refine_chance(enum refine_type wlv, int refine); // Status changes listing. These code are for use by the server. @@ -48,25 +58,26 @@ typedef enum sc_type { SC_SILENCE, SC_CONFUSION, SC_BLIND, - SC_BLEEDING, - SC_DPOISON, //10 - SC_COMMON_MAX = 10, // end + SC_BLOODING, + SC_DPOISON, + SC_BURNING, //11 + SC_COMMON_MAX = 11, // end //Next up, we continue on 20, to leave enough room for additional "common" ailments in the future. SC_PROVOKE = 20, SC_ENDURE, SC_TWOHANDQUICKEN, - SC_CONCENTRATE, + SC_CONCENTRATION, SC_HIDING, SC_CLOAKING, - SC_ENCPOISON, + SC_ENCHANTPOISON, SC_POISONREACT, SC_QUAGMIRE, SC_ANGELUS, SC_BLESSING, //30 - SC_SIGNUMCRUCIS, - SC_INCREASEAGI, - SC_DECREASEAGI, + SC_CRUCIS, + SC_INC_AGI, + SC_DEC_AGI, SC_SLOWPOISON, SC_IMPOSITIO , SC_SUFFRAGIUM, @@ -75,40 +86,40 @@ typedef enum sc_type { SC_KYRIE, SC_MAGNIFICAT, //40 SC_GLORIA, - SC_AETERNA, + SC_LEXAETERNA, SC_ADRENALINE, - SC_WEAPONPERFECTION, + SC_WEAPONPERFECT, SC_OVERTHRUST, SC_MAXIMIZEPOWER, SC_TRICKDEAD, - SC_LOUD, + SC_SHOUT, SC_ENERGYCOAT, SC_BROKENARMOR, //50 - NOTE: These two aren't used anywhere, and they have an icon... SC_BROKENWEAPON, - SC_HALLUCINATION, - SC_WEIGHT50, - SC_WEIGHT90, - SC_ASPDPOTION0, - SC_ASPDPOTION1, - SC_ASPDPOTION2, - SC_ASPDPOTION3, - SC_SPEEDUP0, - SC_SPEEDUP1, //60 - SC_ATKPOTION, - SC_MATKPOTION, + SC_ILLUSION, + SC_WEIGHTOVER50, + SC_WEIGHTOVER90, + SC_ATTHASTE_POTION1, + SC_ATTHASTE_POTION2, + SC_ATTHASTE_POTION3, + SC_ATTHASTE_INFINITY, + SC_MOVHASTE_HORSE, + SC_MOVHASTE_INFINITY, //60 + SC_PLUSATTACKPOWER, + SC_PLUSMAGICPOWER, SC_WEDDING, SC_SLOWDOWN, - SC_ANKLE, + SC_ANKLESNARE, SC_KEEPING, SC_BARRIER, - SC_STRIPWEAPON, - SC_STRIPSHIELD, - SC_STRIPARMOR, //70 - SC_STRIPHELM, - SC_CP_WEAPON, - SC_CP_SHIELD, - SC_CP_ARMOR, - SC_CP_HELM, + SC_NOEQUIPWEAPON, + SC_NOEQUIPSHIELD, + SC_NOEQUIPARMOR, //70 + SC_NOEQUIPHELM, + SC_PROTECTWEAPON, + SC_PROTECTSHIELD, + SC_PROTECTARMOR, + SC_PROTECTHELM, SC_AUTOGUARD, SC_REFLECTSHIELD, SC_SPLASHER, @@ -126,24 +137,24 @@ typedef enum sc_type { SC_RUWACH, //90 SC_EXTREMITYFIST, SC_EXPLOSIONSPIRITS, - SC_COMBO, + SC_COMBOATTACK, SC_BLADESTOP_WAIT, SC_BLADESTOP, - SC_FIREWEAPON, - SC_WATERWEAPON, - SC_WINDWEAPON, - SC_EARTHWEAPON, + SC_PROPERTYFIRE, + SC_PROPERTYWATER, + SC_PROPERTYWIND, + SC_PROPERTYGROUND, SC_VOLCANO, //100, SC_DELUGE, SC_VIOLENTGALE, SC_WATK_ELEMENT, SC_ARMOR, - SC_ARMOR_ELEMENT, + SC_ARMORPROPERTY, SC_NOCHAT, SC_BABY, SC_AURABLADE, SC_PARRYING, - SC_CONCENTRATION, //110 + SC_LKCONCENTRATION, //110 SC_TENSIONRELAX, SC_BERSERK, SC_FURY, @@ -158,10 +169,10 @@ typedef enum sc_type { SC_MELTDOWN, SC_CARTBOOST, SC_CHASEWALK, - SC_REJECTSWORD, + SC_SWORDREJECT, + SC_MARIONETTE_MASTER, SC_MARIONETTE, - SC_MARIONETTE2, - SC_CHANGEUNDEAD, + SC_PROPERTYUNDEAD, SC_JOINTBEAT, SC_MINDBREAKER, //130 SC_MEMORIZE, @@ -171,39 +182,40 @@ typedef enum sc_type { SC_SACRIFICE, SC_STEELBODY, SC_ORCISH, - SC_READYSTORM, - SC_READYDOWN, - SC_READYTURN, //140 - SC_READYCOUNTER, - SC_DODGE, + SC_STORMKICK_READY, + SC_DOWNKICK_READY, + SC_TURNKICK_READY, //140 + SC_COUNTERKICK_READY, + SC_DODGE_READY, SC_RUN, - SC_SHADOWWEAPON, + SC_PROPERTYDARK, SC_ADRENALINE2, - SC_GHOSTWEAPON, + SC_PROPERTYTELEKINESIS, SC_KAIZEL, SC_KAAHI, SC_KAUPE, - SC_ONEHAND, //150 + SC_ONEHANDQUICKEN, //150 SC_PRESERVE, - SC_BATTLEORDERS, - SC_REGENERATION, - SC_DOUBLECAST, + SC_GDSKILL_BATTLEORDER, + SC_GDSKILL_REGENERATION, + SC_DOUBLECASTING, SC_GRAVITATION, - SC_MAXOVERTHRUST, + SC_OVERTHRUSTMAX, SC_LONGING, SC_HERMODE, - SC_SHRINK, - SC_SIGHTBLASTER, //160 - SC_WINKCHARM, - SC_CLOSECONFINE, - SC_CLOSECONFINE2, + SC_TAROTCARD, + SC_CR_SHRINK, //160 + SC_WZ_SIGHTBLASTER, + SC_DC_WINKCHARM, + SC_RG_CCONFINE_M, + SC_RG_CCONFINE_S, SC_DANCING, - SC_ELEMENTALCHANGE, + SC_ARMOR_PROPERTY, SC_RICHMANKIM, SC_ETERNALCHAOS, SC_DRUMBATTLE, - SC_NIBELUNGEN, - SC_ROKISWEIL, //170 + SC_NIBELUNGEN, //170 + SC_ROKISWEIL, SC_INTOABYSS, SC_SIEGFRIED, SC_WHISTLE, @@ -212,18 +224,18 @@ typedef enum sc_type { SC_APPLEIDUN, SC_MODECHANGE, SC_HUMMING, - SC_DONTFORGETME, - SC_FORTUNE, //180 - SC_SERVICE4U, + SC_DONTFORGETME, //180 + SC_FORTUNE, + SC_SERVICEFORYOU, SC_STOP, //Prevents inflicted chars from walking. [Skotlex] - SC_SPURT, - SC_SPIRIT, + SC_STRUP, + SC_SOULLINK, SC_COMA, //Not a real SC_, it makes a char's HP/SP hit 1. - SC_INTRAVISION, + SC_CLAIRVOYANCE, SC_INCALLSTATUS, - SC_INCSTR, - SC_INCAGI, - SC_INCVIT, //190 + SC_CHASEWALK2, + SC_INCAGI, //190 + SC_INCVIT, SC_INCINT, SC_INCDEX, SC_INCLUK, @@ -232,18 +244,18 @@ typedef enum sc_type { SC_INCFLEE, SC_INCFLEERATE, SC_INCMHPRATE, - SC_INCMSPRATE, - SC_INCATKRATE, //200 + SC_INCMSPRATE, //200 + SC_INCATKRATE, SC_INCMATKRATE, SC_INCDEFRATE, - SC_STRFOOD, - SC_AGIFOOD, - SC_VITFOOD, - SC_INTFOOD, - SC_DEXFOOD, - SC_LUKFOOD, - SC_HITFOOD, - SC_FLEEFOOD, //210 + SC_FOOD_STR, + SC_FOOD_AGI, + SC_FOOD_VIT, + SC_FOOD_INT, + SC_FOOD_DEX, + SC_FOOD_LUK, + SC_FOOD_BASICHIT, //210 + SC_FOOD_BASICAVOIDANCE, SC_BATKFOOD, SC_WATKFOOD, SC_MATKFOOD, @@ -252,8 +264,8 @@ typedef enum sc_type { SC_WARM, //SG skills [Komurka] SC_SUN_COMFORT, SC_MOON_COMFORT, - SC_STAR_COMFORT, - SC_FUSION, //220 + SC_STAR_COMFORT, //220 + SC_FUSION, SC_SKILLRATE_UP, SC_SKE, SC_KAITE, @@ -261,82 +273,82 @@ typedef enum sc_type { SC_SKA, // [marquis007] SC_EARTHSCROLL, SC_MIRACLE, //SG 'hidden' skill [Komurka] - SC_MADNESSCANCEL, - SC_ADJUSTMENT, - SC_INCREASING, //230 - SC_GATLINGFEVER, - SC_TATAMIGAESHI, - SC_UTSUSEMI, - SC_BUNSINJYUTSU, - SC_KAENSIN, - SC_SUITON, - SC_NEN, + SC_GS_MADNESSCANCEL, + SC_GS_ADJUSTMENT, //230 + SC_GS_ACCURACY, + SC_GS_GATLINGFEVER, + SC_NJ_TATAMIGAESHI, + SC_NJ_UTSUSEMI, + SC_NJ_BUNSINJYUTSU, + SC_NJ_KAENSIN, + SC_NJ_SUITON, + SC_NJ_NEN, SC_KNOWLEDGE, - SC_SMA, - SC_FLING, //240 - SC_AVOID, - SC_CHANGE, - SC_BLOODLUST, - SC_FLEET, - SC_SPEED, - SC_DEFENCE, + SC_SMA_READY, //240 + SC_FLING, + SC_HLIF_AVOID, + SC_HLIF_CHANGE, + SC_HAMI_BLOODLUST, + SC_HLIF_FLEET, + SC_HLIF_SPEED, + SC_HAMI_DEFENCE, SC_INCASPDRATE, - SC_INCFLEE2 = 248, - SC_JAILED, - SC_ENCHANTARMS, //250 + SC_PLUSAVOIDVALUE, + SC_JAILED, //250 + SC_ENCHANTARMS, SC_MAGICALATTACK, - SC_ARMORCHANGE, + SC_STONESKIN, SC_CRITICALWOUND, SC_MAGICMIRROR, SC_SLOWCAST, SC_SUMMER, - SC_EXPBOOST, - SC_ITEMBOOST, - SC_BOSSMAPINFO, - SC_LIFEINSURANCE, //260 - SC_INCCRI, + SC_CASH_PLUSEXP, + SC_CASH_RECEIVEITEM, + SC_CASH_BOSS_ALARM, //260 + SC_CASH_DEATHPENALTY, + SC_CRITICALPERCENT, //SC_INCDEF, - //SC_INCBASEATK = 263, + //SC_INCBASEATK = 264, //SC_FASTCAST, - SC_MDEF_RATE = 265, + SC_PROTECT_MDEF = 266, //SC_HPREGEN, - SC_INCHEALRATE = 267, + SC_HEALPLUS = 268, SC_PNEUMA, - SC_AUTOTRADE, - SC_KSPROTECTED, //270 - SC_ARMOR_RESIST = 271, - SC_SPCOST_RATE, - SC_COMMONSC_RESIST, - SC_SEVENWIND, - SC_DEF_RATE, + SC_AUTOTRADE, //270 + SC_KSPROTECTED, + SC_ARMOR_RESIST, + SC_ATKER_BLOOD, + SC_TARGET_BLOOD, + SC_TK_SEVENWIND, + SC_PROTECT_DEF, //SC_SPREGEN, - SC_WALKSPEED = 277, + SC_WALKSPEED = 278, // Mercenary Only Bonus Effects - SC_MERC_FLEEUP, - SC_MERC_ATKUP, - SC_MERC_HPUP, //280 - SC_MERC_SPUP, - SC_MERC_HITUP, - SC_MERC_QUICKEN, + SC_MER_FLEE, + SC_MER_ATK, //280 + SC_MER_HP, + SC_MER_SP, + SC_MER_HIT, + SC_MER_QUICKEN, SC_REBIRTH, - //SC_SKILLCASTRATE, //285 + //SC_SKILLCASTRATE, //286 //SC_DEFRATIOATK, //SC_HPDRAIN, //SC_SKILLATKBONUS, - SC_ITEMSCRIPT = 289, - SC_S_LIFEPOTION, //290 + SC_ITEMSCRIPT = 290, + SC_S_LIFEPOTION, SC_L_LIFEPOTION, - SC_JEXPBOOST, + SC_CASH_PLUSONLYJOBEXP, //SC_IGNOREDEF, - SC_HELLPOWER = 294, - SC_INVINCIBLE, //295 + SC_HELLPOWER = 295, + SC_INVINCIBLE, SC_INVINCIBLEOFF, SC_MANU_ATK, SC_MANU_DEF, - SC_SPL_ATK, - SC_SPL_DEF, //300 + SC_SPL_ATK, //300 + SC_SPL_DEF, SC_MANU_MATK, SC_SPL_MATK, SC_FOOD_STR_CASH, @@ -344,25 +356,24 @@ typedef enum sc_type { SC_FOOD_VIT_CASH, SC_FOOD_DEX_CASH, SC_FOOD_INT_CASH, - SC_FOOD_LUK_CASH,//308 + SC_FOOD_LUK_CASH, /** * 3rd **/ - SC_FEAR,//309 - SC_BURNING,//310 - SC_FREEZING,//311 + SC_FEAR, + SC_FROSTMISTY, /** * Rune Knight **/ - SC_ENCHANTBLADE,//312 - SC_DEATHBOUND,//313 + SC_ENCHANTBLADE, + SC_DEATHBOUND, SC_MILLENNIUMSHIELD, - SC_CRUSHSTRIKE,//315 + SC_CRUSHSTRIKE, SC_REFRESH, SC_REUSE_REFRESH, SC_GIANTGROWTH, SC_STONEHARDSKIN, - SC_VITALITYACTIVATION,//320 + SC_VITALITYACTIVATION, SC_STORMBLAST, SC_FIGHTINGSPIRIT, SC_ABUNDANCE, @@ -370,12 +381,12 @@ typedef enum sc_type { * Arch Bishop **/ SC_ADORAMUS, - SC_EPICLESIS,//325 + SC_EPICLESIS, SC_ORATIO, SC_LAUDAAGNUS, SC_LAUDARAMUS, SC_RENOVATIO, - SC_EXPIATIO,//330 + SC_EXPIATIO, SC_DUPLELIGHT, SC_SECRAMENT, /** @@ -383,38 +394,38 @@ typedef enum sc_type { **/ SC_WHITEIMPRISON, SC_MARSHOFABYSS, - SC_RECOGNIZEDSPELL,//335 + SC_RECOGNIZEDSPELL, SC_STASIS, - SC_SPHERE_1, - SC_SPHERE_2, - SC_SPHERE_3, - SC_SPHERE_4,//340 - SC_SPHERE_5, + SC_SUMMON1, + SC_SUMMON2, + SC_SUMMON3, + SC_SUMMON4, + SC_SUMMON5, SC_READING_SB, - SC_FREEZINGSPELL, + SC_FREEZINGSP, /** * Ranger **/ SC_FEARBREEZE, - SC_ELECTRICSHOCKER,//345 + SC_ELECTRICSHOCKER, SC_WUGDASH, - SC_BITE, + SC_WUGBITE, SC_CAMOUFLAGE, /** * Mechanic **/ SC_ACCELERATION, - SC_HOVERING,//350 + SC_HOVERING, SC_SHAPESHIFT, SC_INFRAREDSCAN, SC_ANALYZE, SC_MAGNETICFIELD, - SC_NEUTRALBARRIER,//355 + SC_NEUTRALBARRIER, SC_NEUTRALBARRIER_MASTER, SC_STEALTHFIELD, SC_STEALTHFIELD_MASTER, SC_OVERHEAT, - SC_OVERHEAT_LIMITPOINT,//360 + SC_OVERHEAT_LIMITPOINT, /** * Guillotine Cross **/ @@ -422,30 +433,30 @@ typedef enum sc_type { SC_POISONINGWEAPON, SC_WEAPONBLOCKING, SC_CLOAKINGEXCEED, - SC_HALLUCINATIONWALK,//365 + SC_HALLUCINATIONWALK, SC_HALLUCINATIONWALK_POSTDELAY, SC_ROLLINGCUTTER, SC_TOXIN, SC_PARALYSE, - SC_VENOMBLEED,//370 + SC_VENOMBLEED, SC_MAGICMUSHROOM, SC_DEATHHURT, SC_PYREXIA, SC_OBLIVIONCURSE, - SC_LEECHESEND,//375 + SC_LEECHESEND, /** * Royal Guard **/ - SC_REFLECTDAMAGE, + SC_LG_REFLECTDAMAGE, SC_FORCEOFVANGUARD, SC_SHIELDSPELL_DEF, SC_SHIELDSPELL_MDEF, - SC_SHIELDSPELL_REF,//380 + SC_SHIELDSPELL_REF, SC_EXEEDBREAK, SC_PRESTIGE, SC_BANDING, SC_BANDING_DEFENCE, - SC_EARTHDRIVE,//385 + SC_EARTHDRIVE, SC_INSPIRATION, /** * Sorcerer @@ -453,30 +464,30 @@ typedef enum sc_type { SC_SPELLFIST, SC_CRYSTALIZE, SC_STRIKING, - SC_WARMER,//390 + SC_WARMER, SC_VACUUM_EXTREME, SC_PROPERTYWALK, /** * Minstrel / Wanderer **/ - SC_SWINGDANCE, - SC_SYMPHONYOFLOVER, - SC_MOONLITSERENADE,//395 - SC_RUSHWINDMILL, + SC_SWING, + SC_SYMPHONY_LOVE, + SC_MOONLIT_SERENADE, + SC_RUSH_WINDMILL, SC_ECHOSONG, SC_HARMONIZE, - SC_VOICEOFSIREN, - SC_DEEPSLEEP,//400 + SC_SIREN, + SC_DEEP_SLEEP, SC_SIRCLEOFNATURE, SC_GLOOMYDAY, SC_GLOOMYDAY_SK, - SC_SONGOFMANA, - SC_DANCEWITHWUG,//405 - SC_SATURDAYNIGHTFEVER, - SC_LERADSDEW, + SC_SONG_OF_MANA, + SC_DANCE_WITH_WUG, + SC_SATURDAY_NIGHT_FEVER, + SC_LERADS_DEW, SC_MELODYOFSINK, - SC_BEYONDOFWARCRY, - SC_UNLIMITEDHUMMINGVOICE,//410 + SC_BEYOND_OF_WARCRY, + SC_UNLIMITED_HUMMING_VOICE, SC_SITDOWN_FORCE, SC_NETHERWORLD, /** @@ -485,35 +496,35 @@ typedef enum sc_type { SC_CRESCENTELBOW, SC_CURSEDCIRCLE_ATKER, SC_CURSEDCIRCLE_TARGET, - SC_LIGHTNINGWALK,//416 + SC_LIGHTNINGWALK, SC_RAISINGDRAGON, - SC_GT_ENERGYGAIN, - SC_GT_CHANGE, - SC_GT_REVITALIZE, + SC_GENTLETOUCH_ENERGYGAIN, + SC_GENTLETOUCH_CHANGE, + SC_GENTLETOUCH_REVITALIZE, /** * Genetic **/ - SC_GN_CARTBOOST,//427 - SC_THORNSTRAP, - SC_BLOODSUCKER, - SC_SMOKEPOWDER, - SC_TEARGAS, - SC_MANDRAGORA,//426 + SC_GN_CARTBOOST, + SC_THORNS_TRAP, + SC_BLOOD_SUCKER, + SC_FIRE_EXPANSION_SMOKE_POWDER, + SC_FIRE_EXPANSION_TEAR_GAS, + SC_MANDRAGORA, SC_STOMACHACHE, SC_MYSTERIOUS_POWDER, SC_MELON_BOMB, SC_BANANA_BOMB, - SC_BANANA_BOMB_SITDOWN,//431 + SC_BANANA_BOMB_SITDOWN_POSTDELAY, SC_SAVAGE_STEAK, SC_COCKTAIL_WARG_BLOOD, SC_MINOR_BBQ, SC_SIROMA_ICE_TEA, - SC_DROCERA_HERB_STEAMED,//436 + SC_DROCERA_HERB_STEAMED, SC_PUTTI_TAILS_NOODLES, SC_BOOST500, SC_FULL_SWING_K, SC_MANA_PLUS, - SC_MUSTLE_M,//441 + SC_MUSTLE_M, SC_LIFE_FORCE_F, SC_EXTRACT_WHITE_POTION_Z, SC_VITATA_500, @@ -521,21 +532,21 @@ typedef enum sc_type { /** * Shadow Chaser **/ - SC__REPRODUCE,//446 + SC__REPRODUCE, SC__AUTOSHADOWSPELL, SC__SHADOWFORM, SC__BODYPAINT, SC__INVISIBILITY, - SC__DEADLYINFECT,//451 + SC__DEADLYINFECT, SC__ENERVATION, SC__GROOMY, SC__IGNORANCE, SC__LAZINESS, - SC__UNLUCKY,//456 + SC__UNLUCKY, SC__WEAKNESS, - SC__STRIPACCESSORY, + SC__STRIPACCESSARY, SC__MANHOLE, - SC__BLOODYLUST,//460 + SC__BLOODYLUST, /** * Elemental Spirits **/ @@ -543,61 +554,60 @@ typedef enum sc_type { SC_CIRCLE_OF_FIRE_OPTION, SC_FIRE_CLOAK, SC_FIRE_CLOAK_OPTION, - SC_WATER_SCREEN,//465 + SC_WATER_SCREEN, SC_WATER_SCREEN_OPTION, SC_WATER_DROP, SC_WATER_DROP_OPTION, SC_WATER_BARRIER, - SC_WIND_STEP,//470 + SC_WIND_STEP, SC_WIND_STEP_OPTION, SC_WIND_CURTAIN, SC_WIND_CURTAIN_OPTION, SC_ZEPHYR, - SC_SOLID_SKIN,//475 + SC_SOLID_SKIN, SC_SOLID_SKIN_OPTION, SC_STONE_SHIELD, SC_STONE_SHIELD_OPTION, SC_POWER_OF_GAIA, - SC_PYROTECHNIC,//480 + SC_PYROTECHNIC, SC_PYROTECHNIC_OPTION, SC_HEATER, SC_HEATER_OPTION, SC_TROPIC, - SC_TROPIC_OPTION,//485 + SC_TROPIC_OPTION, SC_AQUAPLAY, SC_AQUAPLAY_OPTION, SC_COOLER, SC_COOLER_OPTION, - SC_CHILLY_AIR,//490 + SC_CHILLY_AIR, SC_CHILLY_AIR_OPTION, SC_GUST, SC_GUST_OPTION, SC_BLAST, - SC_BLAST_OPTION,//495 + SC_BLAST_OPTION, SC_WILD_STORM, SC_WILD_STORM_OPTION, SC_PETROLOGY, SC_PETROLOGY_OPTION, - SC_CURSED_SOIL,//500 + SC_CURSED_SOIL, SC_CURSED_SOIL_OPTION, SC_UPHEAVAL, SC_UPHEAVAL_OPTION, SC_TIDAL_WEAPON, - SC_TIDAL_WEAPON_OPTION,//505 + SC_TIDAL_WEAPON_OPTION, SC_ROCK_CRUSHER, SC_ROCK_CRUSHER_ATK, /* Guild Aura */ SC_LEADERSHIP, SC_GLORYWOUNDS, - SC_SOULCOLD, //508 + SC_SOULCOLD, SC_HAWKEYES, /* ... */ SC_ODINS_POWER, - SC_RAID, /* Sorcerer .extra */ SC_FIRE_INSIGNIA, SC_WATER_INSIGNIA, - SC_WIND_INSIGNIA, //516 + SC_WIND_INSIGNIA, SC_EARTH_INSIGNIA, /* new pushcart */ SC_PUSH_CART, @@ -610,22 +620,22 @@ typedef enum sc_type { SC_SPELLBOOK6, /** * In official server there are only 7 maximum number of spell books that can be memorized - * To increase the maximum value just add another status type before SC_MAXSPELLBOOK (ex. SC_SPELLBOOK7, SC_SPELLBOOK8 and so on) + * To increase the maximum value just add another status type before SC_SPELLBOOK7 (ex. SC_SPELLBOOK8, SC_SPELLBOOK9 and so on) **/ - SC_MAXSPELLBOOK, + SC_SPELLBOOK7, /* Max HP & SP */ SC_INCMHP, SC_INCMSP, - SC_PARTYFLEE, // 531 + SC_PARTYFLEE, /** * Kagerou & Oboro [malufett] **/ SC_MEIKYOUSISUI, - SC_JYUMONJIKIRI, + SC_KO_JYUMONJIKIRI, SC_KYOUGAKU, SC_IZAYOI, SC_ZENKAI, - SC_KAGEHUMI, + SC_KG_KAGEHUMI, SC_KYOMU, SC_KAGEMUSYA, SC_ZANGETSU, @@ -639,17 +649,24 @@ typedef enum sc_type { SC_ERASER_CUTTER, SC_OVERED_BOOST, SC_LIGHT_OF_REGENE, - SC_ASH, + SC_VOLCANIC_ASH, SC_GRANITIC_ARMOR, SC_MAGMA_FLOW, SC_PYROCLASTIC, - SC_PARALYSIS, + SC_NEEDLE_OF_PARALYZE, SC_PAIN_KILLER, - - #ifdef RENEWAL SC_EXTREMITYFIST2, + SC_RAID, #endif + SC_DARKCROW = 553, + SC_FULL_THROTTLE, + SC_REBOUND, + SC_UNLIMIT, + SC_KINGS_GRACE, + SC_TELEKINESIS_INTENSE, + SC_OFFERTORIUM, + SC_FRIGG_SONG, SC_ALL_RIDING, SC_HANBOK, @@ -660,66 +677,66 @@ typedef enum sc_type { // Official status change ids, used to display status icons on the client. enum si_type { SI_BLANK = -1, - SI_PROVOKE = 0, - SI_ENDURE = 1, - SI_TWOHANDQUICKEN = 2, - SI_CONCENTRATE = 3, - SI_HIDING = 4, - SI_CLOAKING = 5, - SI_ENCPOISON = 6, - SI_POISONREACT = 7, - SI_QUAGMIRE = 8, - SI_ANGELUS = 9, - SI_BLESSING = 10, - SI_SIGNUMCRUCIS = 11, - SI_INCREASEAGI = 12, - SI_DECREASEAGI = 13, - SI_SLOWPOISON = 14, - SI_IMPOSITIO = 15, - SI_SUFFRAGIUM = 16, - SI_ASPERSIO = 17, - SI_BENEDICTIO = 18, - SI_KYRIE = 19, - SI_MAGNIFICAT = 20, - SI_GLORIA = 21, - SI_AETERNA = 22, - SI_ADRENALINE = 23, - SI_WEAPONPERFECTION = 24, - SI_OVERTHRUST = 25, - SI_MAXIMIZEPOWER = 26, - SI_RIDING = 27, - SI_FALCON = 28, - SI_TRICKDEAD = 29, - SI_LOUD = 30, - SI_ENERGYCOAT = 31, - SI_BROKENARMOR = 32, - SI_BROKENWEAPON = 33, - SI_HALLUCINATION = 34, - SI_WEIGHT50 = 35, - SI_WEIGHT90 = 36, - SI_ASPDPOTION0 = 37, - SI_ASPDPOTION1 = 38, - SI_ASPDPOTION2 = 39, - SI_ASPDPOTIONINFINITY = 40, - SI_SPEEDPOTION1 = 41, -// SI_MOVHASTE_INFINITY = 42, + SI_PROVOKE = 0, + SI_ENDURE = 1, + SI_TWOHANDQUICKEN = 2, + SI_CONCENTRATION = 3, + SI_HIDING = 4, + SI_CLOAKING = 5, + SI_ENCHANTPOISON = 6, + SI_POISONREACT = 7, + SI_QUAGMIRE = 8, + SI_ANGELUS = 9, + SI_BLESSING = 10, + SI_CRUCIS = 11, + SI_INC_AGI = 12, + SI_DEC_AGI = 13, + SI_SLOWPOISON = 14, + SI_IMPOSITIO = 15, + SI_SUFFRAGIUM = 16, + SI_ASPERSIO = 17, + SI_BENEDICTIO = 18, + SI_KYRIE = 19, + SI_MAGNIFICAT = 20, + SI_GLORIA = 21, + SI_LEXAETERNA = 22, + SI_ADRENALINE = 23, + SI_WEAPONPERFECT = 24, + SI_OVERTHRUST = 25, + SI_MAXIMIZE = 26, + SI_RIDING = 27, + SI_FALCON = 28, + SI_TRICKDEAD = 29, + SI_SHOUT = 30, + SI_ENERGYCOAT = 31, + SI_BROKENARMOR = 32, + SI_BROKENWEAPON = 33, + SI_ILLUSION = 34, + SI_WEIGHTOVER50 = 35, + SI_WEIGHTOVER90 = 36, + SI_ATTHASTE_POTION1 = 37, + SI_ATTHASTE_POTION2 = 38, + SI_ATTHASTE_POTION3 = 39, + SI_ATTHASTE_INFINITY = 40, + SI_MOVHASTE_POTION = 41, + SI_MOVHASTE_INFINITY = 42, // SI_AUTOCOUNTER = 43, // SI_SPLASHER = 44, -// SI_ANKLESNARE = 45, - SI_ACTIONDELAY = 46, + SI_ANKLESNARE = 45, + SI_POSTDELAY = 46, // SI_NOACTION = 47, // SI_IMPOSSIBLEPICKUP = 48, // SI_BARRIER = 49, - SI_STRIPWEAPON = 50, - SI_STRIPSHIELD = 51, - SI_STRIPARMOR = 52, - SI_STRIPHELM = 53, - SI_CP_WEAPON = 54, - SI_CP_SHIELD = 55, - SI_CP_ARMOR = 56, - SI_CP_HELM = 57, - SI_AUTOGUARD = 58, - SI_REFLECTSHIELD = 59, + SI_NOEQUIPWEAPON = 50, + SI_NOEQUIPSHIELD = 51, + SI_NOEQUIPARMOR = 52, + SI_NOEQUIPHELM = 53, + SI_PROTECTWEAPON = 54, + SI_PROTECTSHIELD = 55, + SI_PROTECTARMOR = 56, + SI_PROTECTHELM = 57, + SI_AUTOGUARD = 58, + SI_REFLECTSHIELD = 59, // SI_DEVOTION = 60, SI_PROVIDENCE = 61, SI_DEFENDER = 62, @@ -750,29 +767,29 @@ enum si_type { SI_STEELBODY = 87, SI_EXTREMITYFIST = 88, // SI_COMBOATTACK = 89, - SI_FIREWEAPON = 90, - SI_WATERWEAPON = 91, - SI_WINDWEAPON = 92, - SI_EARTHWEAPON = 93, + SI_PROPERTYFIRE = 90, + SI_PROPERTYWATER = 91, + SI_PROPERTYWIND = 92, + SI_PROPERTYGROUND = 93, // SI_MAGICATTACK = 94, SI_STOP = 95, // SI_WEAPONBRAKER = 96, - SI_UNDEAD = 97, + SI_PROPERTYUNDEAD = 97, // SI_POWERUP = 98, // SI_AGIUP = 99, // SI_SIEGEMODE = 100, // SI_INVISIBLE = 101, // SI_STATUSONE = 102, - SI_AURABLADE = 103, - SI_PARRYING = 104, - SI_CONCENTRATION = 105, - SI_TENSIONRELAX = 106, + SI_AURABLADE = 103, + SI_PARRYING = 104, + SI_LKCONCENTRATION = 105, + SI_TENSIONRELAX = 106, SI_BERSERK = 107, // SI_SACRIFICE = 108, // SI_GOSPEL = 109, SI_ASSUMPTIO = 110, // SI_BASILICA = 111, - SI_LANDENDOW = 112, + SI_GROUNDMAGIC = 112, SI_MAGICPOWER = 113, SI_EDP = 114, SI_TRUESIGHT = 115, @@ -780,52 +797,52 @@ enum si_type { SI_MELTDOWN = 117, SI_CARTBOOST = 118, // SI_CHASEWALK = 119, - SI_REJECTSWORD = 120, - SI_MARIONETTE = 121, - SI_MARIONETTE2 = 122, - SI_MOONLIT = 123, - SI_BLEEDING = 124, + SI_SWORDREJECT = 120, + SI_MARIONETTE_MASTER = 121, + SI_MARIONETTE = 122, + SI_MOON = 123, + SI_BLOODING = 124, SI_JOINTBEAT = 125, // SI_MINDBREAKER = 126, // SI_MEMORIZE = 127, // SI_FOGWALL = 128, // SI_SPIDERWEB = 129, - SI_BABY = 130, + SI_PROTECTEXP = 130, // SI_SUB_WEAPONPROPERTY = 131, SI_AUTOBERSERK = 132, SI_RUN = 133, - SI_BUMP = 134, - SI_READYSTORM = 135, -// SI_STORMKICK_READY = 136, - SI_READYDOWN = 137, -// SI_DOWNKICK_READY = 138, - SI_READYTURN = 139, -// SI_TURNKICK_READY = 140, - SI_READYCOUNTER = 141, -// SI_COUNTER_READY = 142, - SI_DODGE = 143, -// SI_DODGE_READY = 144, - SI_SPURT = 145, - SI_SHADOWWEAPON = 146, - SI_ADRENALINE2 = 147, - SI_GHOSTWEAPON = 148, - SI_SPIRIT = 149, - SI_PLUSATTACKPOWER = 150, - SI_PLUSMAGICPOWER = 151, - SI_DEVIL = 152, + SI_TING = 134, + SI_STORMKICK_ON = 135, + SI_STORMKICK_READY = 136, + SI_DOWNKICK_ON = 137, + SI_DOWNKICK_READY = 138, + SI_TURNKICK_ON = 139, + SI_TURNKICK_READY = 140, + SI_COUNTER_ON = 141, + SI_COUNTER_READY = 142, + SI_DODGE_ON = 143, + SI_DODGE_READY = 144, + SI_STRUP = 145, + SI_PROPERTYDARK = 146, + SI_ADRENALINE2 = 147, + SI_PROPERTYTELEKINESIS = 148, + SI_SOULLINK = 149, + SI_PLUSATTACKPOWER = 150, + SI_PLUSMAGICPOWER = 151, + SI_DEVIL1 = 152, SI_KAITE = 153, // SI_SWOO = 154, // SI_STAR2 = 155, SI_KAIZEL = 156, SI_KAAHI = 157, SI_KAUPE = 158, - SI_SMA = 159, - SI_NIGHT = 160, - SI_ONEHAND = 161, + SI_SMA_READY = 159, + SI_SKE = 160, + SI_ONEHANDQUICKEN = 161, // SI_FRIEND = 162, // SI_FRIENDUP = 163, // SI_SG_WARM = 164, - SI_WARM = 165, + SI_SG_SUN_WARM = 165, // 166 | The three show the exact same display: ultra red character (165, 166, 167) // 167 | Their names would be SI_SG_SUN_WARM, SI_SG_MOON_WARM, SI_SG_STAR_WARM // SI_EMOTION = 168, @@ -844,34 +861,34 @@ enum si_type { SI_PRESERVE = 181, SI_INCSTR = 182, // SI_NOT_EXTREMITYFIST = 183, - SI_INTRAVISION = 184, + SI_CLAIRVOYANCE = 184, // SI_MOVESLOW_POTION = 185, - SI_DOUBLECAST = 186, + SI_DOUBLECASTING = 186, // SI_GRAVITATION = 187, - SI_MAXOVERTHRUST = 188, + SI_OVERTHRUSTMAX = 188, // SI_LONGING = 189, // SI_HERMODE = 190, - SI_TAROT = 191, // the icon allows no doubt... but what is it really used for ?? [DracoRPG] + SI_TAROTCARD = 191, // the icon allows no doubt... but what is it really used for ?? [DracoRPG] // SI_HLIF_AVOID = 192, // SI_HFLI_FLEET = 193, // SI_HFLI_SPEED = 194, // SI_HLIF_CHANGE = 195, // SI_HAMI_BLOODLUST = 196, - SI_SHRINK = 197, - SI_SIGHTBLASTER = 198, - SI_WINKCHARM = 199, - SI_CLOSECONFINE = 200, - SI_CLOSECONFINE2 = 201, + SI_CR_SHRINK = 197, + SI_WZ_SIGHTBLASTER = 198, + SI_DC_WINKCHARM = 199, + SI_RG_CCONFINE_M = 200, + SI_RG_CCONFINE_S = 201, // SI_DISABLEMOVE = 202, - SI_MADNESSCANCEL = 203, //[blackhole89] - SI_GATLINGFEVER = 204, - SI_EARTHSCROLL = 205, - SI_UTSUSEMI = 206, - SI_BUNSINJYUTSU = 207, - SI_NEN = 208, - SI_ADJUSTMENT = 209, - SI_ACCURACY = 210, -// SI_NJ_SUITON = 211, + SI_GS_MADNESSCANCEL = 203, //[blackhole89] + SI_GS_GATLINGFEVER = 204, + SI_EARTHSCROLL = 205, + SI_NJ_UTSUSEMI = 206, + SI_NJ_BUNSINJYUTSU = 207, + SI_NJ_NEN = 208, + SI_GS_ADJUSTMENT = 209, + SI_GS_ACCURACY = 210, + SI_NJ_SUITON = 211, // SI_PET = 212, // SI_MENTAL = 213, // SI_EXPMEMORY = 214, @@ -901,19 +918,19 @@ enum si_type { // SI_DGAUGE = 238, // SI_DACCEL = 239, // SI_DBLOCK = 240, - SI_FOODSTR = 241, - SI_FOODAGI = 242, - SI_FOODVIT = 243, - SI_FOODDEX = 244, - SI_FOODINT = 245, - SI_FOODLUK = 246, - SI_FOODFLEE = 247, - SI_FOODHIT = 248, - SI_FOODCRI = 249, - SI_EXPBOOST = 250, - SI_LIFEINSURANCE = 251, - SI_ITEMBOOST = 252, - SI_BOSSMAPINFO = 253, + SI_FOOD_STR = 241, + SI_FOOD_AGI = 242, + SI_FOOD_VIT = 243, + SI_FOOD_DEX = 244, + SI_FOOD_INT = 245, + SI_FOOD_LUK = 246, + SI_FOOD_BASICAVOIDANCE = 247, + SI_FOOD_BASICHIT = 248, + SI_FOOD_CRITICALSUCCESSVALUE = 249, + SI_CASH_PLUSEXP = 250, + SI_CASH_DEATHPENALTY = 251, + SI_CASH_RECEIVEITEM = 252, + SI_CASH_BOSS_ALARM = 253, // SI_DA_ENERGY = 254, // SI_DA_FIRSTSLOT = 255, // SI_DA_HEADDEF = 256, @@ -937,11 +954,11 @@ enum si_type { SI_FOOD_DEX_CASH = 274, SI_FOOD_INT_CASH = 275, SI_FOOD_LUK_CASH = 276, - SI_MERC_FLEEUP = 277, - SI_MERC_ATKUP = 278, - SI_MERC_HPUP = 279, - SI_MERC_SPUP = 280, - SI_MERC_HITUP = 281, + SI_MER_FLEE = 277, + SI_MER_ATK = 278, + SI_MER_HP = 279, + SI_MER_SP = 280, + SI_MER_HIT = 281, SI_SLOWCAST = 282, // SI_MAGICMIRROR = 283, // SI_STONESKIN = 284, @@ -949,14 +966,14 @@ enum si_type { SI_CRITICALWOUND = 286, // SI_NPC_DEFENDER = 287, // SI_NOACTION_WAIT = 288, - SI_MOVHASTE_HORSE = 289, - SI_DEF_RATE = 290, - SI_MDEF_RATE = 291, - SI_INCHEALRATE = 292, - SI_S_LIFEPOTION = 293, - SI_L_LIFEPOTION = 294, - SI_INCCRI = 295, - SI_PLUSAVOIDVALUE = 296, + SI_MOVHASTE_HORSE = 289, + SI_PROTECT_DEF = 290, + SI_PROTECT_MDEF = 291, + SI_HEALPLUS = 292, + SI_S_LIFEPOTION = 293, + SI_L_LIFEPOTION = 294, + SI_CRITICALPERCENT = 295, + SI_PLUSAVOIDVALUE = 296, // SI_ATKER_ASPD = 297, // SI_TARGET_ASPD = 298, // SI_ATKER_MOVESPEED = 299, @@ -975,7 +992,7 @@ enum si_type { SI_CASH_PLUSONLYJOBEXP = 312, SI_PARTYFLEE = 313, // SI_ANGEL_PROTECT = 314, - SI_ENDURE_MDEF = 315, +// SI_ENDURE_MDEF = 315, SI_ENCHANTBLADE = 316, SI_DEATHBOUND = 317, SI_REFRESH = 318, @@ -1094,12 +1111,12 @@ enum si_type { SI_PROPERTYWALK = 431, SI_SPELLFIST = 432, SI_NETHERWORLD = 433, - SI_VOICEOFSIREN = 434, + SI_SIREN = 434, SI_DEEPSLEEP = 435, SI_SIRCLEOFNATURE = 436, SI_COLD = 437, SI_GLOOMYDAY = 438, - SI_SONGOFMANA = 439, + SI_SONG_OF_MANA = 439, SI_CLOUDKILL = 440, SI_DANCEWITHWUG = 441, SI_RUSHWINDMILL = 442, @@ -1361,6 +1378,34 @@ enum si_type { SI_QUEST_BUFF3 = 707, SI_REUSE_LIMIT_RECALL = 708, SI_SAVEPOSITION = 709, + SI_HANDICAPSTATE_ICEEXPLO = 710, + SI_FENRIR_CARD = 711, + SI_REUSE_LIMIT_ASPD_POTION = 712, + SI_MAXPAIN = 713, + SI_PC_STOP = 714, + SI_FRIGG_SONG = 715, + SI_OFFERTORIUM = 716, + SI_TELEKINESIS_INTENSE = 717, + SI_MOONSTAR = 718, + SI_STRANGELIGHTS = 719, + SI_FULL_THROTTLE = 720, + SI_REBOUND = 721, + SI_UNLIMIT = 722, + SI_KINGS_GRACE = 723, + SI_ITEM_ATKMAX = 724, + SI_ITEM_ATKMIN = 725, + SI_ITEM_MATKMAX = 726, + SI_ITEM_MATKMIN = 727, + SI_SUPER_STAR = 728, + SI_HIGH_RANKER = 729, + SI_DARKCROW = 730, + SI_2013_VALENTINE1 = 731, + SI_2013_VALENTINE2 = 732, + SI_2013_VALENTINE3 = 733, + //SI_ = 734, + //SI_ = 735, + SI_CHILL = 736, + SI_BURNT = 737, SI_MAX, }; @@ -1553,7 +1598,7 @@ enum scb_flag //Basic damage info of a weapon //Required because players have two of these, one in status_data //and another for their left hand weapon. -struct weapon_atk { +typedef struct weapon_atk { unsigned short atk, atk2; unsigned short range; unsigned char ele; @@ -1561,7 +1606,7 @@ struct weapon_atk { unsigned short matk; unsigned char wlv; #endif -}; +}weapon_atk; sc_type SkillStatusChangeTable[MAX_SKILL]; // skill -> status int StatusIconChangeTable[SC_MAX]; // status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated) @@ -1681,6 +1726,7 @@ sc_type status_skill2sc(int skill); int status_sc2skill(sc_type sc); unsigned int status_sc2scb_flag(sc_type sc); int status_type2relevant_bl_types(int type); +int status_get_sc_type(sc_type idx); int status_damage(struct block_list *src,struct block_list *target,int hp,int sp, int walkdelay, int flag); //Define for standard HP damage attacks. @@ -1801,10 +1847,20 @@ int status_check_visibility(struct block_list *src, struct block_list *target); int status_change_spread( struct block_list *src, struct block_list *bl ); +defType status_calc_def(struct block_list *bl, struct status_change *sc, int, bool); +signed short status_calc_def2(struct block_list *,struct status_change *, int, bool); +defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int, bool); +signed short status_calc_mdef2(struct block_list *,struct status_change *, int, bool); + #ifdef RENEWAL unsigned short status_base_matk(const struct status_data* status, int level); +int status_get_weapon_atk(struct block_list *src, struct weapon_atk *watk, int flag); +int status_get_total_mdef(struct block_list *src); +int status_get_total_def(struct block_list *src); #endif +int status_get_matk(struct block_list *src, int flag); + int status_readdb(void); int do_init_status(void); void do_final_status(void); diff --git a/src/map/unit.c b/src/map/unit.c index 153ef5eda..371a75ac7 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -491,7 +491,7 @@ int unit_run(struct block_list *bl) if( (to_x == bl->x && to_y == bl->y ) || (to_x == (bl->x+1) || to_y == (bl->y+1)) || (to_x == (bl->x-1) || to_y == (bl->y-1))) { //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] - clif->sc_load(bl,bl->id,AREA,SI_BUMP,0,0,0); + clif->sc_load(bl,bl->id,AREA,SI_TING,0,0,0); //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] unit_bl2ud(bl)->state.running = 0; @@ -499,7 +499,7 @@ int unit_run(struct block_list *bl) skill->blown(bl,bl,skill->get_blewcount(TK_RUN,lv),unit_getdir(bl),0); clif->fixpos(bl); //Why is a clif->slide (skill->blown) AND a fixpos needed? Ask Aegis. - clif->sc_end(bl,bl->id,AREA,SI_BUMP); + clif->sc_end(bl,bl->id,AREA,SI_TING); return 0; } if (unit_walktoxy(bl, to_x, to_y, 1)) @@ -511,7 +511,7 @@ int unit_run(struct block_list *bl) } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1)); if ( i == 0 ) { // copy-paste from above - clif->sc_load(bl,bl->id,AREA,SI_BUMP,0,0,0); + clif->sc_load(bl,bl->id,AREA,SI_TING,0,0,0); //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] unit_bl2ud(bl)->state.running = 0; @@ -519,7 +519,7 @@ int unit_run(struct block_list *bl) skill->blown(bl,bl,skill->get_blewcount(TK_RUN,lv),unit_getdir(bl),0); clif->fixpos(bl); - clif->sc_end(bl,bl->id,AREA,SI_BUMP); + clif->sc_end(bl,bl->id,AREA,SI_TING); return 0; } return 1; @@ -924,7 +924,7 @@ int unit_can_move(struct block_list *bl) { if (sc) { if( sc->count && ( - sc->data[SC_ANKLE] + sc->data[SC_ANKLESNARE] || sc->data[SC_AUTOCOUNTER] || sc->data[SC_TRICKDEAD] || sc->data[SC_BLADESTOP] @@ -932,14 +932,14 @@ int unit_can_move(struct block_list *bl) { || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) // cannot move while gospel is in effect || (sc->data[SC_BASILICA] && sc->data[SC_BASILICA]->val4 == bl->id) // Basilica caster cannot move || sc->data[SC_STOP] - || sc->data[SC_CLOSECONFINE] - || sc->data[SC_CLOSECONFINE2] - || sc->data[SC_MADNESSCANCEL] + || sc->data[SC_RG_CCONFINE_M] + || sc->data[SC_RG_CCONFINE_S] + || sc->data[SC_GS_MADNESSCANCEL] || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF) || sc->data[SC_WHITEIMPRISON] || sc->data[SC_ELECTRICSHOCKER] - || sc->data[SC_BITE] - || sc->data[SC_THORNSTRAP] + || sc->data[SC_WUGBITE] + || sc->data[SC_THORNS_TRAP] || sc->data[SC_MAGNETICFIELD] || sc->data[SC__MANHOLE] || sc->data[SC_CURSEDCIRCLE_ATKER] @@ -948,9 +948,9 @@ int unit_can_move(struct block_list *bl) { || sc->data[SC_NETHERWORLD] || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3 && !(sc->data[SC_CAMOUFLAGE]->val3&1)) || sc->data[SC_MEIKYOUSISUI] - || sc->data[SC_KAGEHUMI] + || sc->data[SC_KG_KAGEHUMI] || sc->data[SC_KYOUGAKU] - || sc->data[SC_PARALYSIS] + || sc->data[SC_NEEDLE_OF_PARALYZE] || sc->data[SC_VACUUM_EXTREME] || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0) || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) @@ -1069,10 +1069,10 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui sc = NULL; //Unneeded //temp: used to signal combo-skills right now. - if (sc && sc->data[SC_COMBO] && (sc->data[SC_COMBO]->val1 == skill_id || + if (sc && sc->data[SC_COMBOATTACK] && (sc->data[SC_COMBOATTACK]->val1 == skill_id || (sd?skill->check_condition_castbegin(sd,skill_id,skill_lv):0) )) { - if (sc->data[SC_COMBO]->val2) - target_id = sc->data[SC_COMBO]->val2; + if (sc->data[SC_COMBOATTACK]->val2) + target_id = sc->data[SC_COMBOATTACK]->val2; else target_id = ud->target; @@ -1240,17 +1240,17 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui casttime += casttime * min(skill_lv, sd->spiritball); break; case MO_EXTREMITYFIST: - if (sc && sc->data[SC_COMBO] && - (sc->data[SC_COMBO]->val1 == MO_COMBOFINISH || - sc->data[SC_COMBO]->val1 == CH_TIGERFIST || - sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH)) + if (sc && sc->data[SC_COMBOATTACK] && + (sc->data[SC_COMBOATTACK]->val1 == MO_COMBOFINISH || + sc->data[SC_COMBOATTACK]->val1 == CH_TIGERFIST || + sc->data[SC_COMBOATTACK]->val1 == CH_CHAINCRUSH)) casttime = -1; temp = 1; break; case SR_GATEOFHELL: case SR_TIGERCANNON: - if (sc && sc->data[SC_COMBO] && - sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) + if (sc && sc->data[SC_COMBOATTACK] && + sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE) casttime = -1; temp = 1; break; @@ -1317,10 +1317,11 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if(!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026 unit_stop_walking(src,1);// eventhough this is not how official works but this will do the trick. bugreport:6829 + // in official this is triggered even if no cast time. clif->skillcasting(src, src->id, target_id, 0,0, skill_id, skill->get_ele(skill_id, skill_lv), casttime); if( casttime > 0 || temp ) - { + { if (sd && target->type == BL_MOB) { TBL_MOB *md = (TBL_MOB*)target; @@ -1518,7 +1519,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui if( casttime > 0 ) { ud->skilltimer = iTimer->add_timer( tick+casttime, skill->castend_pos, src->id, 0 ); if( (sd && pc->checkskill(sd,SA_FREECAST) > 0) || skill_id == LG_EXEEDBREAK) - status_calc_bl(&sd->bl, SCB_SPEED); + status_calc_bl(&sd->bl, SCB_SPEED); } else { ud->skilltimer = INVALID_TIMER; skill->castend_pos(ud->skilltimer,tick,src->id,0); @@ -1638,7 +1639,7 @@ int unit_cancel_combo(struct block_list *bl) { struct unit_data *ud; - if (!status_change_end(bl, SC_COMBO, INVALID_TIMER)) + if (!status_change_end(bl, SC_COMBOATTACK, INVALID_TIMER)) return 0; //Combo wasn't active. ud = unit_bl2ud(bl); @@ -1925,7 +1926,7 @@ int unit_skillcastcancel(struct block_list *bl,int type) return 0; if (sd && (sd->special_state.no_castcancel2 || - ((sd->sc.data[SC_UNLIMITEDHUMMINGVOICE] || sd->special_state.no_castcancel) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) //fixed flags being read the wrong way around [blackhole89] + ((sd->sc.data[SC_UNLIMITED_HUMMING_VOICE] || sd->special_state.no_castcancel) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) //fixed flags being read the wrong way around [blackhole89] return 0; } @@ -2053,17 +2054,17 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, if(sc && sc->count ) { //map-change/warp dispells. status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); status_change_end(bl, SC_BASILICA, INVALID_TIMER); - status_change_end(bl, SC_ANKLE, INVALID_TIMER); + status_change_end(bl, SC_ANKLESNARE, INVALID_TIMER); status_change_end(bl, SC_TRICKDEAD, INVALID_TIMER); status_change_end(bl, SC_BLADESTOP_WAIT, INVALID_TIMER); status_change_end(bl, SC_RUN, INVALID_TIMER); status_change_end(bl, SC_DANCING, INVALID_TIMER); status_change_end(bl, SC_WARM, INVALID_TIMER); status_change_end(bl, SC_DEVOTION, INVALID_TIMER); + status_change_end(bl, SC_MARIONETTE_MASTER, INVALID_TIMER); status_change_end(bl, SC_MARIONETTE, INVALID_TIMER); - status_change_end(bl, SC_MARIONETTE2, INVALID_TIMER); - status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); - status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); status_change_end(bl, SC_HIDING, INVALID_TIMER); // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later if ( bl->type != BL_PC ) @@ -2074,7 +2075,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_CHASEWALK, INVALID_TIMER); if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) status_change_end(bl, SC_GOSPEL, INVALID_TIMER); - status_change_end(bl, SC_CHANGE, INVALID_TIMER); + status_change_end(bl, SC_HLIF_CHANGE, INVALID_TIMER); status_change_end(bl, SC_STOP, INVALID_TIMER); status_change_end(bl, SC_WUGDASH, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); @@ -2322,7 +2323,7 @@ int unit_free(struct block_list *bl, clr_type clrtype) pc->inventory_rental_clear(sd); pc->delspiritball(sd,sd->spiritball,1); for(i = 1; i < 5; i++) - pc->del_talisman(sd, sd->talisman[i], i); + pc->del_charm(sd, sd->charm[i], i); if( sd->reg ) { //Double logout already freed pointer fix... [Skotlex] aFree(sd->reg); diff --git a/src/map/vending.c b/src/map/vending.c index e0dd844e1..b9575c8dd 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -272,7 +272,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); // custom reply packet return; } - sd->state.prevend = 0; + sd->state.prevend = sd->state.workinprogress = 0; sd->state.vending = true; sd->vender_id = getid(); sd->vend_num = i; -- cgit v1.2.3-70-g09d2