diff options
author | zephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-09-10 14:30:25 +0000 |
---|---|---|
committer | zephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-09-10 14:30:25 +0000 |
commit | d3f9255b3d67e570a7784b44b151ed15198425ee (patch) | |
tree | b48e75936e8b77b61d3f65b8b972556ac511d0c4 | |
parent | e02e0c5cba6e83986da6fdce9c69a9201f9a271f (diff) | |
download | hercules-d3f9255b3d67e570a7784b44b151ed15198425ee.tar.gz hercules-d3f9255b3d67e570a7784b44b151ed15198425ee.tar.bz2 hercules-d3f9255b3d67e570a7784b44b151ed15198425ee.tar.xz hercules-d3f9255b3d67e570a7784b44b151ed15198425ee.zip |
- Full implementation of mercenary skills.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13203 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | src/map/battle.c | 82 | ||||
-rw-r--r-- | src/map/clif.c | 205 | ||||
-rw-r--r-- | src/map/clif.h | 2 | ||||
-rw-r--r-- | src/map/mob.c | 25 | ||||
-rw-r--r-- | src/map/pc.c | 2 | ||||
-rw-r--r-- | src/map/skill.c | 352 | ||||
-rw-r--r-- | src/map/skill.h | 5 | ||||
-rw-r--r-- | src/map/status.c | 205 | ||||
-rw-r--r-- | src/map/status.h | 1 | ||||
-rw-r--r-- | src/map/unit.c | 65 |
10 files changed, 622 insertions, 322 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index 8dc6eb394..d671be45e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -39,7 +39,8 @@ int battle_getcurrentskill(struct block_list *bl) { //Returns the current/last skill in use by this bl. struct unit_data *ud; - if (bl->type == BL_SKILL) { + if( bl->type == BL_SKILL ) + { struct skill_unit * su = (struct skill_unit*)bl; return su->group?su->group->skill_id:0; } @@ -322,9 +323,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i if( sc->data[SC_PNEUMA] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG ) return 0; - if((sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && - !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) && - rand()%100 < sce->val2) + if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) && rand()%100 < sce->val2 ) { int delay; clif_skill_nodamage(bl,bl,CR_AUTOGUARD,sce->val1,1); @@ -342,11 +341,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i return 0; } - if((sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON - && skill_num != WS_CARTTERMINATION - && rand()%100 < sce->val2) - {// attack blocked by Parrying - clif_skill_nodamage(bl,bl,LK_PARRYING,sce->val1,1); + if( (sce=sc->data[SC_PARRYING]) && flag&BF_WEAPON && skill_num != WS_CARTTERMINATION && rand()%100 < sce->val2 ) + { // attack blocked by Parrying + clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1); return 0; } @@ -948,6 +945,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo break; case KN_PIERCE: + case ML_PIERCE: wd.div_= (wd.div_>0?tstatus->size+1:-(tstatus->size+1)); break; @@ -959,6 +957,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case GS_GROUNDDRIFT: case KN_SPEARSTAB: case KN_BOWLINGBASH: + case MS_BOWLINGBASH: case MO_BALKYOUNG: case TK_TURNKICK: wd.blewcount=0; @@ -1011,7 +1010,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if(!flag.cri && sstatus->cri && (!skill_num || skill_num == KN_AUTOCOUNTER || - skill_num == SN_SHARPSHOOTING || + skill_num == SN_SHARPSHOOTING || skill_num == MA_SHARPSHOOTING || skill_num == NJ_KIRIKAGE)) { short cri = sstatus->cri; @@ -1042,6 +1041,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo cri <<= 1; break; case SN_SHARPSHOOTING: + case MA_SHARPSHOOTING: cri += 200; break; case NJ_KIRIKAGE: @@ -1123,6 +1123,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case MS_BASH: hitrate += hitrate * 5 * skill_lv / 100; break; + case MS_MAGNUM: case SM_MAGNUM: hitrate += hitrate * 10 * skill_lv / 100; break; @@ -1141,6 +1142,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo hitrate += hitrate * 20 / 100; break; case KN_PIERCE: + case ML_PIERCE: hitrate += hitrate * 5 * skill_lv / 100; break; case AS_SONICBLOW: @@ -1194,6 +1196,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo } break; case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: if (sd) { short index = sd->equip_index[EQI_HAND_R]; @@ -1295,18 +1298,15 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if(sc->data[SC_BERSERK]) skillratio += 100; } - if (!skill_num) - { - // Random chance to deal multiplied damage - Consider it as part of skill-based-damage - if(sd && - sd->random_attack_increase_add > 0 && - sd->random_attack_increase_per && - rand()%100 < sd->random_attack_increase_per - ) + if( !skill_num ) + { // Random chance to deal multiplied damage - Consider it as part of skill-based-damage + if( sd && sd->random_attack_increase_add > 0 && sd->random_attack_increase_per && rand()%100 < sd->random_attack_increase_per ) skillratio += sd->random_attack_increase_add; - + ATK_RATE(skillratio); - } else { //Skills + } + else + { switch( skill_num ) { case SM_BASH: @@ -1314,6 +1314,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo skillratio += 30*skill_lv; break; case SM_MAGNUM: + case MS_MAGNUM: skillratio += 20*skill_lv; break; case MC_MAMMONITE: @@ -1323,18 +1324,26 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo skillratio += 5*sstatus->str; break; case AC_DOUBLE: + case MA_DOUBLE: skillratio += 10*(skill_lv-1); break; case AC_SHOWER: + case MA_SHOWER: skillratio += 5*skill_lv-25; break; case AC_CHARGEARROW: + case MA_CHARGEARROW: skillratio += 50; break; case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: skillratio += -50+10*skill_lv; break; case KN_PIERCE: + case ML_PIERCE: + skillratio += 10*skill_lv; + break; + case MER_CRASH: skillratio += 10*skill_lv; break; case KN_SPEARSTAB: @@ -1344,6 +1353,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo skillratio += 50*skill_lv; break; case KN_BRANDISHSPEAR: + case ML_BRANDISH: { int ratio = 100+20*skill_lv; skillratio += ratio-100; @@ -1356,6 +1366,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo break; } case KN_BOWLINGBASH: + case MS_BOWLINGBASH: skillratio+= 40*skill_lv; break; case AS_GRIMTOOTH: @@ -1478,6 +1489,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo skillratio += 40*skill_lv-60; break; case SN_SHARPSHOOTING: + case MA_SHARPSHOOTING: skillratio += 100+50*skill_lv; break; case CG_ARROWVULCAN: @@ -1754,15 +1766,16 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo } //Post skill/vit reduction damage increases - if (sc && skill_num != LK_SPIRALPIERCE) + if( sc && skill_num != LK_SPIRALPIERCE && skill_num != ML_SPIRALPIERCE ) { //SC skill damages if(sc->data[SC_AURABLADE]) ATK_ADD(20*sc->data[SC_AURABLADE]->val1); } //Refine bonus - if (sd && flag.weapon && skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST) { - if (skill_num == MO_FINGEROFFENSIVE) //Counts refine bonus multiple times + if( sd && flag.weapon && skill_num != MO_INVESTIGATE && skill_num != MO_EXTREMITYFIST ) + { // Counts refine bonus multiple times + if( skill_num == MO_FINGEROFFENSIVE ) { ATK_ADD2(wd.div_*sstatus->rhw.atk2, wd.div_*sstatus->lhw.atk2); } else { @@ -2498,8 +2511,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * //Skill Range Criteria md.flag |= battle_range_type(src, target, skill_num, skill_lv); - switch(skill_num){ + switch( skill_num ) + { case HT_LANDMINE: + case MA_LANDMINE: md.damage=skill_lv*(sstatus->dex+75)*(100+sstatus->int_)/100; break; case HT_BLASTMINE: @@ -2917,9 +2932,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t battle_consume_ammo(sd, 0, 0); damage = wd.damage + wd.damage2; - if (damage > 0 && src != target) { + if( damage > 0 && src != target ) + { rdamage = battle_calc_return_damage(target, damage, wd.flag); - if (rdamage > 0) { + if( rdamage > 0 ) + { rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0); //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] skill_additional_effect(target,src,CR_REFLECTSHIELD,1,BF_WEAPON|BF_SHORT|BF_NORMAL,tick); @@ -3094,17 +3111,20 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case BL_SKILL: { TBL_SKILL *su = (TBL_SKILL*)target; - if (!su->group) + if( !su->group ) return 0; - if (skill_get_inf2(su->group->skill_id)&INF2_TRAP) - { //Only a few skills can target traps... - switch (battle_getcurrentskill(src)) + if( skill_get_inf2(su->group->skill_id)&INF2_TRAP ) + { //Only a few skills can target traps... + switch( battle_getcurrentskill(src) ) { + case MA_REMOVETRAP: case HT_REMOVETRAP: case AC_SHOWER: + case MA_SHOWER: case WZ_SIGHTRASHER: case WZ_SIGHTBLASTER: case SM_MAGNUM: + case MS_MAGNUM: state |= BCT_ENEMY; strip_enemy = 0; break; @@ -3312,7 +3332,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f /*========================================== * 射程判定 *------------------------------------------*/ -bool battle_check_range(struct block_list *src,struct block_list *bl,int range) +bool battle_check_range(struct block_list *src, struct block_list *bl, int range) { int d; nullpo_retr(false, src); diff --git a/src/map/clif.c b/src/map/clif.c index 489a765cf..20808ad3a 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -3313,8 +3313,8 @@ void clif_storageclose(struct map_session_data* sd) *------------------------------------------*/ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd) { - struct map_session_data* tmpsd; int gmlvl; + struct block_list *d_bl; int i; if(dstsd->chatID) @@ -3338,19 +3338,15 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d // display link (sd - dstsd) to sd ARR_FIND( 0, 5, i, sd->devotion[i] == dstsd->bl.id ); - if( i < 5 ) clif_devotion(sd, sd); + if( i < 5 ) clif_devotion(&sd->bl, sd); // display links (dstsd - devotees) to sd ARR_FIND( 0, 5, i, dstsd->devotion[i] > 0 ); - if( i < 5 ) clif_devotion(dstsd, sd); + if( i < 5 ) clif_devotion(&dstsd->bl, sd); // display link (dstsd - crusader) to sd - if( dstsd->sc.data[SC_DEVOTION] && (tmpsd = map_id2sd(dstsd->sc.data[SC_DEVOTION]->val1)) != NULL ) - clif_devotion(tmpsd, sd); - - // pvp circle for duel [LuzZza] - //if(dstsd->duel_group) - // clif_specialeffect(&dstsd->bl, 159, 4); - + if( dstsd->sc.data[SC_DEVOTION] && (d_bl = map_id2bl(dstsd->sc.data[SC_DEVOTION]->val1)) != NULL ) + clif_devotion(d_bl, sd); } + void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { uint8 buf[128]; @@ -3381,6 +3377,10 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) clif_specialeffect_single(bl,421,sd->fd); } break; + case BL_MER: // Devotion Effects + if( ((TBL_MER*)bl)->devotion_flag ) + clif_devotion(bl, sd); + break; case BL_NPC: { TBL_NPC* nd = (TBL_NPC*)bl; @@ -4339,7 +4339,7 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) nullpo_retr(0, sd); nullpo_retr(0, dst); - if(dst->type!=BL_MOB ) + if( dst->type != BL_MOB ) return 0; status = status_get_status_data(dst); @@ -5870,23 +5870,39 @@ int clif_autospell(struct map_session_data *sd,int skilllv) * Devotion's visual effect * S 01cf <devoter id>.L { <devotee id>.L }[5] <max distance>.W *------------------------------------------*/ -void clif_devotion(struct map_session_data *sd, struct map_session_data *tsd) +void clif_devotion(struct block_list *src, struct map_session_data *tsd) { unsigned char buf[56]; int i; - - nullpo_retv(sd); + + nullpo_retv(src); + memset(buf,0,packet_len(0x1cf)); WBUFW(buf,0) = 0x1cf; - WBUFL(buf,2) = sd->bl.id; - for( i = 0; i < 5; i++ ) - WBUFL(buf,6+4*i) = sd->devotion[i]; - WBUFW(buf,26) = skill_get_range2(&sd->bl,CR_DEVOTION,pc_checkskill(sd,CR_DEVOTION)); // ignored + WBUFL(buf,2) = src->id; + if( src->type == BL_MER ) + { + struct mercenary_data *md = BL_CAST(BL_MER,src); + if( md && md->master && md->devotion_flag ) + WBUFL(buf,6) = md->master->bl.id; + + WBUFW(buf,26) = skill_get_range2(src, ML_DEVOTION, mercenary_checkskill(md, ML_DEVOTION)); + } + else + { + struct map_session_data *sd = BL_CAST(BL_PC,src); + if( sd == NULL ) + return; + + for( i = 0; i < 5; i++ ) + WBUFL(buf,6+4*i) = sd->devotion[i]; + WBUFW(buf,26) = skill_get_range2(src, CR_DEVOTION, pc_checkskill(sd, CR_DEVOTION)); + } if( tsd ) - clif_send(buf,packet_len(0x1cf),&tsd->bl,SELF); + clif_send(buf, packet_len(0x1cf), &tsd->bl, SELF); else - clif_send(buf,packet_len(0x1cf),&sd->bl,AREA); + clif_send(buf, packet_len(0x1cf), src, AREA); } /*========================================== @@ -9216,6 +9232,30 @@ static void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct unit_skilluse_id(&md->bl, target_id, skillnum, skilllv); } +static void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, short skillnum, short skilllv, short x, short y, int skillmoreinfo) +{ + int lv; + if( !md ) + return; + if( skillnotok_mercenary(skillnum, md) ) + return; + if( md->ud.skilltimer != INVALID_TIMER ) + return; + if( DIFF_TICK(tick, md->ud.canact_tick) < 0 ) + { + clif_skill_fail(md->master, skillnum, 4, 0); + return; + } + + if( md->sc.data[SC_BASILICA] ) + return; + lv = mercenary_checkskill(md, skillnum); + if( skilllv > lv ) + skilllv = lv; + if( skilllv ) + unit_skilluse_pos(&md->bl, x, y, skillnum, skilllv); +} + /*========================================== * スキル使用(ID指定) *------------------------------------------*/ @@ -9229,20 +9269,19 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) skillnum = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]); target_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[2]); - if (skilllv < 1) skilllv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex] - + if( skilllv < 1 ) skilllv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex] tmp = skill_get_inf(skillnum); if (tmp&INF_GROUND_SKILL || !tmp) return; //Using a ground/passive skill on a target? WRONG. - if( skillnum >= HM_SKILLBASE && skillnum < HM_SKILLBASE+MAX_HOMUNSKILL ) + if( skillnum >= HM_SKILLBASE && skillnum < HM_SKILLBASE + MAX_HOMUNSKILL ) { clif_parse_UseSkillToId_homun(sd->hd, sd, tick, skillnum, skilllv, target_id); return; } - if( skillnum >= MC_SKILLBASE && skillnum < MC_SKILLBASE+MAX_MERCSKILL ) + if( skillnum >= MC_SKILLBASE && skillnum < MC_SKILLBASE + MAX_MERCSKILL ) { clif_parse_UseSkillToId_mercenary(sd->md, sd, tick, skillnum, skilllv, target_id); return; @@ -9251,21 +9290,24 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] sd->idletime = last_tick; - if (pc_cant_act(sd)) + if( pc_cant_act(sd) ) return; - if (pc_issit(sd)) + if( pc_issit(sd) ) return; - if (skillnotok(skillnum, sd)) + if( skillnotok(skillnum, sd) ) return; - if (sd->bl.id != target_id && !sd->state.skill_flag && tmp&INF_SELF_SKILL) + if( sd->bl.id != target_id && !sd->state.skill_flag && tmp&INF_SELF_SKILL ) target_id = sd->bl.id; //What good is it to mess up the target in self skills? Wished I knew... [Skotlex] - if (sd->ud.skilltimer != -1) { - if (skillnum != SA_CASTCANCEL) + if( sd->ud.skilltimer != -1 ) + { + if( skillnum != SA_CASTCANCEL ) return; - } else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) { + } + else if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) + { clif_skill_fail(sd, skillnum, 4, 0); return; } @@ -9276,70 +9318,81 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if(target_id<0 && -target_id == sd->bl.id) // for disguises [Valaris] + if( target_id < 0 && -target_id == sd->bl.id ) // for disguises [Valaris] target_id = sd->bl.id; - if(sd->menuskill_id) + if( sd->menuskill_id ) { - if (sd->menuskill_id == SA_TAMINGMONSTER) + if( sd->menuskill_id == SA_TAMINGMONSTER ) sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else - if (sd->menuskill_id != SA_AUTOSPELL) + else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } - if (sd->skillitem == skillnum) { - if (skilllv != sd->skillitemlv) + if( sd->skillitem == skillnum ) + { + if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv); return; } sd->skillitem = sd->skillitemlv = 0; - if (skillnum == MO_EXTREMITYFIST) { - if ((!sd->sc.data[SC_COMBO] || + if( skillnum == MO_EXTREMITYFIST ) + { + if( (!sd->sc.data[SC_COMBO] || (sd->sc.data[SC_COMBO]->val1 != MO_COMBOFINISH && sd->sc.data[SC_COMBO]->val1 != CH_TIGERFIST && sd->sc.data[SC_COMBO]->val1 != CH_CHAINCRUSH))) { - if (!sd->state.skill_flag ) { + if( !sd->state.skill_flag ) + { sd->state.skill_flag = 1; clif_skillinfo(sd, MO_EXTREMITYFIST, INF_ATTACK_SKILL, -1); return; - } else if (sd->bl.id == target_id) { + } else if( sd->bl.id == target_id ) + { clif_skillinfo(sd, MO_EXTREMITYFIST, INF_ATTACK_SKILL, -1); return; } } } - if (skillnum == TK_JUMPKICK) { - if (!sd->sc.data[SC_COMBO] || sd->sc.data[SC_COMBO]->val1 != TK_JUMPKICK) { - if (!sd->state.skill_flag ) { + if( skillnum == TK_JUMPKICK ) + { + if( !sd->sc.data[SC_COMBO] || sd->sc.data[SC_COMBO]->val1 != TK_JUMPKICK ) + { + if( !sd->state.skill_flag ) + { sd->state.skill_flag = 1; clif_skillinfo(sd, TK_JUMPKICK, INF_ATTACK_SKILL, -1); return; - } else if (sd->bl.id == target_id) { + } + else if( sd->bl.id == target_id ) + { clif_skillinfo(sd, TK_JUMPKICK, INF_ATTACK_SKILL, -1); return; } } } - if (skillnum >= GD_SKILLBASE) { - if (sd->state.gmaster_flag) + if( skillnum >= GD_SKILLBASE ) + { + if( sd->state.gmaster_flag ) skilllv = guild_checkskill(sd->state.gmaster_flag, skillnum); else skilllv = 0; - } else { + } + else + { tmp = pc_checkskill(sd, skillnum); - if (skilllv > tmp) + if( skilllv > tmp ) skilllv = tmp; } pc_delinvincibletimer(sd); - if (skilllv) + if( skilllv ) unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv); - if (sd->state.skill_flag) + if( sd->state.skill_flag ) sd->state.skill_flag = 0; } @@ -9351,17 +9404,24 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skil int lv; unsigned int tick = gettick(); - //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( !(skill_get_inf(skillnum)&INF_GROUND_SKILL) ) + return; //Using a target skill on the ground? WRONG. - if (skillnotok(skillnum, sd)) + if( skillnum >= MC_SKILLBASE && skillnum < MC_SKILLBASE + MAX_MERCSKILL ) + { + clif_parse_UseSkillToPos_mercenary(sd->md, sd, tick, skillnum, skilllv, x, y, skillmoreinfo); return; + } - if (!(skill_get_inf(skillnum)&INF_GROUND_SKILL)) - return; //Using a target skill on the ground? WRONG. + //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] + sd->idletime = last_tick; - if (skillmoreinfo != -1) { - if (pc_issit(sd)) { + if( skillnotok(skillnum, sd) ) + return; + if( skillmoreinfo != -1 ) + { + if( pc_issit(sd) ) + { clif_skill_fail(sd, skillnum, 0, 0); return; } @@ -9369,10 +9429,10 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skil safestrncpy(sd->message, (char*)RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE); } - if (sd->ud.skilltimer != -1) + if( sd->ud.skilltimer != -1 ) return; - if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) + if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { clif_skill_fail(sd, skillnum, 4, 0); return; @@ -9384,32 +9444,34 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skil if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if(sd->menuskill_id) + if( sd->menuskill_id ) { - if (sd->menuskill_id == SA_TAMINGMONSTER) + if( sd->menuskill_id == SA_TAMINGMONSTER ) sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else - if (sd->menuskill_id != SA_AUTOSPELL) + else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } pc_delinvincibletimer(sd); - if (sd->skillitem == skillnum) { - if (skilllv != sd->skillitemlv) + if( sd->skillitem == skillnum ) + { + if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; unit_skilluse_pos(&sd->bl, x, y, skillnum, skilllv); - } else { + } + else + { sd->skillitem = sd->skillitemlv = 0; - if ((lv = pc_checkskill(sd, skillnum)) > 0) { - if (skilllv > lv) + if( (lv = pc_checkskill(sd, skillnum)) > 0 ) + { + if( skilllv > lv ) skilllv = lv; unit_skilluse_pos(&sd->bl, x, y, skillnum,skilllv); } } } - void clif_parse_UseSkillToPos(int fd, struct map_session_data *sd) { if (pc_cant_act(sd)) @@ -12484,7 +12546,6 @@ void clif_mercenary_info(struct map_session_data *sd) // Mercenary shows ATK as a random value between ATK ~ ATK2 atk = rand()%(status->rhw.atk2 - status->rhw.atk + 1) + status->rhw.atk; WFIFOW(fd,6) = cap_value(atk, 0, SHRT_MAX); - WFIFOW(fd,8) = cap_value(status->matk_max, 0, SHRT_MAX); WFIFOW(fd,10) = status->hit; WFIFOW(fd,12) = status->cri/10; diff --git a/src/map/clif.h b/src/map/clif.h index dc9f4ef52..6ff91a957 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -233,7 +233,7 @@ void clif_skill_delunit(struct skill_unit *unit); void clif_01ac(struct block_list* bl); int clif_autospell(struct map_session_data *sd,int skilllv); -void clif_devotion(struct map_session_data *sd, struct map_session_data *tsd); +void clif_devotion(struct block_list *src, struct map_session_data *tsd); int clif_spiritball(struct map_session_data *sd); int clif_combo_delay(struct block_list *src,int wait); int clif_bladestop(struct block_list *src,struct block_list *dst,int bool_); diff --git a/src/map/mob.c b/src/map/mob.c index 309b47000..1305a9eb7 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1286,8 +1286,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) || !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) ) && md->state.attacked_count++ >= RUDE_ATTACKED_COUNT - && !mobskill_use(md, tick, MSC_RUDEATTACKED) //If can't rude Attack - && can_move && unit_escape(&md->bl, tbl, rand()%10 +1)) //Attempt escape + && !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack + && can_move && unit_escape(&md->bl, tbl, rand()%10 +1)) // Attempt escape { //Escaped md->attacked_id = 0; return true; @@ -1297,18 +1297,17 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) if( (abl = map_id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode)) ) { if( md->bl.m != abl->m || abl->prev == NULL - || (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE - || battle_check_target(&md->bl, abl, BCT_ENEMY) <= 0 - || (battle_config.mob_ai&0x2 && !status_check_skilluse(&md->bl, abl, 0, 0)) //Retaliate check - || (!battle_check_range(&md->bl, abl, md->status.rhw.range) - && - ( //Reach check - (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB])) - || !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH) - ) + || (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE // Attacker longer than visual area + || battle_check_target(&md->bl, abl, BCT_ENEMY) <= 0 // Attacker is not enemy of mob + || status_isdead(abl) // Attacker is Dead (Reflecting Damage?) + || (battle_config.mob_ai&0x2 && !status_check_skilluse(&md->bl, abl, 0, 0)) // Cannot normal attack back to Attacker + || (!battle_check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... + && ( // Reach check + (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || md->sc.data[SC_SPIDERWEB])) + || !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH) ) - ) - { //Rude attacked + ) ) + { // Rude attacked if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move && !tbl && unit_escape(&md->bl, abl, rand()%10 +1)) diff --git a/src/map/pc.c b/src/map/pc.c index eb8e87159..debc3361f 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3155,6 +3155,8 @@ int pc_isUseitem(struct map_session_data *sd,int n) case 12243: // Mercenary's Berserk Potion if( sd->md == NULL || sd->md->db == NULL ) return 0; + if( sd->md->sc.data[SC_BERSERK] ) + return 0; if( nameid == 12242 && sd->md->db->lv < 40 ) return 0; if( nameid == 12243 && sd->md->db->lv < 80 ) diff --git a/src/map/skill.c b/src/map/skill.c index 1a8cdf0a1..5dbd6d8be 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -215,26 +215,31 @@ int skill_get_casttype (int id) int skill_get_range2 (struct block_list *bl, int id, int lv) { int range; - if(bl->type == BL_MOB && !(battle_config.mob_ai&0x400)) + if( bl->type == BL_MOB && !(battle_config.mob_ai&0x400) ) return 9; //Mobs have a range of 9 regardless of skill used. range = skill_get_range(id, lv); - if(range < 0) { - if (battle_config.use_weapon_skill_range&bl->type) + if( range < 0 ) + { + if( battle_config.use_weapon_skill_range&bl->type ) return status_get_range(bl); range *=-1; } + //TODO: Find a way better than hardcoding the list of skills affected by AC_VULTURE - switch (id) { - case AC_SHOWER: - case AC_DOUBLE: + switch( id ) + { + case AC_SHOWER: case MA_SHOWER: + case AC_DOUBLE: case MA_DOUBLE: case HT_BLITZBEAT: case AC_CHARGEARROW: + case MA_CHARGEARROW: case SN_FALCONASSAULT: case SN_SHARPSHOOTING: + case MA_SHARPSHOOTING: case HT_POWER: - if (bl->type == BL_PC) + if( bl->type == BL_PC ) range += pc_checkskill((TBL_PC*)bl, AC_VULTURE); else range += 10; //Assume level 10? @@ -256,7 +261,7 @@ int skill_get_range2 (struct block_list *bl, int id, int lv) break; } - if(!range && bl->type != BL_PC) + if( !range && bl->type != BL_PC ) return 9; // Enable non players to use self skills on others. [Skotlex] return range; } @@ -553,6 +558,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int } break; + case MER_CRASH: + sc_start(bl,SC_STUN,(6*skilllv),skilllv,skill_get_time2(skillid,skilllv)); + break; + case AS_VENOMKNIFE: if (sd) //Poison chance must be that of Envenom. [Skotlex] skilllv = pc_checkskill(sd, TF_POISON); @@ -593,6 +602,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int break; case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: sc_start(bl,SC_FREEZE,(3*skilllv+35),skilllv,skill_get_time2(skillid,skilllv)); break; @@ -601,6 +611,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int break; case HT_LANDMINE: + case MA_LANDMINE: sc_start(bl,SC_STUN,(5*skilllv+30),skilllv,skill_get_time2(skillid,skilllv)); break; @@ -609,6 +620,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int break; case HT_SANDMAN: + case MA_SANDMAN: sc_start(bl,SC_SLEEP,(10*skilllv+40),skilllv,skill_get_time2(skillid,skilllv)); break; @@ -728,6 +740,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int break; case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: sc_start(bl,SC_STOP,(15+skilllv*5),0,skill_get_time2(skillid,skilllv)); break; @@ -852,12 +865,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int break; } - if(sd && attack_type&BF_WEAPON && + if( sd && attack_type&BF_WEAPON && skillid != WS_CARTTERMINATION && skillid != AM_DEMONSTRATION && - skillid != CR_REFLECTSHIELD && - skillid != ASC_BREAKER - ){ //Trigger status effects + skillid != CR_REFLECTSHIELD && skillid != MS_REFLECTSHIELD && + skillid != ASC_BREAKER ) + { // Trigger status effects enum sc_type type; int i; for(i=0; i < ARRAYLENGTH(sd->addeff) && sd->addeff[i].flag; i++) @@ -1679,11 +1692,12 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds clif_skillinfoblock(tsd); } } - if (skillid != WZ_SIGHTRASHER && + if( skillid != WZ_SIGHTRASHER && skillid != WZ_SIGHTBLASTER && - skillid != AC_SHOWER && - skillid != SM_MAGNUM && - bl->type == BL_SKILL && damage > 0) { + 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] @@ -1835,12 +1849,16 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap) break; case AL_WARP: case HT_SKIDTRAP: + case MA_SKIDTRAP: case HT_LANDMINE: + case MA_LANDMINE: case HT_ANKLESNARE: case HT_SHOCKWAVE: case HT_SANDMAN: + case MA_SANDMAN: case HT_FLASHER: case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: case HT_BLASTMINE: case HT_CLAYMORETRAP: case HT_TALKIEBOX: @@ -2289,17 +2307,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int switch(skillid) { + case MER_CRASH: case SM_BASH: case MS_BASH: case MC_MAMMONITE: case TF_DOUBLE: case AC_DOUBLE: + case MA_DOUBLE: case AS_SONICBLOW: case KN_PIERCE: + case ML_PIERCE: case KN_SPEARBOOMERANG: case TF_POISON: case TF_SPRINKLESAND: case AC_CHARGEARROW: + case MA_CHARGEARROW: case RG_INTIMIDATE: case AM_ACIDTERROR: case BA_MUSICALSTRIKE: @@ -2338,6 +2360,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_SLEEPATTACK: case LK_AURABLADE: case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: case LK_HEADCRUSH: case CG_ARROWVULCAN: case HW_MAGICCRASHER: @@ -2438,6 +2461,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int break; case SN_SHARPSHOOTING: + case MA_SHARPSHOOTING: case NJ_KAMAITACHI: //It won't shoot through walls since on castend there has to be a direct //line of sight between caster and target. @@ -2552,8 +2576,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int flag |= SD_PREAMBLE; // a fake packet will be sent for the first target to be hit case AS_SPLASHER: case SM_MAGNUM: + case MS_MAGNUM: case HT_BLITZBEAT: case AC_SHOWER: + case MA_SHOWER: case MG_NAPALMBEAT: case MG_FIREBALL: case RG_RAID: @@ -2598,15 +2624,19 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int 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); //FIXME: move this to skill_additional_effect or some such? [ultramage] - if (skillid == SM_MAGNUM) { - //Initiate 10% of your damage becomes fire element. + if( skillid == SM_MAGNUM || skillid == MS_MAGNUM ) + { // Initiate 10% of your damage becomes fire element. sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill_get_time2(skillid, skilllv)); - if (sd) skill_blockpc_start (sd, skillid, skill_get_time(skillid, skilllv)); + if( sd ) + skill_blockpc_start(sd, skillid, skill_get_time(skillid, skilllv)); + if( bl->type == BL_MER ) + skill_blockmerc_start((TBL_MER*)bl, skillid, skill_get_time(skillid, skilllv)); } } break; case KN_BRANDISHSPEAR: + case ML_BRANDISH: //Coded apart for it needs the flag passed to the damage calculation. if (skill_area_temp[1] != bl->id) skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag|SD_ANIMATION); @@ -2615,6 +2645,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int break; case KN_BOWLINGBASH: + case MS_BOWLINGBASH: if(flag&1){ if(bl->id==skill_area_temp[1]) break; @@ -2883,14 +2914,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int *------------------------------------------*/ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, int skillid, int skilllv, unsigned int tick, int flag) { - struct map_session_data *sd; + struct map_session_data *sd, *dstsd; + struct mob_data *md, *dstmd; struct homun_data *hd; - struct map_session_data *dstsd; + struct mercenary_data *mer; struct status_data *sstatus, *tstatus; struct status_change *tsc; struct status_change_entry *tsce; - struct mob_data *md; - struct mob_data *dstmd; + int i; enum sc_type type; @@ -2905,6 +2936,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in sd = BL_CAST(BL_PC, src); hd = BL_CAST(BL_HOM, src); md = BL_CAST(BL_MOB, src); + mer = BL_CAST(BL_MER, src); dstsd = BL_CAST(BL_PC, bl); dstmd = BL_CAST(BL_MOB, bl); @@ -3080,10 +3112,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case AL_DECAGI: - clif_skill_nodamage (src, bl, skillid, skilllv, - sc_start(bl, type, - (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), - skilllv, skill_get_time(skillid,skilllv))); + case MER_DECAGI: + clif_skill_nodamage (src, bl, skillid, skilllv, + sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), skilllv, skill_get_time(skillid,skilllv))); break; case AL_CRUCIS: @@ -3097,12 +3128,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case PR_LEXDIVINA: - if (tsce) { + case MER_LEXDIVINA: + if( tsce ) + { status_change_end(bl,type, -1); clif_skill_nodamage (src, bl, skillid, skilllv, 1); - } else - clif_skill_nodamage (src, bl, skillid, skilllv, - sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + } + else + clif_skill_nodamage (src, bl, skillid, skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; case SA_ABRACADABRA: @@ -3338,6 +3371,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; //Passive Magnum, should had been casted on yourself. case SM_MAGNUM: + case MS_MAGNUM: skill_area_temp[1] = 0; map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_SKILL|BL_CHAR, src,skillid,skilllv,tick, flag|BCT_ENEMY|1, skill_castend_damage_id); @@ -3359,11 +3393,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case PR_SUFFRAGIUM: case PR_BENEDICTIO: case LK_BERSERK: + case MS_BERSERK: case KN_AUTOCOUNTER: case KN_TWOHANDQUICKEN: case KN_ONEHAND: + case MER_QUICKEN: case CR_SPEARQUICKEN: case CR_REFLECTSHIELD: + case MS_REFLECTSHIELD: case AS_POISONREACT: case MC_LOUD: case MG_ENERGYCOAT: @@ -3371,7 +3408,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case MO_STEELBODY: case MO_BLADESTOP: case LK_AURABLADE: - case LK_PARRYING: + case LK_PARRYING: + case MS_PARRYING: case LK_CONCENTRATION: case WS_CARTBOOST: case SN_SIGHT: @@ -3401,6 +3439,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; case MG_SIGHT: + case MER_SIGHT: case AL_RUWACH: case WZ_SIGHTBLASTER: case NPC_WIDESIGHT: @@ -3503,74 +3542,90 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case SM_PROVOKE: - if((tstatus->mode&MD_BOSS) || battle_check_undead(tstatus->race,tstatus->def_ele)) { + case MER_PROVOKE: + if( (tstatus->mode&MD_BOSS) || battle_check_undead(tstatus->race,tstatus->def_ele) ) + { map_freeblock_unlock(); return 1; } //TODO: How much does base level affects? Dummy value of 1% per level difference used. [Skotlex] clif_skill_nodamage(src,bl,skillid,skilllv, - (i=sc_start(bl,type, - 50 +3*skilllv +status_get_lv(src) -status_get_lv(bl), - skilllv,skill_get_time(skillid,skilllv)))); - if (!i) + (i = sc_start(bl,type, 50 + 3*skilllv + status_get_lv(src) - status_get_lv(bl), skilllv, skill_get_time(skillid,skilllv)))); + if( !i ) { - if (sd) + if( sd ) clif_skill_fail(sd,skillid,0,0); map_freeblock_unlock(); return 0; } unit_skillcastcancel(bl, 2); - if(tsc && tsc->count){ - if(tsc->data[SC_FREEZE]) + if( tsc && tsc->count ) + { + if( tsc->data[SC_FREEZE] ) status_change_end(bl,SC_FREEZE,-1); - if(tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE) + if( tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE ) status_change_end(bl,SC_STONE,-1); - if(tsc->data[SC_SLEEP]) + if( tsc->data[SC_SLEEP] ) status_change_end(bl,SC_SLEEP,-1); } - if(dstmd) { + if( dstmd ) + { dstmd->state.provoke_flag = src->id; - mob_target(dstmd,src,skill_get_range2(src,skillid,skilllv)); + mob_target(dstmd, src, skill_get_range2(src,skillid,skilllv)); } break; + case ML_DEVOTION: case CR_DEVOTION: - if(sd && dstsd) { - int count = min(skilllv, 5); - int lv = sd->status.base_level - dstsd->status.base_level; - if (lv < 0) lv = -lv; - if (lv > battle_config.devotion_level_difference || - (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || //Avoid overriding [Skotlex] - (dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER) { - clif_skill_fail(sd,skillid,0,0); + int count, lv; + if( !dstsd ) + { // Only players can be devoted + if( sd ) + clif_skill_fail(sd, skillid, 0, 0); + break; + } + + if( (lv = status_get_lv(src) - dstsd->status.base_level) < 0 ) + lv = -lv; + if( lv > battle_config.devotion_level_difference || // Level difference requeriments + (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || // Cannot Devote a player devoted from another source + (skillid == ML_DEVOTION && (!mer || mer != dstsd->md)) || // Mercenary only can devote owner + (dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER ) // Crusader Cannot be devoted + { + if( sd ) + clif_skill_fail(sd,skillid,0,0); map_freeblock_unlock(); return 1; } - // check if the char isn't devoted already - ARR_FIND( 0, count, i, sd->devotion[i] == bl->id ); - if( i == count ) - {// not there, find first empty slot - ARR_FIND( 0, count, i, sd->devotion[i] == 0 ); + i = 0; + count = (sd)? min(skilllv,5) : 1; // Mercenary only can Devote owner + if( sd ) + { // Player Devoting Player + ARR_FIND(0, count, i, sd->devotion[i] == bl->id ); if( i == count ) - {// all slots full, fail - clif_skill_fail(sd,skillid,0,0); - map_freeblock_unlock(); - return 1; + { + ARR_FIND(0, count, i, sd->devotion[i] == 0 ); + if( i == count ) + { // No free slots, skill Fail + clif_skill_fail(sd, skillid, 0, 0); + map_freeblock_unlock(); + return 1; + } } + + sd->devotion[i] = bl->id; } + else + mer->devotion_flag = 1; // Mercenary Devoting Owner - sd->devotion[i] = bl->id; - clif_skill_nodamage(src,bl,skillid,skilllv, - sc_start4(bl,type,100,src->id,i,skill_get_range2(src,skillid,skilllv),skill_get_time2(skillid, skilllv),1000)); - clif_devotion(sd,NULL); + clif_skill_nodamage(src, bl, skillid, skilllv, + sc_start4(bl, type, 100, src->id, i, skill_get_range2(src,skillid,skilllv), skill_get_time2(skillid, skilllv), 1000)); + clif_devotion(src, NULL); } - else - if (sd) - clif_skill_fail(sd,skillid,0,0); break; case MO_CALLSPIRITS: @@ -3662,6 +3717,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in break; case KN_BRANDISHSPEAR: + case ML_BRANDISH: { int c,n=4; int dir = map_calc_dir(src,bl->x,bl->y); @@ -3749,14 +3805,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case PR_MAGNIFICAT: case PR_GLORIA: case SN_WINDWALK: - if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) { - clif_skill_nodamage(bl,bl,skillid,skilllv, - sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); - } else if (sd) { - party_foreachsamemap (skill_area_sub, - sd,skill_get_splash(skillid, skilllv), - src,skillid,skilllv,tick, flag|BCT_PARTY|1, - skill_castend_nodamage_id); + if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + else if( sd ) + party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + break; + case MER_MAGNIFICAT: + if( mer != NULL ) + { + clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); + if( mer->master && mer->master->status.party_id != 0 && !(flag&1) ) + party_foreachsamemap(skill_area_sub, mer->master, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id); + else if( mer->master && !(flag&1) ) + clif_skill_nodamage(src, &mer->master->bl, skillid, skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); } break; @@ -3778,7 +3839,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case BS_MAXIMIZE: case NV_TRICKDEAD: case CR_DEFENDER: + case ML_DEFENDER: case CR_AUTOGUARD: + case ML_AUTOGUARD: case TK_READYSTORM: case TK_READYDOWN: case TK_READYTURN: @@ -3814,9 +3877,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src,bl,skillid,skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid, skilllv))); break; - case SM_AUTOBERSERK: // Celest - if (tsce) - i = status_change_end(bl, type, -1); + case SM_AUTOBERSERK: + case MER_AUTOBERSERK: + if( tsce ) + i = status_change_end(bl, type, -1); else i = sc_start(bl,type,100,skilllv,60000); clif_skill_nodamage(src,bl,skillid,skilllv,i); @@ -3996,18 +4060,63 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in mob_unlocktarget(dstmd,tick); break; + // Mercenary Supportive Skills + case MER_BENEDICTION: + status_change_end(bl, SC_CURSE, -1); + status_change_end(bl, SC_BLIND, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + case MER_COMPRESS: + status_change_end(bl, SC_BLEEDING, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + case MER_MENTALCURE: + status_change_end(bl, SC_CONFUSION, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + case MER_RECUPERATE: + status_change_end(bl, SC_POISON, -1); + status_change_end(bl, SC_SILENCE, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + case MER_REGAIN: + status_change_end(bl, SC_SLEEP, -1); + status_change_end(bl, SC_STUN, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + case MER_TENDER: + status_change_end(bl, SC_FREEZE, -1); + status_change_end(bl, SC_STONE, -1); + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; + + case MER_SCAPEGOAT: + if( mer && mer->master ) + { + status_heal(&mer->master->bl, mer->battle_status.hp, 0, 2); + status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1); + } + break; + + case MER_ESTIMATION: + if( !mer ) + break; + sd = mer->master; case WZ_ESTIMATION: - if(sd) { - if (dstsd) { - clif_skill_fail(sd,skillid,0,0); - break; - } - if (dstmd && dstmd->class_ == MOBID_EMPERIUM) { - break; - } - clif_skill_nodamage(src,bl,skillid,skilllv,1); - clif_skill_estimation((struct map_session_data *)src,bl); + if( sd == NULL ) + break; + if( dstsd ) + { // Fail on Players + clif_skill_fail(sd,skillid,0,0); + break; } + if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) + break; // Cannot be Used on Emperium + + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + clif_skill_estimation(sd, bl); + if( skillid == MER_ESTIMATION ) + sd = NULL; break; case BS_REPAIRWEAPON: @@ -4676,6 +4785,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in } break; + case MA_REMOVETRAP: case HT_REMOVETRAP: //FIXME: I think clif_skill_fail() is supposed to be sent if it fails below [ultramage] clif_skill_nodamage(src, bl, skillid, skilllv, 1); @@ -4684,13 +4794,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in struct skill_unit_group* sg; su = BL_CAST(BL_SKILL, bl); - if( (su) - && (sg = su->group) - && (sg->src_id == src->id || map_flag_vs(bl->m)) - && (skill_get_inf2(sg->skill_id)&INF2_TRAP) ) - { // prevent picking up expired traps - if( !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) - { + // Mercenaries can remove any trap + // Players can only remove their own traps or traps on Vs maps. + if( su && (sg = su->group) && (src->type == BL_MER || sg->src_id == src->id || map_flag_vs(bl->m)) && (skill_get_inf2(sg->skill_id)&INF2_TRAP) ) + { + if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) + { // prevent picking up expired traps if( battle_config.skill_removetrap_type ) { // get back all items used to deploy the trap for( i = 0; i < 10; i++ ) @@ -5095,7 +5204,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(src,bl,skillid,skilllv,1); for(i = 0; i < g->max_member; i++, j++) { if (j>8) j=0; - if ((dstsd = g->member[i].sd) != NULL && sd != dstsd) { + if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !pc_isdead(dstsd)) { if (map[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m)) continue; if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) @@ -5358,7 +5467,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr data) break; } } - if (ud->skillid == PR_LEXDIVINA) + if( ud->skillid == PR_LEXDIVINA || ud->skillid == MER_LEXDIVINA ) { sc = status_get_sc(target); if( battle_check_target(src,target, BCT_ENEMY) <= 0 && (!sc || !sc->data[SC_SILENCE]) ) @@ -5723,12 +5832,16 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case CR_GRANDCROSS: case NPC_GRANDDARKNESS: case HT_SKIDTRAP: + case MA_SKIDTRAP: case HT_LANDMINE: + case MA_LANDMINE: case HT_ANKLESNARE: case HT_SHOCKWAVE: case HT_SANDMAN: + case MA_SANDMAN: case HT_FLASHER: case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: case HT_BLASTMINE: case HT_CLAYMORETRAP: case AS_VENOMDUST: @@ -5740,6 +5853,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk case WE_CALLPARENT: case WE_CALLBABY: case AC_SHOWER: //Ground-placed skill implementation. + case MA_SHOWER: case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE: @@ -6333,12 +6447,16 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli case HT_SHOCKWAVE: val1=skilllv*15+10; case HT_SANDMAN: + case MA_SANDMAN: case HT_CLAYMORETRAP: case HT_SKIDTRAP: + case MA_SKIDTRAP: case HT_LANDMINE: + case MA_LANDMINE: case HT_ANKLESNARE: case HT_FLASHER: case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: case HT_BLASTMINE: if( map_flag_gvg(src->m) ) limit *= 4; // longer trap times in WOE [celest] @@ -6557,13 +6675,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli val2 = map_getcell(src->m, ux, uy, CELL_GETTYPE); break; case HT_LANDMINE: + case MA_LANDMINE: case HT_ANKLESNARE: case HT_SHOCKWAVE: case HT_SANDMAN: + case MA_SANDMAN: case HT_FLASHER: case HT_FREEZINGTRAP: + case MA_FREEZINGTRAP: case HT_TALKIEBOX: case HT_SKIDTRAP: + case MA_SKIDTRAP: val1 = 3500; break; case GS_DESPERADO: @@ -7780,7 +7902,9 @@ int skill_check_condition(struct map_session_data* sd, short skill, short lv, in case TF_HIDING: case AS_CLOAKING: case CR_AUTOGUARD: + case ML_AUTOGUARD: case CR_DEFENDER: + case ML_DEFENDER: case ST_CHASEWALK: case PA_GOSPEL: case CR_SHRINK: @@ -8411,10 +8535,11 @@ int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv) { int delaynodex = skill_get_delaynodex(skill_id, skill_lv); int time = skill_get_delay(skill_id, skill_lv); - //struct map_session_data *sd = BL_CAST(BL_PC, bl); + struct map_session_data *sd; struct status_change *sc = status_get_sc(bl); nullpo_retr(0, bl); + sd = BL_CAST(BL_PC, bl); if (skill_id == SA_ABRACADABRA) return 0; //Will use picked skill's delay. @@ -8477,9 +8602,8 @@ int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv) } } - if (!(delaynodex&4)) - if (bl->type == BL_PC && ((TBL_PC*)bl)->delayrate != 100) - time = time * ((TBL_PC*)bl)->delayrate / 100; + if( !(delaynodex&4) && sd && sd->delayrate != 100 ) + time = time * sd->delayrate / 100; if (battle_config.delay_rate != 100) time = time * battle_config.delay_rate / 100; @@ -10557,6 +10681,30 @@ int skill_blockhomun_start(struct homun_data *hd, int skillid, int tick) //[orn] return add_timer(gettick() + tick, skill_blockhomun_end, hd->bl.id, skillid); } +int skill_blockmerc_end(int tid, unsigned int tick, int id, intptr data) //[orn] +{ + struct mercenary_data *md = (TBL_MER*)map_id2bl(id); + if( data <= 0 || data >= MAX_SKILL ) + return 0; + if( md ) md->blockskill[data] = 0; + + return 1; +} + +int skill_blockmerc_start(struct mercenary_data *md, int skillid, int tick) +{ + nullpo_retr (-1, md); + + if( (skillid = skill_get_index(skillid)) == 0 ) + return -1; + if( tick < 1 ) + { + md->blockskill[skillid] = 0; + return -1; + } + md->blockskill[skillid] = 1; + return add_timer(gettick() + tick, skill_blockmerc_end, md->bl.id, skillid); +} /* * diff --git a/src/map/skill.h b/src/map/skill.h index 34ce889b8..75cb63e9c 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -327,8 +327,9 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag ); int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skilllv,unsigned int tick,int flag); -int skill_blockpc_start (struct map_session_data*,int,int); // [celest] -int skill_blockhomun_start (struct homun_data*,int,int); //[orn] +int skill_blockpc_start (struct map_session_data*,int,int); +int skill_blockhomun_start (struct homun_data*,int,int); +int skill_blockmerc_start (struct mercenary_data*,int,int); // スキル攻?一括?理 int skill_attack( int attack_type, struct block_list* src, struct block_list *dsrc,struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag ); diff --git a/src/map/status.c b/src/map/status.c index 44c829078..b1fd9df34 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -403,6 +403,26 @@ void initChangeTables(void) set_sc( HAMI_DEFENCE , SC_DEFENCE , SI_BLANK , SCB_DEF ); set_sc( HAMI_BLOODLUST , SC_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK ); + add_sc( MER_CRASH , SC_STUN ); + set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); + add_sc( MS_MAGNUM , SC_WATK_ELEMENT ); + add_sc( MER_SIGHT , SC_SIGHT ); + set_sc( MER_DECAGI , SC_DECREASEAGI , SI_DECREASEAGI , SCB_AGI|SCB_SPEED ); + set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN ); + add_sc( MER_LEXDIVINA , SC_SILENCE ); + add_sc( MA_LANDMINE , SC_STUN ); + add_sc( MA_SANDMAN , SC_SLEEP ); + add_sc( MA_FREEZINGTRAP , SC_FREEZE ); + set_sc( MER_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE ); + set_sc( ML_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE ); + set_sc( MS_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE ); + set_sc( ML_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD ); + set_sc( MS_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); + set_sc( MS_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN ); + add_sc( ML_SPIRALPIERCE , SC_STOP ); + set_sc( MER_QUICKEN , SC_MERC_QUICKEN , SI_BLANK , SCB_ASPD ); + add_sc( ML_DEVOTION , SC_DEVOTION ); + set_sc( GD_LEADERSHIP , SC_GUILDAURA , SI_BLANK , SCB_STR|SCB_AGI|SCB_VIT|SCB_DEX ); set_sc( GD_BATTLEORDER , SC_BATTLEORDERS , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX ); set_sc( GD_REGENERATION , SC_REGENERATION , SI_BLANK , SCB_REGEN ); @@ -637,18 +657,23 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s if (sc && !sc->count) sc = NULL; - if (hp && !(flag&1)) { - if (sc) { + if( hp && !(flag&1) ) { + if( sc ) { struct status_change_entry *sce; - if ((sce=sc->data[SC_DEVOTION]) && src && battle_getcurrentskill(src) != PA_PRESSURE) - { //Devotion prevents any of the other ailments from ending. - struct map_session_data *sd2 = map_id2sd(sce->val1); - if (sd2 && sd2->devotion[sce->val2] == target->id && check_distance_bl(target, &sd2->bl, sce->val3)) + if( (sce = sc->data[SC_DEVOTION]) && src && battle_getcurrentskill(src) != PA_PRESSURE ) + { // Devotion prevents any of the other ailments from ending. + struct block_list *d_bl = map_id2bl(sce->val1); + + if( d_bl && ( + (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || + (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) + ) && check_distance_bl(target, d_bl, sce->val3) ) { - clif_damage(&sd2->bl, &sd2->bl, gettick(), 0, 0, hp, 0, 0, 0); - status_fix_damage(NULL, &sd2->bl, hp, 0); + clif_damage(d_bl, d_bl, gettick(), 0, 0, hp, 0, 0, 0); + status_fix_damage(NULL, d_bl, hp, 0); return 0; } + status_change_end(target, SC_DEVOTION, -1); } if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) @@ -2963,11 +2988,6 @@ void status_calc_bl_sub_mer(struct mercenary_data *md, unsigned long flag) status->max_sp = cap_value(status->max_sp, 1, battle_config.max_sp); status->sp = cap_value(status->sp, 0, status->max_sp); } - if( flag&SCB_VIT ) - { - flag |= SCB_DEF; - status->def += status->vit; // Doddler says Merc DEF = DEF + VIT - } if( flag == SCB_ALL ) return; // Client Refresh invoked by status_calc_mercenary @@ -3908,6 +3928,10 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * max < sc->data[SC_ONEHAND]->val2) max = sc->data[SC_ONEHAND]->val2; + if(sc->data[SC_MERC_QUICKEN] && + max < sc->data[SC_MERC_QUICKEN]->val2) + max = sc->data[SC_MERC_QUICKEN]->val2; + if(sc->data[SC_ADRENALINE2] && max < sc->data[SC_ADRENALINE2]->val3) max = sc->data[SC_ADRENALINE2]->val3; @@ -4804,6 +4828,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val return 0; break; case SC_ONEHAND: + case SC_MERC_QUICKEN: case SC_TWOHANDQUICKEN: if(sc->data[SC_DECREASEAGI]) return 0; @@ -4974,6 +4999,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl,SC_SPEARQUICKEN,-1); status_change_end(bl,SC_TWOHANDQUICKEN,-1); status_change_end(bl,SC_ONEHAND,-1); + status_change_end(bl,SC_MERC_QUICKEN,-1); break; case SC_ONEHAND: //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] @@ -5010,6 +5036,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl,SC_CONCENTRATION,-1); status_change_end(bl,SC_PARRYING,-1); status_change_end(bl,SC_AURABLADE,-1); + status_change_end(bl,SC_MERC_QUICKEN,-1); } break; case SC_ASSUMPTIO: @@ -5140,19 +5167,23 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_ENDURE: val2 = 7; // Hit-count [Celest] - if (!(flag&1) && sd && !map_flag_gvg(bl->m) && (type != SC_ENDURE || !val4)) - { //See if there are devoted characters, and pass the status to them. [Skotlex] - //(but do not pass infinite endure) + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !val4 ) + { struct map_session_data *tsd; - int i; - for (i = 0; i < 5; i++) - { - if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i]))) - status_change_start(&tsd->bl,type,10000,val1,val2,val3,val4,tick,1); + if( sd ) + { + int i; + for( i = 0; i < 5; i++ ) + { + if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + } } + else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); } //val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) - if(val4) + if( val4 ) tick = -1; break; case SC_AUTOBERSERK: @@ -5221,16 +5252,21 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2=val1*5; //Race/Ele resist break; case SC_REFLECTSHIELD: - val2=10+val1*3; //% Dmg reflected - if (sd && !(flag&1)) - { //Pass it to devoted chars. + val2=10+val1*3; // %Dmg reflected + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) + { struct map_session_data *tsd; - int i; - for (i = 0; i < 5; i++) - { //Pass the status to the other affected chars. [Skotlex] - if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i]))) - status_change_start(&tsd->bl,type,10000,val1,val2,0,0,tick,1); + if( sd ) + { + int i; + for( i = 0; i < 5; i++ ) + { + if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + } } + else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } break; case SC_STRIPWEAPON: @@ -5290,6 +5326,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (val1 > 10) //For boss casted skills [Skotlex] val2 += 20*(val1-10); break; + case SC_MERC_QUICKEN: + val2 = 300; + break; + case SC_SPEARQUICKEN: val2 = 200+10*val1; break; @@ -5458,19 +5498,28 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_AUTOGUARD: - if (!(flag&1)) + if( !(flag&1) ) { struct map_session_data *tsd; int i,t; - for(i=val2=0;i<val1;i++) { + for( i = val2 = 0; i < val1; i++) + { t = 5-(i>>1); val2 += (t < 0)? 1:t; } - if (sd) - for (i = 0; i < 5; i++) - { //Pass the status to the other affected chars. [Skotlex] - if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i]))) - status_change_start(&tsd->bl,type,10000,val1,val2,0,0,tick,1); + + if( bl->type&(BL_PC|BL_MER) ) + { + if( sd ) + { + for( i = 0; i < 5; i++ ) + { + if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + } + } + else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } } break; @@ -5702,19 +5751,19 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_DEVOTION: { - struct map_session_data *src; - if ((src = map_id2sd(val1)) && src->sc.count) - { //Try to inherit the status from the Crusader [Skotlex] - //Ideally, we should calculate the remaining time and use that, but we'll trust that - //once the Crusader's status changes, it will reflect on the others. + struct block_list *d_bl; + struct status_change *d_sc; + + if( (d_bl = map_id2bl(val1)) && (d_sc = status_get_sc(d_bl)) && d_sc->count ) + { // Inherits Status From Source const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE }; enum sc_type type2; int i = map_flag_gvg(bl->m)?2:3; - while (i >= 0) { + while( i >= 0 ) + { type2 = types[i]; - if (src->sc.data[type2]) - sc_start(bl,type2,100,src->sc.data[type2]->val1, - skill_get_time(status_sc2skill(type2),src->sc.data[type2]->val1)); + if( d_sc->data[type2] ) + sc_start(bl, type2, 100, d_sc->data[type2]->val1, skill_get_time(status_sc2skill(type2),d_sc->data[type2]->val1)); i--; } } @@ -6476,32 +6525,44 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid) case SC_DEFENDER: case SC_REFLECTSHIELD: case SC_AUTOGUARD: - if (sd) { - struct map_session_data *tsd; - int i; - for (i = 0; i < 5; i++) - { //Clear the status from the others too [Skotlex] - if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) && tsd->sc.data[type]) - status_change_end(&tsd->bl,type,-1); + { + struct map_session_data *tsd; + if( bl->type == BL_PC ) + { // Clear Status from others + int i; + for( i = 0; i < 5; i++ ) + { + if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) && tsd->sc.data[type] ) + status_change_end(&tsd->bl, type, -1); + } + } + else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) + { // Clear Status from Master + tsd = ((TBL_MER*)bl)->master; + if( tsd && tsd->sc.data[type] ) + status_change_end(&tsd->bl, type, -1); + } } - } - break; - case SC_DEVOTION: - { - struct map_session_data *md = map_id2sd(sce->val1); - //The status could have changed because the Crusader left the game. [Skotlex] - if (md) + break; + case SC_DEVOTION: { - md->devotion[sce->val2] = 0; - clif_devotion(md,NULL); + struct block_list *d_bl = map_id2bl(sce->val1); + if( d_bl ) + { + if( d_bl->type == BL_PC ) + ((TBL_PC*)d_bl)->devotion[sce->val2] = 0; + else if( d_bl->type == BL_MER ) + ((TBL_MER*)d_bl)->devotion_flag = 0; + clif_devotion(d_bl, NULL); + } + + status_change_end(bl,SC_AUTOGUARD,-1); + status_change_end(bl,SC_DEFENDER,-1); + status_change_end(bl,SC_REFLECTSHIELD,-1); + status_change_end(bl,SC_ENDURE,-1); } - //Remove inherited status [Skotlex] - status_change_end(bl,SC_AUTOGUARD,-1); - status_change_end(bl,SC_DEFENDER,-1); - status_change_end(bl,SC_REFLECTSHIELD,-1); - status_change_end(bl,SC_ENDURE,-1); - } - break; + break; + case SC_BLADESTOP: if(sce->val4) { @@ -6608,8 +6669,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid) sc->data[SC_ENDURE]->val4 = 0; status_change_end(bl, SC_ENDURE, -1); } - sc_start4(bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), - skill_get_time(LK_BERSERK, sce->val1)); + sc_start4(bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill_get_time(LK_BERSERK, sce->val1)); break; case SC_GOSPEL: if (sce->val3) { //Clear the group. @@ -6725,6 +6785,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid) case SC_ONEHAND: case SC_SPEARQUICKEN: case SC_CONCENTRATION: + case SC_MERC_QUICKEN: sc->opt3 &= ~0x1; opt_flag = 0; break; @@ -6813,7 +6874,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid) } //On Aegis, when turning off a status change, first goes the sc packet, then the option packet. - if( vd && pcdb_checkid(vd->class_) ) + if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) ) clif_status_change(bl,StatusIconChangeTable[type],0); else if (sd) clif_status_load(bl,StatusIconChangeTable[type],0); diff --git a/src/map/status.h b/src/map/status.h index ae26c499e..f5e36ec88 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -302,6 +302,7 @@ typedef enum sc_type { SC_MERC_HPUP, SC_MERC_SPUP, SC_MERC_HITUP, + SC_MERC_QUICKEN, SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; diff --git a/src/map/unit.c b/src/map/unit.c index 4003e89c6..daa96819f 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -945,29 +945,32 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh return 0; } //TODO: Add type-independant skill_check_condition function. - if (src->type == BL_MOB) { - switch (skill_num) { + if( src->type == BL_MOB ) + switch( skill_num ) + { case NPC_SUMMONSLAVE: case NPC_SUMMONMONSTER: case AL_TELEPORT: - if (((TBL_MOB*)src)->master_id && ((TBL_MOB*)src)->special_state.ai) + if( ((TBL_MOB*)src)->master_id && ((TBL_MOB*)src)->special_state.ai ) return 0; } - } - + //Check range when not using skill on yourself or is a combo-skill during attack //(these are supposed to always have the same range as your attack) - if(src->id != target_id && (!temp || ud->attacktimer == -1)) + if( src->id != target_id && (!temp || ud->attacktimer == -1) ) { - if (skill_get_state(ud->skillid) == ST_MOVE_ENABLE) + if( skill_get_state(ud->skillid) == ST_MOVE_ENABLE ) { - if (!unit_can_reach_bl(src, target, skill_get_range2(src, skill_num,skill_lv)+1, 1, NULL, NULL)) - return 0; //Walk-path check failed. - } else - if (!battle_check_range(src, target, skill_get_range2(src, skill_num,skill_lv) - +(skill_num==RG_CLOSECONFINE?0:1))) - //Close confine is exploitable thanks to this extra range "feature" of the client. [Skotlex] - return 0; //Arrow-path check failed. + if( !unit_can_reach_bl(src, target, skill_get_range2(src, skill_num,skill_lv) + 1, 1, NULL, NULL) ) + return 0; // Walk-path check failed. + } + else if( src->type == BL_MER && skill_num == MA_REMOVETRAP ) + { + if( !battle_check_range(battle_get_master(src), target, skill_get_range2(src, skill_num, skill_lv) + 1) ) + return 0; // Aegis calc remove trap based on Master position, ignoring mercenary O.O + } + else if( !battle_check_range(src, target, skill_get_range2(src, skill_num,skill_lv) + (skill_num == RG_CLOSECONFINE?0:1)) ) + return 0; // Arrow-path check failed. } if (!temp) //Stop attack on non-combo skills [Skotlex] @@ -1028,8 +1031,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh if (!(skill_get_castnodex(skill_num, skill_lv)&2)) casttime = skill_castfix_sc(src, casttime); - if( casttime>0 || temp){ - + if( casttime > 0 || temp ) + { 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) @@ -1062,8 +1065,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh } } - if( casttime<=0 ) - ud->state.skillcastcancel=0; + if( casttime <= 0 ) + ud->state.skillcastcancel = 0; ud->canact_tick = tick + casttime + 100; ud->skilltarget = target_id; @@ -1072,14 +1075,14 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh ud->skillid = skill_num; ud->skilllv = skill_lv; - if(sc && sc->data[SC_CLOAKING] && - !(sc->data[SC_CLOAKING]->val4&4) && skill_num != AS_CLOAKING) + if( sc && sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4) && skill_num != AS_CLOAKING ) { status_change_end(src,SC_CLOAKING,-1); if (!src->prev) return 0; //Warped away! } - if(casttime > 0) { + if( casttime > 0 ) + { ud->skilltimer = add_timer( tick+casttime, skill_castend_id, src->id, 0 ); if( sd && pc_checkskill(sd,SA_FREECAST) > 0 ) status_calc_bl(&sd->bl, SCB_SPEED); @@ -1147,12 +1150,12 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh bl.x = skill_x; bl.y = skill_y; - if (skill_get_state(ud->skillid) == ST_MOVE_ENABLE) + if( skill_get_state(ud->skillid) == ST_MOVE_ENABLE ) { - if (!unit_can_reach_bl(src, &bl, skill_get_range2(src, skill_num,skill_lv)+1, 1, NULL, NULL)) + if( !unit_can_reach_bl(src, &bl, skill_get_range2(src, skill_num,skill_lv) + 1, 1, NULL, NULL) ) return 0; //Walk-path check failed. - } else - if (!battle_check_range(src,&bl,skill_get_range2(src, skill_num,skill_lv)+1)) + } + else if( !battle_check_range(src, &bl, skill_get_range2(src, skill_num,skill_lv) + 1) ) return 0; //Arrow-path check failed. unit_stop_attack(src); @@ -1162,10 +1165,12 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh if (!(skill_get_castnodex(skill_num, skill_lv)&2)) casttime = skill_castfix_sc(src, casttime); - if( casttime>0 ) { + 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); - } else + } + else ud->state.skillcastcancel=0; ud->canact_tick = tick + casttime + 100; @@ -1181,14 +1186,16 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh if (!src->prev) return 0; //Warped away! } - if(casttime > 0) { + if( casttime > 0 ) + { ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 ); if( sd && pc_checkskill(sd,SA_FREECAST) > 0 ) status_calc_bl(&sd->bl, SCB_SPEED); else unit_stop_walking(src,1); } - else { + else + { ud->skilltimer = INVALID_TIMER; skill_castend_pos(ud->skilltimer,tick,src->id,0); } |