From 98cabc236656a475473c7b4c07a81210a1eb9541 Mon Sep 17 00:00:00 2001 From: rud0lp20 Date: Mon, 23 Jul 2012 15:00:12 +0000 Subject: Updated most Ranger skills to its official behavior and damage formula.(bugreport:5272, bugreport:6249, bugreport:5548, bugreport:5888) Fixed issues with traps: (bugreport:5906) - if RA_REASERCHTRAP is learned Alloy Traps can now be used to Hunter traps. - if Hunter traps expire it will now return either Booby Trap or Alloy Trap depending on item used. - some traps should now give full damage to plants. - update list of skills that can hit/damage/affect traps. - damage through skills can now be shown when hitting traps. - proper knock back behaviors - proper animation when triggers and triggering of item bonus script 'bHPDrainRate' Fixed an issues where some skills cannot damage UNT_REVERBERATION/UNT_POEMOFNETHERWORLD and doesn't deal 1 damage Updated some official behavior where informational must shown when hitting, targeting, casting skills to targets. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16483 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/battle.c | 121 +++++++++++++++++++++++------ src/map/pc.c | 3 +- src/map/skill.c | 227 ++++++++++++++++++++++++++++++++++--------------------- src/map/skill.h | 1 + src/map/status.c | 33 ++++---- src/map/unit.c | 13 ++-- 6 files changed, 263 insertions(+), 135 deletions(-) (limited to 'src/map') diff --git a/src/map/battle.c b/src/map/battle.c index a9c8ba6ea..a04f3c328 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1275,10 +1275,14 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo //Initial flag flag.rh=1; flag.weapon=1; - flag.infdef=(tstatus->mode&MD_PLANT&&skill_num!=RA_CLUSTERBOMB?1:0); + flag.infdef=(tstatus->mode&MD_PLANT && skill_num != RA_CLUSTERBOMB +#ifdef RENEWAL + && skill_num != 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) + if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) flag.infdef = 1; } @@ -1466,6 +1470,8 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo 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); @@ -1782,10 +1788,12 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case MA_CHARGEARROW: skillratio += 50; break; +#ifndef RENEWAL case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: skillratio += -50+10*skill_lv; break; +#endif case KN_PIERCE: case ML_PIERCE: skillratio += 10*skill_lv; @@ -2162,13 +2170,13 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo 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()%2; + wd.div_ = tstatus->size + 2 + ( (rnd()%100 < 50-tstatus->size*10) ? 1 : 0 ); break; case RA_CLUSTERBOMB: skillratio += 100 + 100 * skill_lv; break; - case RA_WUGDASH: - skillratio = 500; + case RA_WUGDASH:// ATK 300% + skillratio += 200; break; case RA_WUGSTRIKE: skillratio = 200 * skill_lv; @@ -2495,7 +2503,13 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case NJ_SYURIKEN: ATK_ADD(4*skill_lv); break; - case RA_WUGDASH: + case HT_FREEZINGTRAP: + if(sd) + ATK_ADD( 40 * pc_checkskill(sd, RA_RESEARCHTRAP) ); + break; + case RA_WUGDASH://(Caster’s Current Weight x 10 / 8) + if( sd && sd->weight ) + ATK_ADD( sd->weight / 8 ); case RA_WUGSTRIKE: case RA_WUGBITE: if(sd) @@ -2659,6 +2673,12 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if( tsc && tsc->data[SC_GT_REVITALIZE] && tsc->data[SC_GT_REVITALIZE]->val4 ) def2 += 2 * tsc->data[SC_GT_REVITALIZE]->val4; + if( tsc && tsc->data[SC_CAMOUFLAGE] ){ + i = 5 * (10-tsc->data[SC_CAMOUFLAGE]->val4); + 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); @@ -2744,6 +2764,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if( (bl = map_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) ); } //Refine bonus @@ -3275,7 +3298,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //Skill Range Criteria ad.flag |= battle_range_type(src, target, skill_num, 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_num) { case MG_FIREWALL: @@ -3960,12 +3988,9 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case MA_LANDMINE: case HT_BLASTMINE: case HT_CLAYMORETRAP: - { - int level = sd?sd->status.base_level:status_get_lv(src); - md.damage = skill_lv*sstatus->dex*(3+level/100)*(1+sstatus->int_/35); - md.damage+= md.damage*(rnd()%20-10)/100; - md.damage+= 40*(sd?pc_checkskill(sd,RA_RESEARCHTRAP):0); - } + 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 case HT_LANDMINE: @@ -4071,10 +4096,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case RA_CLUSTERBOMB: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - md.damage = (2 * skill_lv * (sstatus->dex + 100)); - md.damage = md.damage * 2;// Without BaseLv Bonus + md.damage = skill_lv * sstatus->dex + sstatus->int_ * 5 ; RE_LVL_TMDMOD(); - md.damage = md.damage + (5 * sstatus->int_) + (40 * ( sd ? pc_checkskill(sd,RA_RESEARCHTRAP) : 10 ) ); + md.damage = md.damage * (20 * ( sd ? pc_checkskill(sd,RA_RESEARCHTRAP) : 10 ) ); + md.damage = (md.damage?md.damage:1) / (skill_num == RA_CLUSTERBOMB?50:100); break; /** * Mechanic @@ -4185,8 +4210,24 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if(md.damage < 0) md.damage = 0; - else if(md.damage && tstatus->mode&MD_PLANT) - md.damage = 1; + else if(md.damage && tstatus->mode&MD_PLANT){ + switch(skill_num){ + case HT_LANDMINE: + case MA_LANDMINE: + case HT_BLASTMINE: + case HT_CLAYMORETRAP: + case RA_CLUSTERBOMB: +#ifdef RENEWAL + break; +#endif + 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; + } if(!(nk&NK_NO_ELEFIX)) md.damage=battle_attr_fix(src, target, md.damage, s_ele, tstatus->def_ele, tstatus->ele_lv); @@ -4198,9 +4239,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage=battle_calc_bg_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag); switch( skill_num ) { - case RA_CLUSTERBOMB: 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_num,skill_lv,mflag); @@ -4554,7 +4596,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if( sc->data[SC_GIANTGROWTH] && (wd.flag&BF_SHORT) && rnd()%100 < sc->data[SC_GIANTGROWTH]->val2 ) wd.damage *= 3; // Triple Damage - if( sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0 && sd->status.inventory[sd->equip_index[EQI_AMMO]].amount >= sc->data[SC_FEARBREEZE]->val4 && battle_config.arrow_decrement){ + if( sd && sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0 && sd->status.inventory[sd->equip_index[EQI_AMMO]].amount >= sc->data[SC_FEARBREEZE]->val4 && battle_config.arrow_decrement){ pc_delitem(sd,sd->equip_index[EQI_AMMO],sc->data[SC_FEARBREEZE]->val4,0,1,LOG_TYPE_CONSUME); sc->data[SC_FEARBREEZE]->val4 = 0; } @@ -4592,7 +4634,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (sd && sd->bonus.splash_range > 0 && damage > 0) skill_castend_damage_id(src, target, 0, 1, tick, 0); - + if ( target->type == BL_SKILL && damage > 0 ){ + TBL_SKILL *su = (TBL_SKILL*)target; + if( su->group && su->group->skill_id == HT_BLASTMINE) + skill_blown(src, target, 3, -1, 0); + } map_freeblock_lock(); battle_delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion); @@ -4843,6 +4889,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return 0; if( skill_get_inf2(su->group->skill_id)&INF2_TRAP ) { //Only a few skills can target traps... switch( battle_getcurrentskill(src) ) { + case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps + if( !map[m].flag.pvp && !map[m].flag.gvg ) + break; case 0://you can hit them without skills case MA_REMOVETRAP: case HT_REMOVETRAP: @@ -4855,15 +4904,37 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case RA_DETONATOR: case RA_SENSITIVEKEEN: case GN_CRAZYWEED: + case RK_STORMBLAST: + case RK_PHANTOMTHRUST: + case SR_RAMPAGEBLASTER: + case NC_COLDSLOWER: + case NC_SELFDESTRUCTION: +#ifdef RENEWAL + case KN_BOWLINGBASH: + case KN_SPEARSTAB: + case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: + case MO_FINGEROFFENSIVE: + case MO_INVESTIGATE: + case MO_TRIPLEATTACK: + case MO_EXTREMITYFIST: + case CR_HOLYCROSS: + case ASC_METEORASSAULT: + case RG_RAID: + case MC_CARTREVOLUTION: +#endif state |= BCT_ENEMY; strip_enemy = 0; break; - default: - return 0; + default: + if(su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD){ + state |= BCT_ENEMY; + strip_enemy = 0; + }else + return 0; } } else if (su->group->skill_id==WZ_ICEWALL || - su->group->skill_id == GN_WALLOFTHORN || - su->group->skill_id == WM_REVERBERATION) { + su->group->skill_id == GN_WALLOFTHORN) { state |= BCT_ENEMY; strip_enemy = 0; } else //Excepting traps and icewall, you should not be able to target skills. diff --git a/src/map/pc.c b/src/map/pc.c index f918ce9ca..007c4ee67 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4789,7 +4789,8 @@ int pc_checkallowskill(struct map_session_data *sd) SC_ADRENALINE, SC_ADRENALINE2, SC_DANCING, - SC_GATLINGFEVER + SC_GATLINGFEVER, + SC_FEARBREEZE }; const enum sc_type scs_list[] = { SC_AUTOGUARD, diff --git a/src/map/skill.c b/src/map/skill.c index 458cf7518..2eb778f8c 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -119,7 +119,11 @@ static int skill_destroy_trap( struct block_list *bl, va_list ap ); //Since only mob-casted splash skills can hit ice-walls static inline int splash_target(struct block_list* bl) { +#ifndef RENEWAL return ( bl->type == BL_MOB ) ? BL_SKILL|BL_CHAR : BL_CHAR; +#else // Some skills can now hit ground skills(traps, ice wall & etc.) + return BL_SKILL|BL_CHAR; +#endif } /// Returns the id of the skill, or 0 if not found. @@ -803,6 +807,8 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int if((sce=sc->data[SC_EDP])) sc_start4(bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0, skill_get_time2(ASC_EDP,sce->val1)); + // Cancels on normal attack but benefits with the bonuses + status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); } } break; @@ -1161,23 +1167,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int sc_start(bl,SC_FREEZE,100,skilllv,skill_get_time(skillid,skilllv)); break; case RA_WUGBITE: - { - int chance = (50+10*skilllv)-(sstatus->agi/4) + (sd ? pc_checkskill(sd,RA_TOOTHOFWUG)*2 : 0); - if(chance < 50) chance = 50; - sc_start(bl, SC_BITE, chance, skilllv, (skilllv + (sd ? pc_checkskill(sd,RA_TOOTHOFWUG)/2 : 0)) * 1000); - break; - } + sc_start(bl, SC_BITE, (sd ? pc_checkskill(sd,RA_TOOTHOFWUG)*2 : 0), skilllv, (skilllv*1000 + (sd ? pc_checkskill(sd,RA_TOOTHOFWUG)*500 : 0)) ); + break; case RA_SENSITIVEKEEN: if( rnd()%100 < 8 * skilllv ) skill_castend_damage_id(src, bl, RA_WUGBITE, sd ? pc_checkskill(sd, RA_WUGBITE):skilllv, tick, SD_ANIMATION); break; - case RA_MAGENTATRAP: - case RA_COBALTTRAP: - case RA_MAIZETRAP: - case RA_VERDURETRAP: - if( dstmd && !(dstmd->status.mode&MD_BOSS) ) - sc_start2(bl,SC_ELEMENTALCHANGE,100,skilllv,skill_get_ele(skillid,skilllv),skill_get_time2(skillid,skilllv)); - break; case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: sc_start(bl, (skillid == RA_FIRINGTRAP) ? SC_BURNING:SC_FREEZING, 40 + 10 * skilllv, skilllv, skill_get_time2(skillid, skilllv)); @@ -2023,9 +2018,8 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in break; case BL_SKILL: su = (struct skill_unit *)target; - if( su && su->group && (su->group->unit_id == UNT_ANKLESNARE || su->group->unit_id == UNT_ELECTRICSHOCKER - || su->group->unit_id == UNT_CLUSTERBOMB || su->group->unit_id == UNT_REVERBERATION) ) - return 0; // ankle snare, electricshocker, clusterbomb, reverberation cannot be knocked back + if( su && su->group && su->group->unit_id == UNT_ANKLESNARE ) + return 0; // ankle snare cannot be knocked back break; } @@ -2378,7 +2372,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; case EL_STONE_RAIN: dmg.dmotion = clif_skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skillid,-1,(flag&1)?8:5); - break; + break; case WM_SEVERE_RAINSTORM_MELEE: dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,WM_SEVERE_RAINSTORM,skilllv,5); break; @@ -2386,13 +2380,24 @@ 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 HT_CLAYMORETRAP: + case HT_BLASTMINE: + case HT_FLASHER: + case HT_FREEZINGTRAP: + case RA_CLUSTERBOMB: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + clif_skill_damage((bl->type==BL_PC)?dsrc:src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid,flag&SD_LEVEL?-1:skilllv, 5); + case HT_LANDMINE: + dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, -1, type); + 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) */ default: if( flag&SD_ANIMATION && dmg.div_ < 2 ) //Disabling skill animation doesn't works on multi-hit. type = 5; - dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, flag&SD_LEVEL?-1:skilllv, type); + dmg.dmotion = clif_skill_damage((bl->type==BL_PC)?dsrc:src,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, flag&SD_LEVEL?-1:skilllv, type); break; } @@ -2479,16 +2484,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } } } - if( skillid != WZ_SIGHTRASHER && - skillid != WZ_SIGHTBLASTER && - skillid != AC_SHOWER && skillid != MA_SHOWER && - skillid != SM_MAGNUM && skillid != MS_MAGNUM && - bl->type == BL_SKILL && damage > 0 ) - { - struct skill_unit* su = (struct skill_unit*)bl; - if (su->group && skill_get_inf2(su->group->skill_id)&INF2_TRAP) - damage = 0; //Sight rasher, blaster, and arrow shower may dmg traps. [Kevin] - } if (dmg.dmg_lv >= ATK_MISS && (type = skill_get_walkdelay(skillid, skilllv)) > 0) { //Skills with can't walk delay also stop normal attacking for that @@ -2565,6 +2560,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; default: skill_blown(dsrc,bl,dmg.blewcount,direction, 0x0 ); + if ( !dmg.blewcount && bl->type == BL_SKILL && damage > 0 ){ + TBL_SKILL *su = (TBL_SKILL*)bl; + if( su->group && su->group->skill_id == HT_BLASTMINE) + skill_blown(src, bl, 3, -1, 0); + } break; } } @@ -2606,7 +2606,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if(skillid == CR_GRANDCROSS || skillid == NPC_GRANDDARKNESS) dmg.flag |= BF_WEAPON; - if( sd && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) ) && damage > 0 ) + if( sd && src != bl && damage > 0 && ( dmg.flag&BF_WEAPON || + (dmg.flag&BF_MISC && (skillid == RA_CLUSTERBOMB || skillid == RA_FIRINGTRAP || skillid == RA_ICEBOUNDTRAP || skillid == RK_DRAGONBREATH)) ) ) { if (battle_config.left_cardfix_to_right) battle_drain(sd, bl, dmg.damage, dmg.damage, tstatus->race, tstatus->mode&MD_BOSS); @@ -3692,7 +3693,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, (skillid == AS_SPLASHER)?1:skill_get_splash(skillid, skilllv), BL_CHAR, src, skillid, skilllv, tick, BCT_ENEMY, skill_area_sub_count); // recursive invocation of skill_castend_damage_id() with flag|1 - map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), (skillid == WL_CRIMSONROCK)?BL_CHAR|BL_SKILL:splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), ( skillid == WM_REVERBERATION_MELEE || skillid == WM_REVERBERATION_MAGIC )?BL_CHAR:splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); } break; @@ -4203,34 +4204,50 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag|ELE_DARK); break; case RA_WUGSTRIKE: + if( sd && pc_isridingwug(sd) ){ + short x[8]={0,-1,-1,-1,0,1,1,1}; + short y[8]={1,1,0,-1,-1,-1,0,1}; + int dir = map_calc_dir(bl, src->x, src->y); + + if( unit_movepos(src, bl->x+x[dir], bl->y+y[dir], 1, 1) ) + { + clif_slide(src, bl->x+x[dir], bl->y+y[dir]); + clif_fixpos(src); + skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag); + } + break; + } case RA_WUGBITE: if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); - } + }else if( sd && skillid == RA_WUGBITE ) // Only RA_WUGBITE has the skill fail message. + clif_skill_fail(sd, skillid, USESKILL_FAIL_LEVEL, 0); + break; case RA_SENSITIVEKEEN: if( bl->type != BL_SKILL ) { // Only Hits Invisible Targets struct status_change * tsc = status_get_sc(bl); - if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK) || tsc->data[SC__INVISIBILITY]) ) + if( tsc && tsc->option&(OPTION_HIDE|OPTION_CLOAK) ){ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + } } else { struct skill_unit *su = BL_CAST(BL_SKILL,bl); struct skill_unit_group* sg; - if( su && (sg=su->group) && skill_get_inf2(sg->skill_id)&INF2_TRAP && sg->src_id != src->id && - battle_check_target(src, map_id2bl(sg->src_id), BCT_ENEMY) > 0 ) + if( su && (sg=su->group) && skill_get_inf2(sg->skill_id)&INF2_TRAP ) { - if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) + if( !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = ( sg->unit_id >= UNT_MAGENTATRAP && sg->unit_id <= UNT_CLUSTERBOMB )?ITEMID_TRAP_ALLOY:ITEMID_TRAP; + item_tmp.nameid = sg->item_id?sg->item_id:ITEMID_TRAP; item_tmp.identify = 1; if( item_tmp.nameid ) - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); } skill_delunit(su); } @@ -4330,7 +4347,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int } else{ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); - } + } break; case WM_LULLABY_DEEPSLEEP: @@ -4479,6 +4496,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_castend_damage_id); flag|=1; //Set flag to 1 so ammo is not double-consumed. [Skotlex] } + status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); } break; @@ -5619,7 +5637,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_walkok(sd); // So aegis has to resend the walk ok. break; case AS_CLOAKING: - case RA_CAMOUFLAGE: case GC_CLOAKINGEXCEED: case LG_FORCEOFVANGUARD: case SC_REPRODUCE: @@ -5633,6 +5650,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in map_freeblock_unlock(); return 0; } + case RA_CAMOUFLAGE: i = sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)); if( i ) clif_skill_nodamage(src,bl,skillid,( skillid == LG_FORCEOFVANGUARD ) ? skilllv : -1,i); @@ -6642,7 +6660,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in { // get back 1 trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = ITEMID_TRAP; + 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)) ) { @@ -8204,7 +8222,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in if( flag&1 ) { sc_start2(bl,type,(skillid==WM_VOICEOFSIREN)?20+10*skilllv:100,skilllv,(skillid==WM_VOICEOFSIREN)?src->id:0,skill_get_time(skillid,skilllv)); } else { - map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv),(skillid==WM_VOICEOFSIREN)?BL_CHAR:BL_PC, src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); + map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv),(skillid==WM_VOICEOFSIREN)?BL_CHAR|BL_SKILL:BL_PC, src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); clif_skill_nodamage(src,bl,skillid,skilllv,1); } break; @@ -8747,6 +8765,11 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) break; } + if( ud->skillid == RA_WUGSTRIKE ){ + if( !path_search(NULL,src->m,src->x,src->y,target->x,target->y,1,CELL_CHKNOREACH)) + break; + } + if( ud->skillid == PR_LEXDIVINA || ud->skillid == MER_LEXDIVINA ) { sc = status_get_sc(target); @@ -8785,8 +8808,10 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) break; } else - if (inf && battle_check_target(src, target, inf) <= 0) + if (inf && battle_check_target(src, target, inf) <= 0){ + if (sd) clif_skill_fail(sd,ud->skillid,USESKILL_FAIL_LEVEL,0); break; + } if(inf&BCT_ENEMY && (sc = status_get_sc(target)) && sc->data[SC_FOGWALL] && @@ -8886,6 +8911,8 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) // SC_MAGICPOWER needs to switch states before any damage is actually dealt skill_toggle_magicpower(src, ud->skillid); + if( ud->skillid != 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->skillid) == CAST_NODAMAGE) skill_castend_nodamage_id(src,target,ud->skillid,ud->skilllv,tick,flag); @@ -9090,7 +9117,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) // } // } unit_set_walkdelay(src, tick, battle_config.default_walk_delay+skill_get_walkdelay(ud->skillid, ud->skilllv), 1); - + status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER);// only normal attack and auto cast skills benefit from its bonuses map_freeblock_lock(); skill_castend_pos2(src,ud->skillx,ud->skilly,ud->skillid,ud->skilllv,tick,0); @@ -9568,7 +9595,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case RK_WINDCUTTER: case WM_LULLABY_DEEPSLEEP: i = skill_get_splash(skillid,skilllv); - map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR, + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), src,skillid,skilllv,tick,flag|(skillid==WM_LULLABY_DEEPSLEEP?BCT_ALL:BCT_ENEMY)|1,skill_castend_damage_id); break; /** @@ -9602,7 +9629,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk sc->comet_y = y; } i = skill_get_splash(skillid,skilllv); - map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); break; case WL_EARTHSTRAIN: @@ -9675,10 +9702,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk int width;//according to data from irowiki it actually is a square for( width = 0; width < 7; width++ ) for( i = 0; i < 7; i++ ) - map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, BL_CHAR, src, LG_OVERBRAND_BRANDISH, skilllv, tick, flag|BCT_ENEMY,skill_castend_damage_id); + map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, LG_OVERBRAND_BRANDISH, skilllv, tick, flag|BCT_ENEMY,skill_castend_damage_id); for( width = 0; width < 7; width++ ) for( i = 0; i < 7; i++ ) - map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, BL_CHAR, src, skillid, skilllv, tick, flag|BCT_ENEMY,skill_castend_damage_id); + map_foreachincell(skill_area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY,skill_castend_damage_id); } break; @@ -9695,7 +9722,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case LG_RAYOFGENESIS: if( status_charge(src,status_get_max_hp(src)*3*skilllv / 100,0) ) { i = skill_get_splash(skillid,skilllv); - map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR, + map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); } else if( sd ) clif_skill_fail(sd,skillid,USESKILL_FAIL,0); @@ -9709,7 +9736,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case WM_GREAT_ECHO: flag|=1; // Should counsume 1 item per skill usage. - map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv),BL_CHAR, src, skillid, skilllv, tick, flag|BCT_ENEMY, skill_castend_damage_id); + map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv),splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY, skill_castend_damage_id); break; case GN_CRAZYWEED: @@ -10055,7 +10082,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli { struct skill_unit_group *group; int i,limit,val1=0,val2=0,val3=0; - int target,interval,range,unit_flag; + int target,interval,range,unit_flag,req_item=0; struct s_skill_unit_layout *layout; struct map_session_data *sd; struct status_data *status; @@ -10153,10 +10180,16 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case RA_VERDURETRAP: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - if( map_flag_gvg(src->m) || map[src->m].flag.battleground ) - limit *= 4; // longer trap times in WOE [celest] - if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) - target = BCT_ALL; + { + struct skill_condition req = skill_get_requirement(sd,skillid,skilllv); + ARR_FIND(0, MAX_SKILL_ITEM_REQUIRE, i, req.itemid[i] && (req.itemid[i] == ITEMID_TRAP || req.itemid[i] == ITEMID_TRAP_ALLOY)); + if( req.itemid[i] ) + req_item = req.itemid[i]; + if( map_flag_gvg(src->m) || map[src->m].flag.battleground ) + limit *= 4; // longer trap times in WOE [celest] + if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) + target = BCT_ALL; + } break; case SA_LANDPROTECTOR: @@ -10355,6 +10388,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli group->state.ammo_consume = (sd && sd->state.arrow_atk && skillid != GS_GROUNDDRIFT); //Store if this skill needs to consume ammo. group->state.song_dance = (unit_flag&(UF_DANCE|UF_SONG)?1:0)|(unit_flag&UF_ENSEMBLE?2:0); //Signals if this is a song/dance/duet group->state.guildaura = ( skillid >= GD_LEADERSHIP && skillid <= GD_HAWKEYES )?1:0; + group->item_id = req_item; //if tick is greater than current, do not invoke onplace function just yet. [Skotlex] if (DIFF_TICK(group->tick, gettick()) > SKILLUNITTIMER_INTERVAL) active_flag = 0; @@ -10417,6 +10451,8 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case HT_TALKIEBOX: case HT_SKIDTRAP: case MA_SKIDTRAP: + case HT_CLAYMORETRAP: + case HT_BLASTMINE: /** * Ranger **/ @@ -10948,6 +10984,18 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill_get_time2(sg->skill_id,sg->skill_lv),0); break; + + case UNT_MAGENTATRAP: + case UNT_COBALTTRAP: + case UNT_MAIZETRAP: + case UNT_VERDURETRAP: + if( bl->type == BL_PC )// it won't work on players + break; + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + case UNT_CLUSTERBOMB: + if( bl->id == ss->id )// it won't trigger on caster + break; case UNT_LANDMINE: case UNT_CLAYMORETRAP: case UNT_BLASTMINE: @@ -10956,20 +11004,11 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_FLASHER: case UNT_FREEZINGTRAP: case UNT_FIREPILLAR_ACTIVE: - /** - * Ranger - **/ - case UNT_CLUSTERBOMB: - case UNT_MAGENTATRAP: - case UNT_COBALTTRAP: - case UNT_MAIZETRAP: - case UNT_VERDURETRAP: - case UNT_FIRINGTRAP: - case UNT_ICEBOUNDTRAP: 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) clif_changetraplook(&src->bl, sg->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS); - sg->limit=DIFF_TICK(tick,sg->tick)+1500 + (sg->unit_id== UNT_CLUSTERBOMB?1000:0);// Cluster Bomb has 1s to disappear once activated. + sg->limit=DIFF_TICK(tick,sg->tick)+1500 + + (sg->unit_id== UNT_CLUSTERBOMB || sg->unit_id== UNT_ICEBOUNDTRAP?1000:0);// Cluster Bomb/Icebound has 1s to disappear once activated. sg->unit_id = UNT_USED_TRAPS; //Changed ID so it does not invoke a for each in area again. break; @@ -11547,6 +11586,7 @@ int skill_unit_ondamaged (struct skill_unit *src, struct block_list *bl, int dam nullpo_ret(sg=src->group); switch( sg->unit_id ) { + case UNT_BLASTMINE: case UNT_SKIDTRAP: case UNT_LANDMINE: case UNT_SHOCKWAVE: @@ -11561,9 +11601,6 @@ int skill_unit_ondamaged (struct skill_unit *src, struct block_list *bl, int dam case UNT_WALLOFTHORN: src->val1-=damage; break; - case UNT_BLASTMINE: - skill_blown(bl, &src->bl, 3, -1, 0); - break; default: damage = 0; break; @@ -11851,10 +11888,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh case HT_SKIDTRAP: case HT_LANDMINE: case HT_ANKLESNARE: case HT_SHOCKWAVE: case HT_SANDMAN: case HT_FLASHER: case HT_FREEZINGTRAP: case HT_BLASTMINE: case HT_CLAYMORETRAP: case HT_SPRINGTRAP: case RA_DETONATOR: case RA_CLUSTERBOMB: - case RA_WUGDASH: case RA_WUGRIDER: + case RA_WUGDASH: case RA_WUGRIDER: case RA_WUGSTRIKE: break; - default: - clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0); + default: // in official there is no message. return 0; } } @@ -12255,14 +12291,14 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh /** * Ranger **/ - case RA_SENSITIVEKEEN: - if(!pc_iswug(sd)) { - clif_skill_fail(sd,skill,USESKILL_FAIL_CONDITION,0); + case RA_WUGMASTERY: + if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { + clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0); return 0; } break; - case RA_WUGMASTERY: - if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) { + case RA_WUGSTRIKE: + if( !pc_iswug(sd) && !pc_isridingwug(sd) ) { clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0); return 0; } @@ -12872,7 +12908,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short case SO_SUMMON_TERA: if( i < 3 ) continue; - break; + break; } req.itemid[i] = skill_db[j].itemid[i]; @@ -12893,6 +12929,13 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short req.amount[i] = 1; // Hocus Pocus allways use at least 1 gem } } + if( skill >= HT_SKIDTRAP && skill <= HT_TALKIEBOX && pc_checkskill(sd, RA_RESEARCHTRAP) > 0){ + if( (j=pc_search_inventory(sd,req.itemid[i])) < 0 || ( j >= 0 && sd->status.inventory[j].amount < req.amount[i] ) ){ + req.itemid[i] = ITEMID_TRAP_ALLOY; + req.amount[i] = 1; + } + break; + } } /* requirements are level-dependent */ @@ -13863,7 +13906,8 @@ int skill_detonator(struct block_list *bl, va_list ap) clif_changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS); unit->group->unit_id = UNT_USED_TRAPS; - unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) + (unit_id == UNT_TALKIEBOX ? 5000 : (unit_id == UNT_CLUSTERBOMB ? 2500 : 1500) ); + unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) + + (unit_id == UNT_TALKIEBOX ? 5000 : (unit_id == UNT_CLUSTERBOMB || unit_id == UNT_ICEBOUNDTRAP? 2500 : 1500) ); break; } return 0; @@ -14040,16 +14084,20 @@ static int skill_trap_splash (struct block_list *bl, va_list ap) case UNT_FIRINGTRAP: case UNT_ICEBOUNDTRAP: case UNT_CLUSTERBOMB: - if(skill_attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) - clif_skill_damage(src,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5); + if( ss != bl ) + skill_attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1|SD_LEVEL); break; + case UNT_MAGENTATRAP: + case UNT_COBALTTRAP: + 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)); + 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 skill_addtimerskill(ss,tick+250,bl->id,0,0,WM_REVERBERATION_MAGIC,sg->skill_lv,BF_MAGIC,0); break; - case UNT_SEVERE_RAINSTORM: - skill_attack(BF_WEAPON,ss,ss,bl,WM_SEVERE_RAINSTORM_MELEE,sg->skill_lv,tick,0); - break; default: skill_attack(skill_get_type(sg->skill_id),ss,src,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -14609,6 +14657,9 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) switch( group->unit_id ) { case UNT_BLASTMINE: +#ifdef RENEWAL + case UNT_CLAYMORETRAP: +#endif case UNT_GROUNDDRIFT_WIND: case UNT_GROUNDDRIFT_DARK: case UNT_GROUNDDRIFT_POISON: @@ -14633,7 +14684,9 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) case UNT_SANDMAN: case UNT_FLASHER: case UNT_FREEZINGTRAP: +#ifndef RENEWAL case UNT_CLAYMORETRAP: +#endif case UNT_TALKIEBOX: case UNT_CLUSTERBOMB: case UNT_MAGENTATRAP: @@ -14649,7 +14702,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { // revert unit back into a trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = ( group->unit_id >= UNT_MAGENTATRAP && group->unit_id <= UNT_CLUSTERBOMB )?ITEMID_TRAP_ALLOY:ITEMID_TRAP; // Ensure we're returning the correct trap + item_tmp.nameid = group->item_id?group->item_id:ITEMID_TRAP; item_tmp.identify = 1; map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); } @@ -14736,6 +14789,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) if( unit->val1 <= 0 && unit->limit + group->tick > tick + 700 ) unit->limit = DIFF_TICK(tick+700,group->tick); break; + case UNT_BLASTMINE: case UNT_SKIDTRAP: case UNT_LANDMINE: case UNT_SHOCKWAVE: @@ -14745,14 +14799,13 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) case UNT_FREEZINGTRAP: case UNT_TALKIEBOX: case UNT_ANKLESNARE: - case UNT_ELECTRICSHOCKER: - case UNT_CLUSTERBOMB: if( unit->val1 <= 0 ) { if( group->unit_id == UNT_ANKLESNARE && group->val2 > 0 ) skill_delunit(unit); else { - group->unit_id = UNT_USED_TRAPS; + clif_changetraplook(bl, group->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS); group->limit = DIFF_TICK(tick, group->tick) + 1500; + group->unit_id = UNT_USED_TRAPS; } } break; diff --git a/src/map/skill.h b/src/map/skill.h index 8a7af1509..f9f5607e4 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -154,6 +154,7 @@ struct skill_unit_group { int unit_id; int group_id; int unit_count,alive_count; + int item_id; //store item used. struct skill_unit *unit; struct { unsigned ammo_consume : 1; diff --git a/src/map/status.c b/src/map/status.c index f6a5e5997..541123050 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -569,7 +569,7 @@ void initChangeTables(void) { set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE ); 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_CRI|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 ); @@ -982,6 +982,7 @@ void initChangeTables(void) { StatusChangeStateTable[SC_CURSEDCIRCLE_TARGET] |= SCS_NOMOVE; StatusChangeStateTable[SC_CRYSTALIZE] |= SCS_NOMOVE|SCS_NOMOVECOND; StatusChangeStateTable[SC_NETHERWORLD] |= SCS_NOMOVE; + StatusChangeStateTable[SC_CAMOUFLAGE] |= SCS_NOMOVE|SCS_NOMOVECOND; /* StatusChangeState (SCS_) NOPICKUPITEMS */ StatusChangeStateTable[SC_HIDING] |= SCS_NOPICKITEM; @@ -3415,6 +3416,8 @@ void status_calc_state( struct block_list *bl, struct status_change *sc, enum sc || (sc->data[SC_CLOAKING] && //Need wall at level 1-2 sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) || (sc->data[SC_CRYSTALIZE] && bl->type != BL_MOB) + || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3 + && !(sc->data[SC_CAMOUFLAGE]->val3&1)) ) { sc->cant.move += ( start ? 1 : -1 ); } @@ -4487,8 +4490,6 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch critical += sc->data[SC_STRIKING]->val1; if(sc->data[SC__INVISIBILITY]) critical += critical * sc->data[SC__INVISIBILITY]->val3 / 100; - if(sc->data[SC_CAMOUFLAGE]) - critical += 100; if(sc->data[SC__UNLUCKY]) critical -= critical * sc->data[SC__UNLUCKY]->val2 / 100; #ifdef RENEWAL @@ -4929,7 +4930,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sc->data[SC_MARSHOFABYSS] ) val = max( val, 40 + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) - val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 300 : 25 * (6 - sc->data[SC_CAMOUFLAGE]->val1) ); + val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); if( sc->data[SC__GROOMY] ) val = max( val, sc->data[SC__GROOMY]->val2); if( sc->data[SC_STEALTHFIELD_MASTER] ) @@ -6028,14 +6029,14 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti 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% break; case SC_ELECTRICSHOCKER: - case SC_BITE: { - if( bl->type == BL_MOB ) - tick -= 1000 * (status->agi/10); - if( sd && type != SC_ELECTRICSHOCKER ) - tick >>= 1; - } + if( bl->type == BL_MOB ) + tick -= 1000 * (status->agi/10); break; case SC_CRYSTALIZE: tick -= (1000*(status->vit/10))+(status_get_lv(bl)/50); @@ -7836,7 +7837,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_CAMOUFLAGE: - //val3 |= battle_config.pc_camouflage_check_type&7; + val4 = tick/1000; tick_time = 1000; // [GodLesZ] tick time break; case SC_WUGDASH: @@ -9874,10 +9875,12 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) break; case SC_CAMOUFLAGE: - if( !status_charge(bl,0,7 - sce->val1) ) - break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; + if(--(sce->val4) > 0){ + status_charge(bl,0,7 - sce->val1); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; case SC__REPRODUCE: if(!status_charge(bl, 0, 1)) diff --git a/src/map/unit.c b/src/map/unit.c index 53ad02d8a..63b2805fb 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1253,11 +1253,11 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh // moved here to prevent Suffragium from ending if skill fails if (!(skill_get_castnodex(skill_num, skill_lv)&2)) casttime = skill_castfix_sc(src, casttime, skill_num, skill_lv); - + // in official this is triggered even if no cast time. + clif_skillcasting(src, src->id, target_id, 0,0, skill_num, skill_get_ele(skill_num, skill_lv), casttime); if( casttime > 0 || temp ) { unit_stop_walking(src,1); - clif_skillcasting(src, src->id, target_id, 0,0, skill_num, skill_get_ele(skill_num, skill_lv), casttime); if (sd && target->type == BL_MOB) { @@ -1318,8 +1318,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh } else if( sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4) && skill_num != GC_CLOAKINGEXCEED ) { status_change_end(src,SC_CLOAKINGEXCEED, INVALID_TIMER); if (!src->prev) return 0; - } else if( sc->data[SC_CAMOUFLAGE] && skill_num != RA_CAMOUFLAGE ) - status_change_end(src,SC_CAMOUFLAGE,INVALID_TIMER); + } } @@ -1440,13 +1439,13 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh } else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4)) { status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); if (!src->prev) return 0; - } else if( sc->data[SC_CAMOUFLAGE] && skill_num != RA_CAMOUFLAGE ) - status_change_end(src,SC_CAMOUFLAGE,INVALID_TIMER); + } } + // in official this is triggered even if no cast time. + clif_skillcasting(src, src->id, 0, skill_x, skill_y, skill_num, skill_get_ele(skill_num, skill_lv), casttime); if( casttime > 0 ) { unit_stop_walking(src,1); - clif_skillcasting(src, src->id, 0, skill_x, skill_y, skill_num, skill_get_ele(skill_num, skill_lv), casttime); ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 ); if( (sd && pc_checkskill(sd,SA_FREECAST) > 0) || skill_num == LG_EXEEDBREAK) status_calc_bl(&sd->bl, SCB_SPEED); -- cgit v1.2.3-70-g09d2