- Full implementation of mercenary skills.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13203 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
zephyrus 2008-09-10 14:30:25 +00:00
parent 331e0a0a15
commit 2513d01bee
10 changed files with 625 additions and 325 deletions

View File

@ -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)
if( skill_get_inf2(su->group->skill_id)&INF2_TRAP )
{ //Only a few skills can target traps...
switch (battle_getcurrentskill(src))
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);

View File

@ -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;
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(&sd->bl,CR_DEVOTION,pc_checkskill(sd,CR_DEVOTION)); // ignored
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);
}
/*==========================================
* ƒXƒLƒŽgp<EFBFBD>iIDŽwè<EFBFBD>j
*------------------------------------------*/
@ -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();
if( !(skill_get_inf(skillnum)&INF_GROUND_SKILL) )
return; //Using a target skill on the ground? WRONG.
if( skillnum >= MC_SKILLBASE && skillnum < MC_SKILLBASE + MAX_MERCSKILL )
{
clif_parse_UseSkillToPos_mercenary(sd->md, sd, tick, skillnum, skilllv, x, y, skillmoreinfo);
return;
}
//Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex]
sd->idletime = last_tick;
if (skillnotok(skillnum, sd))
if( skillnotok(skillnum, sd) )
return;
if (!(skill_get_inf(skillnum)&INF_GROUND_SKILL))
return; //Using a target skill on the ground? WRONG.
if (skillmoreinfo != -1) {
if (pc_issit(sd)) {
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;

View File

@ -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_);

View File

@ -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
|| (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))

View File

@ -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 )

View File

@ -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:
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)));
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:
@ -3372,6 +3409,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case MO_BLADESTOP:
case LK_AURABLADE:
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) {
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 );
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 )
{// not there, find first empty slot
ARR_FIND( 0, count, i, sd->devotion[i] == 0 );
{
ARR_FIND(0, count, i, sd->devotion[i] == 0 );
if( i == count )
{// all slots full, fail
clif_skill_fail(sd,skillid,0,0);
{ // No free slots, skill Fail
clif_skill_fail(sd, skillid, 0, 0);
map_freeblock_unlock();
return 1;
}
}
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);
}
else
if (sd)
clif_skill_fail(sd,skillid,0,0);
mer->devotion_flag = 1; // Mercenary Devoting Owner
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);
}
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,8 +3877,9 @@ 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)
case SM_AUTOBERSERK:
case MER_AUTOBERSERK:
if( tsce )
i = status_change_end(bl, type, -1);
else
i = sc_start(bl,type,100,skilllv,60000);
@ -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) {
if( sd == NULL )
break;
if( dstsd )
{ // Fail on Players
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( 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);
}
/*
*

View File

@ -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 );

View File

@ -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)
struct map_session_data *tsd;
int i;
for (i = 0; i < 5; i++)
if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !val4 )
{
if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
status_change_start(&tsd->bl,type,10000,val1,val2,val3,val4,tick,1);
struct map_session_data *tsd;
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,17 +5252,22 @@ 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;
if( sd )
{
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);
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:
if (!sd) //Watk reduction
@ -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;
if( bl->type == BL_PC )
{ // Clear Status from others
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);
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)
struct block_list *d_bl = map_id2bl(sce->val1);
if( d_bl )
{
md->devotion[sce->val2] = 0;
clif_devotion(md,NULL);
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);
}
//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;
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);

View File

@ -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;

View File

@ -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);
}