diff options
Diffstat (limited to 'src/map/skill.c')
-rw-r--r-- | src/map/skill.c | 659 |
1 files changed, 364 insertions, 295 deletions
diff --git a/src/map/skill.c b/src/map/skill.c index 612b205e9..c744dbde4 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2,46 +2,48 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/ers.h" +#define HERCULES_CORE -#include "map.h" -#include "path.h" -#include "clif.h" -#include "pc.h" -#include "status.h" +#include "../config/core.h" // DBPATH, MAGIC_REFLECTION_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_CAST, VARCAST_REDUCTION() #include "skill.h" -#include "pet.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "battle.h" +#include "battleground.h" +#include "chrif.h" +#include "clif.h" +#include "date.h" +#include "elemental.h" +#include "guild.h" #include "homunculus.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" #include "mercenary.h" -#include "elemental.h" #include "mob.h" #include "npc.h" -#include "battle.h" -#include "battleground.h" #include "party.h" -#include "itemdb.h" +#include "path.h" +#include "pc.h" +#include "pet.h" #include "script.h" -#include "intif.h" -#include "log.h" -#include "chrif.h" -#include "guild.h" -#include "date.h" +#include "status.h" #include "unit.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <math.h> - +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" #define SKILLUNITTIMER_INTERVAL 100 @@ -541,23 +543,6 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) return 1; } break; - case BS_GREED: - case WS_CARTBOOST: - case BS_HAMMERFALL: - case BS_ADRENALINE: - case MC_CARTREVOLUTION: - case MC_MAMMONITE: - case WS_MELTDOWN: - case MG_SIGHT: - case TF_HIDING: - /** - * These skills cannot be used while in mado gear (credits to Xantara) - **/ - if( pc_ismadogear(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR_RIDE,0); - return 1; - } - break; case SC_MANHOLE: case WM_SOUND_OF_DESTRUCTION: @@ -585,12 +570,12 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd) return 1; switch(skill_id){ case MH_LIGHT_OF_REGENE: - if(hd->homunculus.intimacy <= 75000) //if not cordial - return 1; - break; - case MH_OVERED_BOOST: - if(hd->homunculus.hunger <= 1) //if we starving - return 1; + if( homun->get_intimacy_grade(hd) != 4 ){ + if( hd->master ) + clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0); + return 1; + } + break; case MH_GOLDENE_FERSE: //can be used with angriff if(hd->sc.data[SC_ANGRIFFS_MODUS]) return 1; @@ -760,15 +745,18 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 // Chance to trigger Taekwon kicks [Dralnu] if(sc && !sc->data[SC_COMBOATTACK]) { if(sc->data[SC_STORMKICK_READY] && - sc_start(src,src,SC_COMBOATTACK, 15, TK_STORMKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_STORMKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if(sc->data[SC_DOWNKICK_READY] && - sc_start(src,src,SC_COMBOATTACK, 15, TK_DOWNKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_DOWNKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if(sc->data[SC_TURNKICK_READY] && - sc_start(src,src,SC_COMBOATTACK, 15, TK_TURNKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_TURNKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if (sc->data[SC_COUNTERKICK_READY]) { //additional chance from SG_FRIEND [Komurka] @@ -850,7 +838,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 #ifdef RENEWAL sc_start(src,bl,SC_FREEZE,65-(5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); #else - //Tharis pointed out that this is normal freeze chance with a base of 300% + // [Tharis] pointed out that this is normal freeze chance with a base of 300% if(tsc->sg_counter >= 3 && sc_start(src,bl,SC_FREEZE,300,skill_lv,skill->get_time2(skill_id,skill_lv))) tsc->sg_counter = 0; @@ -991,7 +979,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 break; case NPC_MENTALBREAKER: { - //Based on observations by Tharis, Mental Breaker should do SP damage + //Based on observations by [Tharis], Mental Breaker should do SP damage //equal to Matk*skLevel. rate = status->get_matk(src, 2); rate*=skill_lv; @@ -1030,7 +1018,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 sc_start(src,bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case LK_HEADCRUSH: //Headcrush has chance of causing Bleeding status, except on demon and undead element + 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(src, bl, SC_BLOODING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv)); break; @@ -1257,7 +1245,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 sc_start(src, bl, SC_STUN, 1 + skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_FALLENEMPIRE: - sc_start(src, bl, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_FALLENEMPIRE, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_WINDMILL: if( dstsd ) @@ -1294,11 +1282,11 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 sc_start(src, bl, SC_BLOODING, 100, skill_lv, 10000); break; case ITEMID_MELON_BOMB: - sc_start(src, bl, SC_MELON_BOMB, 100, skill_lv, 60000); // Reduces ASPD and moviment speed + sc_start(src, bl, SC_MELON_BOMB, 100, skill_lv, 60000); // Reduces ASPD and movement speed break; case ITEMID_BANANA_BOMB: sc_start(src, bl, SC_BANANA_BOMB, 100, skill_lv, 60000); // Reduces LUK? Needed confirm it, may be it's bugged in kRORE? - sc_start(src, bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, (sd? sd->status.job_level:0) + sstatus->dex / 6 + tstatus->agi / 4 - tstatus->luk / 5 - status->get_lv(bl) + status->get_lv(src), skill_lv, 1000); // Sitdown for 3 seconds. + sc_start(src, bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, (sd? sd->status.job_level:0) + sstatus->dex / 6 + tstatus->agi / 4 - tstatus->luk / 5 - status->get_lv(bl) + status->get_lv(src), skill_lv, 1000); // Sit down for 3 seconds. break; } sd->itemid = -1; @@ -1341,6 +1329,9 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 if( sc_start(src, bl, SC_ILLUSIONDOPING, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)) ) //custom rate. sc_start(src, bl, SC_ILLUSION, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; + case MH_XENO_SLASHER: + sc_start2(src, bl, SC_BLOODING, 10 * skill_lv, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); + break; } if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) { @@ -1652,7 +1643,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1 return 1; } -/* Splitted off from skill->additional_effect, which is never called when the +/* Split off from skill->additional_effect, which is never called when the * attack skill kills the enemy. Place in this function counter status effects * when using skills (eg: Asura's sp regen penalty, or counter-status effects * from cards) that will take effect on the source, not the target. [Skotlex] @@ -1668,7 +1659,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b nullpo_ret(src); nullpo_ret(bl); - if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! - celest + if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! [celest] sd = BL_CAST(BL_PC, src); dstsd = BL_CAST(BL_PC, bl); @@ -1707,7 +1698,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b case GS_FULLBUSTER: sc_start(src,src,SC_BLIND,2*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case HFLI_SBR44: //[orn] + case HFLI_SBR44: // [orn] case HVAN_EXPLOSION: if(src->type == BL_HOM){ TBL_HOM *hd = (TBL_HOM*)src; @@ -1723,15 +1714,15 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b } if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR - && rnd()%10000 < battle_config.sg_miracle_skill_ratio) //SG_MIRACLE [Komurka] + && rnd()%10000 < battle_config.sg_miracle_skill_ratio) // SG_MIRACLE [Komurka] sc_start(src,src,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); if( sd && skill_id && attack_type&BF_MAGIC && status->isdead(bl) && !(skill->get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL)) && (rate=pc->checkskill(sd,HW_SOULDRAIN)) > 0 ) { - //Soul Drain should only work on targetted spells [Skotlex] - if( pc_issit(sd) ) pc->setstand(sd); //Character stuck in attacking animation while 'sitting' fix. [Skotlex] + // Soul Drain should only work on targeted spells [Skotlex] + if( pc_issit(sd) ) pc->setstand(sd); // Character stuck in attacking animation while 'sitting' fix. [Skotlex] if( skill->get_nk(skill_id)&NK_SPLASH && skill->area_temp[1] != bl->id ) ; else { @@ -1751,7 +1742,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b if( attack_type&BF_MAGIC ) { sp += sd->bonus.magic_sp_gain_value; hp += sd->bonus.magic_hp_gain_value; - if( skill_id == WZ_WATERBALL ) {//(bugreport:5303) + if( skill_id == WZ_WATERBALL ) {// (bugreport:5303) struct status_change *sc = NULL; if( ( sc = status->get_sc(src) ) ) { if( sc->data[SC_SOULLINK] @@ -1846,7 +1837,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b break; } dstsd->state.autocast = 0; - //Set canact delay. [Skotlex] + // Set canact delay. [Skotlex] ud = unit->bl2ud(bl); if (ud) { rate = skill->delay_fix(bl, auto_skill_id, auto_skill_lv); @@ -1984,7 +1975,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int return 0; sc = status->get_sc(bl); - if (!sc || sc->option&OPTION_MADOGEAR ) //Mado Gear cannot be divested [Ind] + if (!sc || sc->option&OPTION_MADOGEAR ) // Mado Gear cannot be divested [Ind] return 0; for (i = 0; i < ARRAYLENGTH(pos); i++) { @@ -2013,16 +2004,16 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in nullpo_ret(src); if (src != target && map->list[src->m].flag.noknockback) - return 0; //No knocking + return 0; // No knocking if (count == 0) - return 0; //Actual knockback distance is 0. + return 0; // Actual knockback distance is 0. switch (target->type) { case BL_MOB: { struct mob_data* md = BL_CAST(BL_MOB, target); if( md->class_ == MOBID_EMPERIUM ) return 0; - if(src != target && is_boss(target)) //Bosses can't be knocked-back + if(src != target && is_boss(target)) // Bosses can't be knocked-back return 0; } break; @@ -2054,11 +2045,13 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in } -// Checks if 'bl' should reflect back a spell cast by 'src'. -// type is the type of magic attack: 0: indirect (aoe), 1: direct (targetted) -// In case of success returns type of reflection, otherwise 0 -// 1 - Regular reflection (Maya) -// 2 - SL_KAITE reflection +/* + Checks if 'bl' should reflect back a spell cast by 'src'. + type is the type of magic attack: 0: indirect (aoe), 1: direct (targeted) + In case of success returns type of reflection, otherwise 0 + 1 - Regular reflection (Maya) + 2 - SL_KAITE reflection +*/ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) { struct status_change *sc = status->get_sc(bl); struct map_session_data* sd = BL_CAST(BL_PC, bl); @@ -2117,8 +2110,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr if(skill_id > 0 && !skill_lv) return 0; - nullpo_ret(src); //Source is the master behind the attack (player/mob/pet) - nullpo_ret(dsrc); //dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src. + nullpo_ret(src); // Source is the master behind the attack (player/mob/pet) + nullpo_ret(dsrc); // dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src. nullpo_ret(bl); //Target to be attacked. if (src != dsrc) { @@ -2126,7 +2119,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr if (!status->check_skilluse(battle_config.skill_caster_check?src:NULL, bl, skill_id, 2)) return 0; } else if ((flag&SD_ANIMATION) && skill->get_nk(skill_id)&NK_SPLASH) { - //Note that splash attacks often only check versus the targetted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex] + //Note that splash attacks often only check versus the targeted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex] if (!status->check_skilluse(src, bl, skill_id, 2)) return 0; } @@ -2134,6 +2127,14 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, bl); + // To block skills that aren't called via battle_check_target [Panikon] + // issue: 8203 + if( sd + && ( (bl->type == BL_MOB && pc_has_permission(sd, PC_PERM_DISABLE_PVM)) + || (bl->type == BL_PC && pc_has_permission(sd, PC_PERM_DISABLE_PVP)) ) + ) + return 0; + sstatus = status->get_status_data(src); tstatus = status->get_status_data(bl); sc = status->get_sc(bl); @@ -2180,7 +2181,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr sc = NULL; //Don't need it. /* bugreport:2564 flag&2 disables double casting trigger */ flag |= 2; - /* bugreport:7859 magical reflect'd zeroes blewcount */ + /* bugreport:7859 magical reflected zeroes blow count */ dmg.blewcount = 0; //Spirit of Wizard blocks Kaite's reflection if( type == 2 && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD ) @@ -2202,11 +2203,11 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr #if MAGIC_REFLECTION_TYPE #ifdef RENEWAL - if( dmg.dmg_lv != ATK_MISS ) //Wiz SL cancelled and consumed fragment + if( dmg.dmg_lv != ATK_MISS ) // Wiz SL canceled and consumed fragment #else // issue:6415 in pre-renewal Kaite reflected the entire damage received - // regardless of caster's equipament (Aegis 11.1) - if( dmg.dmg_lv != ATK_MISS && type == 1 ) //Wiz SL cancelled and consumed fragment + // regardless of caster's equipment (Aegis 11.1) + if( dmg.dmg_lv != ATK_MISS && type == 1 ) //Wiz SL canceled and consumed fragment #endif { short s_ele = skill->get_ele(skill_id, skill_lv); @@ -2229,7 +2230,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER); //Reduction: 6% + 6% every 20% dmg.damage -= dmg.damage * (6 * (1+per)) / 100; - } + } } #endif /* MAGIC_REFLECTION_TYPE */ } @@ -2324,10 +2325,11 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr combo=1; break; case AC_DOUBLE: - 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(NULL,src,SC_COMBOATTACK,100,HT_POWER,bl->id,2000); + // AC_DOUBLE can start the combo with other monster types, but the + // monster that's going to be hit by HT_POWER should be RC_BRUTE or RC_INSECT [Panikon] + if( pc->checkskill(sd, HT_POWER) ) + { + sc_start4(NULL,src,SC_COMBOATTACK,100,HT_POWER,0,1,0,2000); clif->combo_delay(src,2000); } break; @@ -2429,6 +2431,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr case EL_ROCK_CRUSHER_ATK: case EL_HURRICANE: case EL_HURRICANE_ATK: + case EL_TYPOON_MIS: + case EL_TYPOON_MIS_ATK: case KO_BAKURETSU: case NC_MAGMA_ERUPTION: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,5); @@ -2498,7 +2502,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr { //Updated to not be able to copy skills if the blow will kill you. [Skotlex] int copy_skill = skill_id, cidx = 0; /** - * Copy Referal: dummy skills should point to their source upon copying + * Copy Referral: dummy skills should point to their source upon copying **/ switch( skill_id ) { case AB_DUPLELIGHT_MELEE: @@ -2642,7 +2646,7 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr //blown-specific handling switch( skill_id ) { case LG_OVERBRAND_BRANDISH: - if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) < dmg.blewcount ) + if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) < dmg.blewcount ) skill->addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skill_lv, BF_WEAPON, flag|SD_ANIMATION); break; case SR_KNUCKLEARROW: @@ -2730,15 +2734,12 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr * Post-damage effects **/ switch( skill_id ) { - case RK_CRUSHSTRIKE: - skill->break_equip(src,EQP_WEAPON,2000,BCT_SELF); // 20% chance to destroy the weapon. - break; case GC_VENOMPRESSURE: { struct status_change *ssc = status->get_sc(src); if( ssc && ssc->data[SC_POISONINGWEAPON] && rnd()%100 < 70 + 5*skill_lv ) { short rate = 100; - if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reduceable. [Rytech] + if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )// Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] rate = 100 - tstatus->int_ * 4 / 5; sc_start(src, bl,ssc->data[SC_POISONINGWEAPON]->val2,rate,ssc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); status_change_end(src,SC_POISONINGWEAPON,-1); @@ -2773,8 +2774,8 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr } /*========================================== - * sub fonction for recursive skill call. - * Checking bl battle flag and display dammage + * sub function for recursive skill call. + * Checking bl battle flag and display damage * then call func with source,target,skill_id,skill_lv,tick,flag *------------------------------------------*/ int skill_area_sub(struct block_list *bl, va_list ap) { @@ -2965,7 +2966,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, if( (idx = skill->get_index(skill_id)) == 0 ) return 0; - // Requeriments + // Requirements for( i = 0; i < ARRAYLENGTH(itemid); i++ ) { itemid[i] = skill->db[idx].itemid[i]; @@ -2987,7 +2988,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, else sp += (st->max_sp * (-sp_rate)) / 100; - if( bl->type == BL_HOM ) { // Intimacy Requeriments + if( bl->type == BL_HOM ) { // Intimacy Requirements struct homun_data *hd = BL_CAST(BL_HOM, bl); switch( skill_id ) { case HFLI_SBR44: @@ -3095,10 +3096,11 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { case WL_TETRAVORTEX_WATER: case WL_TETRAVORTEX_WIND: case WL_TETRAVORTEX_GROUND: - case SR_FLASHCOMBO_ATK_STEP1: - case SR_FLASHCOMBO_ATK_STEP2: - case SR_FLASHCOMBO_ATK_STEP3: - case SR_FLASHCOMBO_ATK_STEP4: + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: break; default: continue; // Caster is Dead @@ -3122,6 +3124,9 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { map->foreachinarea(skill->frostjoke_scream,skl->map,skl->x-range,skl->y-range, skl->x+range,skl->y+range,BL_CHAR,src,skl->skill_id,skl->skill_lv,tick); break; + case KN_AUTOCOUNTER: + clif->skill_nodamage(src,target,skl->skill_id,skl->skill_lv,1); + break; case NPC_EARTHQUAKE: if( skl->type > 1 ) skill->addtimerskill(src,tick+250,src->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag); @@ -3160,7 +3165,7 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { BL_CHAR|BL_SKILL, target->id); // Search for a new Target around current one... if( nbl == NULL) skl->x++; - else + 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); @@ -3172,9 +3177,9 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { case WL_TETRAVORTEX_WIND: case WL_TETRAVORTEX_GROUND: 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->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 == 4 ){ + 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(src,target, scs[index], rate, skl->skill_lv, src->id, skill->get_time(WL_TETRAVORTEX,index+1)); @@ -3211,22 +3216,23 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { map->foreachinrange(skill->area_sub, target, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, src, skl->skill_id, skl->skill_lv, (int64)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]; - if( distance_xy(src->x, src->y, target->x, target->y) >= 3 ) - break; - skill->consume_requirement(sd,cid,pc->checkskill(sd, cid),1); - skill->castend_damage_id(src, target, cid, pc->checkskill(sd, cid), tick, 0); - } + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: + { + struct map_session_data *sd = NULL; + + if( src->type == BL_PC && (sd = ((TBL_PC*)src)) ) { + if( distance_xy(src->x, src->y, target->x, target->y) >= 3 ) // FIXME: Don't combos ignore distance? [Panikon] + break; + + skill->consume_requirement(sd, skl->skill_id, pc->checkskill(sd, skl->skill_id),1); + skill->castend_damage_id(src, target, skl->skill_id, pc->checkskill(sd, skl->skill_id), tick, 0); } break; + } case SC_ESCAPE: if( skl->type < 4+skl->skill_lv ){ clif->skill_damage(src,src,tick,0,0,-30000,1,skl->skill_id,skl->skill_lv,5); @@ -3344,10 +3350,11 @@ int skill_cleartimerskill (struct block_list *src) case WL_TETRAVORTEX_WATER: case WL_TETRAVORTEX_WIND: case WL_TETRAVORTEX_GROUND: - case SR_FLASHCOMBO_ATK_STEP1: - case SR_FLASHCOMBO_ATK_STEP2: - case SR_FLASHCOMBO_ATK_STEP3: - case SR_FLASHCOMBO_ATK_STEP4: + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: continue; } timer->delete(ud->skilltimerskill[i]->timer, skill->timerskill); @@ -3409,7 +3416,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 return 1; if (skill_id && skill->get_type(skill_id) == BF_MAGIC && status->isimmune(bl) == 100) { - //GTB makes all targetted magic display miss with a single bolt. + //GTB makes all targeted magic display miss with a single bolt. sc_type sct = status->skill2sc(skill_id); if(sct != SC_NONE) status_change_end(bl, sct, INVALID_TIMER); @@ -3492,7 +3499,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case WS_CARTTERMINATION: // Cart Termination case AS_VENOMKNIFE: case HT_PHANTASMIC: - case HT_POWER: case TK_DOWNKICK: case TK_COUNTER: case GS_CHAINACTION: @@ -3516,7 +3522,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case NPC_HELLPOWER: case RK_SONICWAVE: case RK_STORMBLAST: - case RK_CRUSHSTRIKE: case AB_DUPLELIGHT_MELEE: case RA_AIMEDBOLT: case NC_AXEBOOMERANG: @@ -3715,6 +3720,11 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 } break; + case HT_POWER: + if( tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT ) + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + break; + //Splash attack skills. case AS_GRIMTOOTH: case MC_CARTREVOLUTION: @@ -3769,6 +3779,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case KO_MUCHANAGE: case KO_BAKURETSU: case GN_ILLUSIONDOPING: + case MH_XENO_SLASHER: if( flag&1 ) {//Recursive invocation // skill->area_temp[0] holds number of targets in area // skill->area_temp[1] holds the id of the original target @@ -3796,6 +3807,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case GC_ROLLINGCUTTER: flag |= SD_ANIMATION; case LG_MOONSLASHER: + case MH_XENO_SLASHER: clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; case NPC_EARTHQUAKE://FIXME: Isn't EarthQuake a ground skill after all? @@ -4048,7 +4060,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); break; - // Celest + // [Celest] case PF_SOULBURN: if (rnd()%100 < (skill_lv < 5 ? 30 + skill_lv * 10 : 70)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -4133,7 +4145,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if( unit->movepos(src, bl->x+x, bl->y+y, 1, 1) ) { clif->slide(src,bl->x+x,bl->y+y); - clif->fixpos(src); // the official server send these two packts. + clif->fixpos(src); // the official server send these two packets. skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); if( rnd()%100 < 4 * skill_lv ) skill->castend_damage_id(src,bl,GC_CROSSIMPACT,skill_lv,tick,flag); @@ -4190,7 +4202,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case WL_TETRAVORTEX: if( sc ){ int i = SC_SUMMON5, x = 0; - int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 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; @@ -4266,7 +4278,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 if (sd->skillcooldown[i].id == spell_skill_id){ cooldown += sd->skillcooldown[i].val; break; - } + } } if(cooldown) skill->blockpc_start(sd, spell_skill_id, cooldown); @@ -4556,9 +4568,8 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 } break; - //recursive homon skill + // Recursive homun skill case MH_MAGMA_FLOW: - case MH_XENO_SLASHER: case MH_HEILIGE_STANGE: if(flag & 1) skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); @@ -4764,10 +4775,10 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { inf &= ~BCT_NEUTRAL; } - 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( 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 ) { @@ -4786,7 +4797,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { && (sc = status->get_sc(target)) && sc->data[SC_FOGWALL] && rnd() % 100 < 75 ) { - //Fogwall makes all offensive-type targetted skills fail at 75% + // Fogwall makes all offensive-type targeted skills fail at 75% if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); break; } @@ -4837,8 +4848,8 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { 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 + 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){ @@ -4881,7 +4892,7 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { // SC_MAGICPOWER needs to switch states before any damage is actually dealt skill->toggle_magicpower(src, ud->skill_id); - /* On aegis damage skills are also increase by camouflage. Need confirmation on kRo. + /* On aegis damage skills are also increase by camouflage. Need confirmation on kRO. 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); */ @@ -4978,7 +4989,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin int element = 0; enum sc_type type; - if(skill_id > 0 && !skill_lv) return 0; // celest + if(skill_id > 0 && !skill_lv) return 0; // [Celest] nullpo_retr(1, src); nullpo_retr(1, bl); @@ -5014,12 +5025,27 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } } + // Supportive skills that can't be cast in users with mado + if( sd && dstsd && pc_ismadogear(dstsd) ) { + switch( skill_id ) { + case AL_HEAL: + case AL_INCAGI: + case AL_DECAGI: + case AB_RENOVATIO: + case AB_HIGHNESSHEAL: + clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0); + return 0; + default: + break; + } + } + 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] + case HLIF_HEAL: // [orn] if (bl->type != BL_HOM) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ; break ; @@ -5031,11 +5057,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin **/ case AB_RENOVATIO: case AB_HIGHNESSHEAL: - case AL_INCAGI: - if( sd && dstsd && pc_ismadogear(dstsd) ){ - clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0); - return 0; - } + case AL_INCAGI: case ALL_RESURRECTION: case PR_ASPERSIO: //Apparently only player casted skills can be offensive like this. @@ -5090,7 +5112,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin 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 + ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homun 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) @@ -5133,7 +5155,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin map->freeblock_lock(); switch(skill_id) { - case HLIF_HEAL: //[orn] + case HLIF_HEAL: // [orn] case AL_HEAL: /** * Arch Bishop @@ -5489,7 +5511,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (dstsd) { if(dstsd->status.weapon == W_FIST || (dstsd->sc.count && !dstsd->sc.data[type] && - ( //Allow re-enchanting to lenghten time. [Skotlex] + ( //Allow re-enchanting to lengthen time. [Skotlex] dstsd->sc.data[SC_PROPERTYFIRE] || dstsd->sc.data[SC_PROPERTYWATER] || dstsd->sc.data[SC_PROPERTYWIND] || @@ -5594,7 +5616,6 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case PR_BENEDICTIO: case LK_BERSERK: case MS_BERSERK: - case KN_AUTOCOUNTER: case KN_TWOHANDQUICKEN: case KN_ONEHAND: case MER_QUICKEN: @@ -5667,6 +5688,11 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; + + case KN_AUTOCOUNTER: + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + skill->addtimerskill(src, tick + 100, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); + break; case SO_STRIKING: if (sd) { @@ -5707,7 +5733,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin { int duration = skill->get_time(skill_id,skill_lv); clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,duration)); // Master - clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,duration)); // Homunc + clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,duration)); // Homun } break; case NJ_BUNSINJYUTSU: @@ -6041,7 +6067,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; - case HVAN_EXPLOSION: //[orn] + case HVAN_EXPLOSION: // [orn] case NPC_SELFDESTRUCTION: { //Self Destruction hits everyone in range (allies+enemies) @@ -6174,7 +6200,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin return 0; } clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,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] + if (sd) // If the client receives a skill-use packet immediately 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: @@ -6410,7 +6436,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case MC_IDENTIFY: if(sd) { clif->item_identify_list(sd); - if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, dont consume anything, return */ + if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, don't consume anything, return */ map->freeblock_unlock(); return 1; } @@ -6752,7 +6778,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } 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. + || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends against dispel. || (dstsd && pc_ismadogear(dstsd)) || rnd()%100 >= 50+10*skill_lv ) { @@ -7062,7 +7088,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin 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. + md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the AI. } break; @@ -7128,14 +7154,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin 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] + int gain_hp = tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it cost the caster. [Skotlex] clif->skill_nodamage(src,bl,skill_id,status->heal(bl, gain_hp, 0, 0),1); } 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] + int gain_sp = tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it cost the caster. [Skotlex] clif->skill_nodamage(src,bl,skill_id,status->heal(bl, 0, gain_sp, 0),1); } break; @@ -7239,7 +7265,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin // if it is already trapping something don't spring it, // remove trap should be used instead break; - // otherwise fallthrough to below + // otherwise fall through to below case UNT_BLASTMINE: case UNT_SKIDTRAP: case UNT_LANDMINE: @@ -7472,7 +7498,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (count == -1) count = 3; else - count++; //Should not retrigger this one. + count++; //Should not re-trigger this one. break; case 7: // stop freeze or stoned { @@ -7687,7 +7713,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } break; - case AM_CALLHOMUN: //[orn] + case AM_CALLHOMUN: // [orn] if( sd ) { if (homun->call(sd)) clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); @@ -7705,7 +7731,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } break; - case HAMI_CASTLE: //[orn] + case HAMI_CASTLE: // [orn] if(rnd()%100 < 20*skill_lv && src != bl) { int x,y; @@ -7715,7 +7741,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin 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->skill_nodamage(src,src,skill_id,skill_lv,1); // Homun clif->slide(src,bl->x,bl->y) ; if (unit->movepos(bl,x,y,0,0)) { @@ -7734,7 +7760,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin else if (sd) clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; - case HVAN_CHAOTIC: //[orn] + case HVAN_CHAOTIC: // [orn] { static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}}; int r = rnd()%100; @@ -7755,7 +7781,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin status->heal(bl, hp, 0, 0); } break; - //Homun single-target support skills [orn] + // Homun single-target support skills [orn] case HAMI_BLOODLUST: case HFLI_FLEET: case HFLI_SPEED: @@ -8007,7 +8033,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin { // 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 + count = 10; // Max counter status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); } sc_start(src,bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv)); @@ -8113,15 +8139,12 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if( dstsd && dstsd->special_state.no_magic_damage ) break; - if ( sd && sd->status.party_id == 0 ) - count = 1; - else - count = party->foreachsamemap(party->sub_count, sd, 0); + if( sd && sd->status.party_id != 0 ) + count = party->foreachsamemap(party->sub_count, sd, 0); - if (count > 0) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, - sc_start4(src, bl, type, 100, skill_lv, 0, 0, count, skill->get_time(skill_id, skill_lv))); - } else + clif->skill_nodamage(bl, bl, skill_id, skill_lv, + sc_start4(src, bl, type, 100, skill_lv, 0, 0, count, 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 AB_CHEAL: @@ -8526,7 +8549,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin //First we set the success chance based on the caster's build which increases the chance. rate = 10 * skill_lv + rnd_value( sstatus->dex / 12, sstatus->dex / 4 ) + joblvbonus + status->get_lv(src) / 10; // We then reduce the success chance based on the target's build. - rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) - tstatus->luk / 10 - ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) - status->get_lv(bl) / 10; + rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) + tstatus->luk / 10 + ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) + status->get_lv(bl) / 10; //Finally we set the minimum success chance cap based on the caster's skill level and DEX. rate = cap_value( rate, skill_lv + sstatus->dex / 20, 100); clif->skill_nodamage(src,bl,skill_id,0,sc_start(src,bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv))); @@ -8539,7 +8562,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } if ( tsc && tsc->data[SC__UNLUCKY] && skill_id == SC_UNLUCKY) { //If the target was successfully inflected with the Unlucky status, give 1 of 3 random status's. - switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's reguardless of resistance. + switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's regardless of resistance. case 0: status->change_start(src,bl,SC_POISON,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); break; @@ -8568,9 +8591,11 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; case LG_SHIELDSPELL: + if( !sd ) + break; if( flag&1 ) { sc_start(src,bl,SC_SILENCE,100,skill_lv,sd->bonus.shieldmdef * 30000); - } else if( sd ) { + } else { int opt = 0, val = 0, splashrange = 0; struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; if( !shield_data || shield_data->type != IT_ARMOR ) { @@ -8607,6 +8632,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } break; case 2: + if( sd->bonus.shieldmdef == 0 ) + break; // Nothing should happen if the shield has no mdef, not even displaying a message if ( sd->bonus.shieldmdef >= 1 && sd->bonus.shieldmdef <= 3 ) splashrange = 1; else if ( sd->bonus.shieldmdef >= 4 && sd->bonus.shieldmdef <= 5 ) @@ -8634,8 +8661,12 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin break; case 3: { - struct item *shield = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; int rate = 0; + struct item *shield = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; + + if( shield->refine == 0 ) + break; // Nothing should happen if the shield has no refine, not even displaying a message + switch( opt ) { case 1: sc_start(src,bl,SC_SHIELDSPELL_REF,100,opt,shield->refine * 30000); //Now breaks Armor at 100% rate @@ -8723,7 +8754,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } else { int count = 0; clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - count = map->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors + count = map->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-characters 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, @@ -8749,8 +8780,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin { sp = dstsd->spiritball; //1%sp per spiritball. pc->delspiritball(dstsd, dstsd->spiritball, 0); + status_percent_heal(src, 0, sp); } - if( sp ) status_percent_heal(src, 0, sp); clif->skill_nodamage(src, bl, skill_id, skill_lv, sp ? 1:0); } else { clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); @@ -8801,16 +8832,23 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case SR_GENTLETOUCH_CHANGE: case SR_GENTLETOUCH_REVITALIZE: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); + sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv))); break; case SR_FLASHCOMBO: { + const int combo[] = { + SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW + }; int i; - 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 + 400 * (i - SR_FLASHCOMBO_ATK_STEP1), bl->id, 0, 0, i, skill_lv, BF_WEAPON, flag|SD_LEVEL); + + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv))); + + for( i = 0; i < ARRAYLENGTH(combo); i++ ) + skill->addtimerskill(src, tick + 400 * i, bl->id, 0, 0, combo[i], skill_lv, BF_WEAPON, flag|SD_LEVEL); + + break; } - break; case WA_SWING_DANCE: case WA_SYMPHONY_OF_LOVER: case WA_MOONLIT_SERENADE: @@ -8851,7 +8889,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if ( flag&1 ) sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); else if ( sd ) { - int rate = 4 * skill_lv + 2 * (sd ? pc->checkskill(sd,WM_LESSON) : 1) + status->get_lv(src) / 15 + (sd? sd->status.job_level:0) / 5; + int rate = 4 * skill_lv + 2 * pc->checkskill(sd,WM_LESSON) + status->get_lv(src)/15 + sd->status.job_level/5; if ( rnd()%100 < rate ) { flag |= BCT_PARTY|BCT_GUILD; map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_NPC|BL_SKILL, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); @@ -8868,7 +8906,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if( flag&1 ) { sc_start2(src,bl,type,100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv)); } else if( sd ) { - int rate = 6 * skill_lv + (sd ? pc->checkskill(sd,WM_LESSON) : 1) + (sd? sd->status.job_level:0) / 2; + int rate = 6 * skill_lv + pc->checkskill(sd,WM_LESSON) + sd->status.job_level/2; if ( rnd()%100 < rate ) { flag |= BCT_PARTY|BCT_GUILD; map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_NPC|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); @@ -8912,7 +8950,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sc_start(src, bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); if ( madnesscheck >= 8 )//The god of madness deals 9999 fixed unreduceable damage when 8 or more enemy players are affected. status_fix_damage(src, bl, 9999, clif->damage(src, bl, 0, 0, 9999, 0, 0, 0)); - //skill->attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);//To renable when I can confirm it deals damage like this. Data shows its dealed as reflected damage which I dont have it coded like that yet. [Rytech] + //skill->attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);//To renable when I can confirm it deals damage like this. Data shows its dealt as reflected damage which I don't have it coded like that yet. [Rytech] } else if( sd ) { int rate = sstatus->int_ / 6 + (sd? sd->status.job_level:0) / 5 + skill_lv * 4; if ( rnd()%100 < rate ) { @@ -9038,7 +9076,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if( sd ) { int elemental_class = skill->get_elemental_type(skill_id,skill_lv); - // Remove previous elemental fisrt. + // Remove previous elemental first. if( sd->ed ) elemental->delete(sd->ed,0); @@ -9061,7 +9099,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin elemental->delete(sd->ed, 0); break; } - switch( skill_lv ) {// Select mode bassed on skill level used. + switch( skill_lv ) {// Select mode based on skill level used. case 2: mode = EL_MODE_ASSIST; break; case 3: mode = EL_MODE_AGGRESSIVE; break; } @@ -9397,10 +9435,23 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } break; + case MH_LIGHT_OF_REGENE: + if( hd && battle->get_master(src) ) { + hd->homunculus.intimacy = (751 + rnd()%99) * 100; // random between 751 ~ 850 + clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100); //refresh intimacy info + sc_start(src, battle->get_master(src), type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + } + break; + + case MH_OVERED_BOOST: + if ( hd && battle->get_master(src) ) { + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, battle->get_master(src), type, 100, skill_lv, 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_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION }; @@ -9410,40 +9461,15 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin 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(src, 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, 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(src, 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)); + heal = 5 * status->get_lv(&hd->bl) + status->base_matk(&hd->battle_status, status->get_lv(&hd->bl)); + status->heal(bl, heal, 0, 0); + clif->skill_nodamage(src, src, skill_id, skill_lv, clif->skill_nodamage(src, bl, AL_HEAL, heal, 1)); + status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); + status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); } 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(src, s_bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); //gene bonus - } - sc_start(src, 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: if( hd ){ @@ -9458,12 +9484,6 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin } break; - case MH_LIGHT_OF_REGENE: - if(hd) { - hd->homunculus.intimacy = 25100; //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_MAGMA_FLOW: case MH_PAIN_KILLER: sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); @@ -9759,10 +9779,15 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char switch(skill_id) { case AL_TELEPORT: + // The storage window is closed automatically by the client when there's + // any kind of map change, so we need to restore it automatically + // issue: 8027 if(strcmp(mapname,"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); + + clif->refresh_storagewindow(sd); break; case AL_WARP: @@ -9852,7 +9877,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui int r; //if(skill_lv <= 0) return 0; - if(skill_id > 0 && !skill_lv) return 0; // celest + if(skill_id > 0 && !skill_lv) return 0; // [Celest] nullpo_ret(src); @@ -10047,10 +10072,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case MH_VOLCANIC_ASH: case MH_POISON_MIST: case MH_STEINWAND: - case MH_XENO_SLASHER: case NC_MAGMA_ERUPTION: case SO_ELEMENTAL_SHIELD: case RL_B_TRAP: + case MH_XENO_SLASHER: 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); @@ -10158,7 +10183,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui int class_ = skill_id==AM_SPHEREMINE?1142:summons[skill_lv-1]; struct mob_data *md; - // Correct info, don't change any of this! [celest] + // Correct info, don't change any of this! [Celest] md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_MEDIUM, AI_NONE); if (md) { md->master_id = src->id; @@ -10298,7 +10323,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sc_start(src,src,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case AM_RESURRECTHOMUN: //[orn] + case AM_RESURRECTHOMUN: // [orn] if (sd) { if (!homun->ressurect(sd, 20*skill_lv, x, y)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -10320,7 +10345,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case WM_SOUND_OF_DESTRUCTION: r = skill->get_splash(skill_id,skill_lv); map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - break; + break; case WM_LULLABY_DEEPSLEEP: r = skill->get_splash(skill_id,skill_lv); @@ -10610,14 +10635,22 @@ int skill_dance_overlap(struct skill_unit* su, int flag) { return map->foreachincell(skill->dance_overlap_sub, su->bl.m,su->bl.x,su->bl.y,BL_SKILL, su,flag); } -/*========================================== +/** * Converts this group information so that it is handled as a Dissonance or Ugly Dance cell. - * Flag: 0 - Convert, 1 - Revert. - *------------------------------------------*/ + * This function is safe to call even when the unit or the group were freed by other function + * previously. + * @param su Skill unit data (from BA_DISSONANCE or DC_UGLYDANCE) + * @param flag 0 Convert + * @param flag 1 Revert + * @retval true success + **/ bool skill_dance_switch(struct skill_unit* su, int flag) { static int prevflag = 1; // by default the backup is empty static struct skill_unit_group backup; - struct skill_unit_group* group = su->group; + struct skill_unit_group* group; + + if( su == NULL || (group = su->group) == NULL ) + return false; // val2&UF_ENSEMBLE is a hack to indicate dissonance if ( !(group->state.song_dance&0x1 && su->val2&UF_ENSEMBLE) ) @@ -11674,7 +11707,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_FIREPILLAR_ACTIVE: case UNT_CLAYMORETRAP: if( sg->unit_id == UNT_FIRINGTRAP || sg->unit_id == UNT_ICEBOUNDTRAP || sg->unit_id == UNT_CLAYMORETRAP ) - map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &src->bl,tick); + map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &src->bl,tick); else map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); if (sg->unit_id != UNT_FIREPILLAR_ACTIVE) @@ -11876,7 +11909,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_POISONSMOKE: if( battle->check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 50 ) { short rate = 100; - if ( sg->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reduceable. [Rytech] + if ( sg->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] rate = 100 - tstatus->int_ * 4 / 5 ; sc_start(ss,bl,sg->val2,rate,sg->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); } @@ -11911,7 +11944,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_STEALTHFIELD: if( bl->id == sg->src_id ) - break; // Dont work on Self (video shows that) + break; // Don't work on Self (video shows that) case UNT_NEUTRALBARRIER: sc_start(ss,bl,type,100,sg->skill_lv,sg->interval + 100); break; @@ -12193,8 +12226,8 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { //We don't check for SC_LONGING because someone could always have knocked you back and out of the song/dance. //FIXME: This code is not perfect, it doesn't checks for the real ensemble's owner, //it only checks if you are doing the same ensemble. So if there's two chars doing an ensemble - //which overlaps, by stepping outside of the other parther's ensemble will cause you to cancel - //your own. Let's pray that scenario is pretty unlikely and noone will complain too much about it. + //which overlaps, by stepping outside of the other partner's ensemble will cause you to cancel + //your own. Let's pray that scenario is pretty unlikely and none will complain too much about it. status_change_end(bl, SC_DANCING, INVALID_TIMER); } case MH_STEINWAND: @@ -12240,7 +12273,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { if (sce) { status_change_end(bl, type, INVALID_TIMER); if ((sce=sc->data[SC_BLIND])) { - if (bl->type == BL_PC) //Players get blind ended inmediately, others have it still for 30 secs. [Skotlex] + if (bl->type == BL_PC) //Players get blind ended immediately, others have it still for 30 secs. [Skotlex] status_change_end(bl, SC_BLIND, INVALID_TIMER); else { timer->delete(sce->timer, status->change_timer); @@ -12646,6 +12679,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id // Check the skills that can be used while mounted on a warg if( pc_isridingwug(sd) ) { switch( skill_id ) { + // Hunter skills case HT_SKIDTRAP: case HT_LANDMINE: case HT_ANKLESNARE: @@ -12655,43 +12689,39 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case HT_FREEZINGTRAP: case HT_BLASTMINE: case HT_CLAYMORETRAP: - case HT_SPRINGTRAP: + case HT_TALKIEBOX: + // Ranger skills case RA_DETONATOR: + case RA_ELECTRICSHOCKER: case RA_CLUSTERBOMB: - case HT_TALKIEBOX: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: case RA_WUGDASH: case RA_WUGRIDER: case RA_WUGSTRIKE: + // Other + case BS_GREED: break; default: // in official there is no message. return 0; } } + + // Check the skills that can be used whiled using mado if( pc_ismadogear(sd) ) { - switch( skill_id ) { //None Mado skills are unusable when Mado is equipped. [Jobbie] - case BS_REPAIRWEAPON: - case WS_MELTDOWN: - case BS_HAMMERFALL: - case WS_CARTBOOST: - case BS_ADRENALINE: - case WS_WEAPONREFINE: - case BS_WEAPONPERFECT: - case WS_CARTTERMINATION: - case BS_OVERTHRUST: - case WS_OVERTHRUSTMAX: - case BS_MAXIMIZE: - case BS_ADRENALINE2: - case BS_UNFAIRLYTRICK: - case BS_GREED: - clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); - return 0; - default: //Only Mechanic exlcusive skill can be used. - break; + if( !(skill_id > NC_MADOLICENCE && skill_id <= NC_DISJOINT) + && skill_id != NC_MAGMA_ERUPTION + && skill_id != BS_GREED ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); + return 0; } } + if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) return 0; @@ -13001,7 +13031,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } break; - case AM_REST: //Can't vapo homun if you don't have an active homunc or it's hp is < 80% + case AM_REST: //Can't vapo homun if you don't have an active homun or it's hp is < 80% if (!homun_alive(sd->hd) || sd->hd->battle_status.hp < (sd->hd->battle_status.max_hp*80/100)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -13042,14 +13072,17 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case WL_COMET: { int idx; + + if( !require.itemid[0] ) // issue: 7935 + break; if( skill->check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && ((idx = pc->search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[idx].amount < require.amount[0]) ) { //clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } - } break; + } case WL_SUMMONFB: case WL_SUMMONBL: case WL_SUMMONWB: @@ -13059,7 +13092,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id { int j, i = 0; for(j = SC_SUMMON1; j <= SC_SUMMON5; j++) - if( sc && sc->data[j] ) + if( sc && sc->data[j] ) i++; switch(skill_id){ @@ -13438,7 +13471,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id // There's no need to check if the skill is part of a combo if it's // already been checked before, see unit_skilluse_id2 [Panikon] - // Note that if this check is readded part of issue:8047 will reapear! + // Note that if this check is read part of issue:8047 will reappear! //if( sd->sc.data[SC_COMBOATTACK] && !skill->is_combo(skill_id ) ) // return 0; @@ -13686,7 +13719,7 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin continue; 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. + continue; //Gemstones are checked, but not subtracted from inventory. switch( skill_id ){ case SA_SEISMICWEAPON: @@ -13881,7 +13914,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN ) { if( sd->special_state.no_gemstone ) - { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card -helvetica + { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card [helvetica] if( skill_id != SA_ABRACADABRA ) req.itemid[i] = req.amount[i] = 0; else if( --req.amount[i] < 1 ) @@ -14129,9 +14162,9 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 if( sd->bonus.varcastrate < 0 ) VARCAST_REDUCTION(sd->bonus.varcastrate); if( sd->bonus.add_varcast != 0 ) // bonus bVariableCast - time += sd->bonus.add_varcast; + time += sd->bonus.add_varcast; if( sd->bonus.add_fixcast != 0 ) // bonus bFixedCast - fixed += sd->bonus.add_fixcast; + fixed += sd->bonus.add_fixcast; for (i = 0; i < ARRAYLENGTH(sd->skillfixcast) && sd->skillfixcast[i].id; i++) if (sd->skillfixcast[i].id == skill_id){ // bonus2 bSkillFixedCast fixed += sd->skillfixcast[i].val; @@ -14202,7 +14235,7 @@ int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 fixcast_r = max(fixcast_r, sc->data[SC_DANCE_WITH_WUG]->val4); 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) ) + 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] ) @@ -15038,7 +15071,7 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) { if( su == NULL || su->group == NULL || (*alive) == 0 ) return 0; - if( su->group->state.guildaura ) /* guild auras are not cancelled! */ + if( su->group->state.guildaura ) /* guild auras are not canceled! */ return 0; switch (skill_id) { @@ -15290,6 +15323,36 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce return wall; } + +/** + * Verifies if an user can use SC_CLOAKING + **/ +bool skill_can_cloak(struct map_session_data *sd) { + nullpo_retr(false, sd); + + //Avoid cloaking with no wall and low skill level. [Skotlex] + //Due to the cloaking card, we have to check the wall versus to known + //skill level rather than the used one. [Skotlex] + //if (sd && val1 < 3 && skill_check_cloaking(bl,NULL)) + if (pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(&sd->bl,NULL)) + return false; + + return true; +} + +/** + * Verifies if an user can still be cloaked (AS_CLOAKING) + * Is called via map->foreachinrange when any kind of wall disapears + **/ +int skill_check_cloaking_end(struct block_list *bl, va_list ap) { + TBL_PC *sd = BL_CAST(BL_PC, bl); + + if (sd && sd->sc.data[SC_CLOAKING] && !skill->can_cloak(sd)) + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + + return 0; +} + bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce) { static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; @@ -15328,7 +15391,7 @@ bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit){ if( sc && sc->data[SC__SHADOWFORM] && damage ) { src = map->id2bl(sc->data[SC__SHADOWFORM]->val2); - if( !src || src->m != bl->m ) { + if( !src || src->m != bl->m ) { status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); return false; } @@ -15438,6 +15501,13 @@ int skill_delunit (struct skill_unit* su) { clif->changemapcell(0,su->bl.m,su->bl.x,su->bl.y,su->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug skill->unitsetmapcell(su,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false); map->list[su->bl.m].icewall_num--; + // AS_CLOAKING in low levels requires a wall to be cast, thus it needs to be + // checked again when a wall disapears! issue:8182 [Panikon] + map->foreachinarea(skill->check_cloaking_end, su->bl.m, + // Use 3x3 area to check for users near cell + su->bl.x - 1, su->bl.y - 1, + su->bl.x + 1, su->bl.x + 1, + BL_PC); break; case SA_LANDPROTECTOR: skill->unitsetmapcell(su,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false); @@ -15452,7 +15522,7 @@ int skill_delunit (struct skill_unit* su) { } break; case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info) - if( group->val2 ) { // Someone Traped + if( group->val2 ) { // Someone Trapped struct status_change *tsc = status->get_sc(map->id2bl(group->val2)); if( tsc && tsc->data[SC__MANHOLE] ) tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID @@ -15599,7 +15669,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin struct status_change* sc = status->get_sc(src); if (sc && sc->data[SC_DANCING]) { - sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to redelete the group. [Skotlex] + sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to re-delete the group. [Skotlex] status_change_end(src, SC_DANCING, INVALID_TIMER); } } @@ -15981,7 +16051,7 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { return 0; } /*========================================== - * Executes on all skill units every SKILLUNITTIMER_INTERVAL miliseconds. + * Executes on all skill units every SKILLUNITTIMER_INTERVAL milliseconds. *------------------------------------------*/ int skill_unit_timer(int tid, int64 tick, int id, intptr_t data) { map->freeblock_lock(); @@ -16073,9 +16143,6 @@ int skill_unit_move_sub(struct block_list* bl, va_list ap) { } } - //TODO: Normally, this is dangerous since the unit and group could be freed - //inside the onout/onplace functions. Currently it is safe because we know song/dance - //cells do not get deleted within them. [Skotlex] if( dissonance ) skill->dance_switch(su, 1); if( flag&4 ) @@ -16388,7 +16455,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, make_per = 100000; // Star Crumbs are 100% success crafting rate? (made 1000% so it succeeds even after penalties) [Skotlex] break; default: // Enchanted Stones - make_per += 1000+i*500; // Enchantedstone Craft bonus: +15/+20/+25/+30/+35 + make_per += 1000+i*500; // Enchanted stone Craft bonus: +15/+20/+25/+30/+35 break; } break; @@ -16436,7 +16503,7 @@ int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, case ITEMID_COATING_BOTTLE: make_per -= (1+rnd()%100)*10; break; - //Common items, recieve no bonus or penalty, listed just because they are commonly produced + //Common items, receive no bonus or penalty, listed just because they are commonly produced case ITEMID_BLUE_POTION: case ITEMID_RED_SLIM_POTION: case ITEMID_ANODYNE: @@ -17339,7 +17406,7 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick) return 0; } -int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { //[orn] +int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { // [orn] struct homun_data *hd = (TBL_HOM*)map->id2bl(id); if (data <= 0 || data >= MAX_SKILL) return 0; @@ -17348,7 +17415,7 @@ int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { //[orn] return 1; } -int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { //[orn] +int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { // [orn] uint16 idx = skill->get_index(skill_id); nullpo_retr (-1, hd); @@ -17364,7 +17431,7 @@ int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { / return timer->add(timer->gettick() + tick, skill->blockhomun_end, hd->bl.id, idx); } -int skill_blockmerc_end(int tid, int64 tick, int id, intptr_t data) {//[orn] +int skill_blockmerc_end(int tid, int64 tick, int id, intptr_t data) {// [orn] struct mercenary_data *md = (TBL_MER*)map->id2bl(id); if( data <= 0 || data >= MAX_SKILL ) return 0; @@ -17952,7 +18019,7 @@ bool skill_parse_row_requiredb(char* split[], int columns, int current) { skill->split_atoi(split[5],skill->db[idx].sp_rate); skill->split_atoi(split[6],skill->db[idx].zeny); - //Wich weapon type are required, see doc/item_db for types + //Which weapon type are required, see doc/item_db for types p = split[7]; for( j = 0; j < 32; j++ ) { int l = atoi(p); @@ -18449,7 +18516,7 @@ void skill_defaults(void) { memset(&skill->area_temp,0,sizeof(skill->area_temp)); memset(&skill->unit_temp,0,sizeof(skill->unit_temp)); skill->unit_group_newid = 0; - /* accesssors */ + /* accessors */ skill->get_index = skill_get_index; skill->get_type = skill_get_type; skill->get_hit = skill_get_hit; @@ -18520,7 +18587,7 @@ void skill_defaults(void) { skill->unit_onplace = skill_unit_onplace; skill->unit_ondamaged = skill_unit_ondamaged; skill->cast_fix = skill_castfix; - skill->cast_fix_sc = skill_castfix_sc; + skill->cast_fix_sc = skill_castfix_sc; skill->vf_cast_fix = skill_vfcastfix; skill->delay_fix = skill_delay_fix; skill->check_condition_castbegin = skill_check_condition_castbegin; @@ -18540,6 +18607,8 @@ void skill_defaults(void) { skill->autospell = skill_autospell; skill->calc_heal = skill_calc_heal; skill->check_cloaking = skill_check_cloaking; + skill->check_cloaking_end = skill_check_cloaking_end; + skill->can_cloak = skill_can_cloak; skill->enchant_elemental_end = skill_enchant_elemental_end; skill->not_ok = skillnotok; skill->not_ok_hom = skillnotok_hom; |