-fix bugreport:7458 (deleting associate timer before cleanup status)

-merge clif_guild_skillup and clif_skillup (old TODO)
-add implementation for packet : 0x8c7, 0x99f and 0x1c9, variant of ZC_SKILL_ENTRY (0x11f)
-replace some hardcoded skill_flag by enum values

-little cleanup in skill_attack and regroup some skill with same effect (blewcount, animation).
-rewritte combo handling to regroup info and not duplicate info.
-change eleanor skill to use SC_COMBO as memo instead SC_STYLE_CHANGE
-separate SC_TINDER_BREAKER from SC_CLOSE_CONFINE since they don't act same way
-change MH_SONIC_CRAW to one attack with multiple hit instead x attack.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17229 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
glighta 2013-04-04 00:18:59 +00:00
parent 643861ba17
commit 7bc683e21e
15 changed files with 748 additions and 757 deletions

View File

@ -1128,7 +1128,7 @@
8025,7,6,2,4:0:4:0:4,0,0,5,1,no,0,0,0,magic,0, MH_XENO_SLASHER,Xeno Slasher 8025,7,6,2,4:0:4:0:4,0,0,5,1,no,0,0,0,magic,0, MH_XENO_SLASHER,Xeno Slasher
8026,5:5:7:7:9,6,16,0,0x1,0,5,1,no,0,0,0,magic,0, MH_SILENT_BREEZE,Silent Breeze 8026,5:5:7:7:9,6,16,0,0x1,0,5,1,no,0,0,0,magic,0, MH_SILENT_BREEZE,Silent Breeze
8027,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0, MH_STYLE_CHANGE,Style Change 8027,0,6,4,0,0x1,0,1,1,no,0,0,0,none,0, MH_STYLE_CHANGE,Style Change
8028,1,8,1,0,0,0,5,1,no,0,0,0,weapon,0, MH_SONIC_CRAW,Sonic Claw 8028,1,8,1,0,0,0,5,1,no,0,0x0200,0,weapon,0, MH_SONIC_CRAW,Sonic Claw
8029,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_SILVERVEIN_RUSH,Silver Bain Rush 8029,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_SILVERVEIN_RUSH,Silver Bain Rush
8030,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_MIDNIGHT_FRENZY,Midnight Frenzy 8030,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_MIDNIGHT_FRENZY,Midnight Frenzy
8031,5:6:7:8:9,6,1,0,0,0,5,1,no,0,0,0,weapon,3, MH_STAHL_HORN,Steel Horn 8031,5:6:7:8:9,6,1,0,0,0,5,1,no,0,0,0,weapon,3, MH_STAHL_HORN,Steel Horn
@ -1136,7 +1136,7 @@
8033,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0, MH_STEINWAND,Stone Wall 8033,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0, MH_STEINWAND,Stone Wall
8034,9,6,1,6,0x2,1:1:1:1:2,5,1,no,0,0,0,magic,0, MH_HEILIGE_STANGE,Holy Pole 8034,9,6,1,6,0x2,1:1:1:1:2,5,1,no,0,0,0,magic,0, MH_HEILIGE_STANGE,Holy Pole
8035,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0, MH_ANGRIFFS_MODUS,Attack Mode 8035,0,6,4,0,0x1,0,5,1,no,0,0,0,none,0, MH_ANGRIFFS_MODUS,Attack Mode
8036,3:4:5:6:7,6,1,0,0,0,5,1,no,0,0,0,weapon,0, MH_TINDER_BREAKER,Tinder Breaker 8036,3:4:5:6:7,6,1,0,0,0,5,1,no,0,0x0200,0,weapon,0, MH_TINDER_BREAKER,Tinder Breaker
8037,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_CBC,Continual Break Combo 8037,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_CBC,Continual Break Combo
8038,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_EQC,Eternal Quick Combo 8038,1,6,4,0,0,0,5,1,no,0,0x200,0,weapon,0, MH_EQC,Eternal Quick Combo
8039,0,6,4,3,0x2,1:1:1:2:2,5,1,no,0,0,0,weapon,0, MH_MAGMA_FLOW,Magma Flow 8039,0,6,4,3,0x2,1:1:1:2:2,5,1,no,0,0,0,weapon,0, MH_MAGMA_FLOW,Magma Flow

View File

@ -217,6 +217,7 @@ enum e_skill_flag
SKILL_FLAG_PLAGIARIZED, SKILL_FLAG_PLAGIARIZED,
SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0', SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0',
SKILL_FLAG_PERM_GRANTED, // permanent, granted through someway e.g. script SKILL_FLAG_PERM_GRANTED, // permanent, granted through someway e.g. script
SKILL_FLAG_TMP_COMBO, //@FIXME for homon combo atm
//... //...
}; };

View File

@ -3159,7 +3159,7 @@ ACMD_FUNC(lostskill)
} }
sd->status.skill[skill_id].lv = 0; sd->status.skill[skill_id].lv = 0;
sd->status.skill[skill_id].flag = 0; sd->status.skill[skill_id].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,skill_id); clif_deleteskill(sd,skill_id);
clif_displaymessage(fd, msg_txt(71)); // You have forgotten the skill. clif_displaymessage(fd, msg_txt(71)); // You have forgotten the skill.
@ -8707,7 +8707,7 @@ ACMD_FUNC(cart) {
#define MC_CART_MDFY(x) \ #define MC_CART_MDFY(x) \
sd->status.skill[MC_PUSHCART].id = x?MC_PUSHCART:0; \ sd->status.skill[MC_PUSHCART].id = x?MC_PUSHCART:0; \
sd->status.skill[MC_PUSHCART].lv = x?1:0; \ sd->status.skill[MC_PUSHCART].lv = x?1:0; \
sd->status.skill[MC_PUSHCART].flag = x?1:0; sd->status.skill[MC_PUSHCART].flag = x?SKILL_FLAG_TEMPORARY:SKILL_FLAG_PERMANENT;
int val = atoi(message); int val = atoi(message);
bool need_skill = pc_checkskill(sd, MC_PUSHCART) ? false : true; bool need_skill = pc_checkskill(sd, MC_PUSHCART) ? false : true;

View File

@ -1742,6 +1742,11 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
wd.flag |= battle_range_type(src, target, skill_id, skill_lv); wd.flag |= battle_range_type(src, target, skill_id, skill_lv);
switch(skill_id) switch(skill_id)
{ {
case MH_SONIC_CRAW:{
TBL_HOM *hd = BL_CAST(BL_HOM,src);
wd.div_ = hd->homunculus.spiritball;
}
break;
case MO_FINGEROFFENSIVE: case MO_FINGEROFFENSIVE:
if(sd) { if(sd) {
if (battle_config.finger_offensive_type) if (battle_config.finger_offensive_type)

View File

@ -965,7 +965,7 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) {
sd->status.child = 0; sd->status.child = 0;
sd->status.skill[WE_CALLBABY].id = 0; sd->status.skill[WE_CALLBABY].id = 0;
sd->status.skill[WE_CALLBABY].lv = 0; sd->status.skill[WE_CALLBABY].lv = 0;
sd->status.skill[WE_CALLBABY].flag = 0; sd->status.skill[WE_CALLBABY].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,WE_CALLBABY); clif_deleteskill(sd,WE_CALLBABY);
} }
@ -973,7 +973,7 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) {
sd->status.child = 0; sd->status.child = 0;
sd->status.skill[WE_CALLBABY].id = 0; sd->status.skill[WE_CALLBABY].id = 0;
sd->status.skill[WE_CALLBABY].lv = 0; sd->status.skill[WE_CALLBABY].lv = 0;
sd->status.skill[WE_CALLBABY].flag = 0; sd->status.skill[WE_CALLBABY].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,WE_CALLBABY); clif_deleteskill(sd,WE_CALLBABY);
} }

View File

@ -1481,9 +1481,10 @@ int clif_homskillinfoblock(struct map_session_data *sd)
WFIFOW(fd,0)=0x235; WFIFOW(fd,0)=0x235;
for ( i = 0; i < MAX_HOMUNSKILL; i++){ for ( i = 0; i < MAX_HOMUNSKILL; i++){
if( (id = hd->homunculus.hskill[i].id) != 0 ){ if( (id = hd->homunculus.hskill[i].id) != 0 ){
int combo = (hd->homunculus.hskill[i].flag)&SKILL_FLAG_TMP_COMBO;
j = id - HM_SKILLBASE; j = id - HM_SKILLBASE;
WFIFOW(fd,len ) = id; WFIFOW(fd,len ) = id;
WFIFOW(fd,len+2) = skill_get_inf(id); WFIFOW(fd,len+2) = ((combo)?INF_SELF_SKILL:skill_get_inf(id));
WFIFOW(fd,len+4) = 0; WFIFOW(fd,len+4) = 0;
WFIFOW(fd,len+6) = hd->homunculus.hskill[j].lv; WFIFOW(fd,len+6) = hd->homunculus.hskill[j].lv;
WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv); WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv);
@ -4362,46 +4363,68 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi
} }
/// Notifies the client of a skill unit. /// Notifies the client of a skill unit.
/// 011f <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B (ZC_SKILL_ENTRY) /// 011f <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B (ZC_SKILL_ENTRY)
/// 01c9 <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B <has msg>.B <msg>.80B (ZC_SKILL_ENTRY2) /// 01c9 <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B <has msg>.B <msg>.80B (ZC_SKILL_ENTRY2)
static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit) /// 08c7 <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.B <range>.W <visible>.B (ZC_SKILL_ENTRY3)
/// 099f <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.L <range>.W <visible>.B (ZC_SKILL_ENTRY4)
static void clif_getareachar_skillunit(int type,struct map_session_data *sd, struct skill_unit *unit)
{ {
int fd = sd->fd; int fd = sd->fd;
int header=0, unit_id=0, pos=0;
if( unit->group->state.guildaura ) if( unit->group->state.guildaura )
return; return;
if (battle_config.traps_setting&1 && skill_get_inf2(unit->group->skill_id)&INF2_TRAP)
unit_id=UNT_DUMMYSKILL; //Use invisible unit id for traps.
else if (skill_get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT))
unit_id=UNT_DUMMYSKILL; //Use invisible unit id for other case of rangedsingle unit
else
unit_id=unit->group->unit_id;
switch(type){
case 2: header=0x1c9; break;
case 3: header=0x8c7; break;
case 4: header=0x99f; break;
default:
case 1: header=0x11f; break;
}
#if PACKETVER >= 3 #if PACKETVER >= 3
if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris]
WFIFOHEAD(fd,packet_len(0x1c9)); clif_getareachar_skillunit(2,sd,unit);
WFIFOW(fd, 0)=0x1c9;
WFIFOL(fd, 2)=unit->bl.id;
WFIFOL(fd, 6)=unit->group->src_id;
WFIFOW(fd,10)=unit->bl.x;
WFIFOW(fd,12)=unit->bl.y;
WFIFOB(fd,14)=unit->group->unit_id;
WFIFOB(fd,15)=1;
WFIFOB(fd,16)=1;
safestrncpy((char*)WFIFOP(fd,17),unit->group->valstr,MESSAGE_SIZE);
WFIFOSET(fd,packet_len(0x1c9));
return;
} }
#endif #endif
WFIFOHEAD(fd,packet_len(0x11f)); WFIFOHEAD(fd,packet_len(header));
WFIFOW(fd, 0)=0x11f; WFIFOW(fd,pos)=header;
WFIFOL(fd, 2)=unit->bl.id; if(type==3 || type==4){
WFIFOL(fd, 6)=unit->group->src_id; WFIFOW(fd, pos+2)=packet_len(header);
WFIFOW(fd,10)=unit->bl.x; pos +=2;
WFIFOW(fd,12)=unit->bl.y; }
if (battle_config.traps_setting&1 && skill_get_inf2(unit->group->skill_id)&INF2_TRAP) WFIFOL(fd,pos+2)=unit->bl.id;
WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. WFIFOL(fd,pos+6)=unit->group->src_id;
else if (skill_get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) WFIFOW(fd,pos+10)=unit->bl.x;
WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. WFIFOW(fd,pos+12)=unit->bl.y;
else switch(type){
WFIFOB(fd,14)=unit->group->unit_id; case 1: WFIFOB(fd,pos+14)=unit_id;
WFIFOB(fd,15)=1; // ignored by client (always gets set to 1) WFIFOB(fd,pos+15)=1;
WFIFOSET(fd,packet_len(0x11f)); break;
case 2: WFIFOB(fd,pos+14)=unit_id;
WFIFOB(fd,pos+15)=1;
WFIFOB(fd,pos+16)=1;
safestrncpy((char*)WFIFOP(fd,pos+17),unit->group->valstr,MESSAGE_SIZE);
break;
case 3: WFIFOB(fd,pos+14)=unit_id;
WFIFOW(fd,pos+15)=unit->range;
WFIFOB(fd,pos+17)=1; //visible
break;
case 4: WFIFOL(fd,pos+14)=unit_id; pos += 3;
WFIFOW(fd,pos+15)=unit->range;
WFIFOB(fd,pos+17)=1;
break;
}
WFIFOSET(fd,packet_len(header));
if(unit->group->skill_id == WZ_ICEWALL) if(unit->group->skill_id == WZ_ICEWALL)
clif_changemapcell(fd,unit->bl.m,unit->bl.x,unit->bl.y,5,SELF); clif_changemapcell(fd,unit->bl.m,unit->bl.x,unit->bl.y,5,SELF);
@ -4473,7 +4496,7 @@ static int clif_getareachar(struct block_list* bl,va_list ap)
clif_getareachar_item(sd,(struct flooritem_data*) bl); clif_getareachar_item(sd,(struct flooritem_data*) bl);
break; break;
case BL_SKILL: case BL_SKILL:
clif_getareachar_skillunit(sd,(TBL_SKILL*)bl); clif_getareachar_skillunit(1,sd,(TBL_SKILL*)bl);
break; break;
default: default:
if(&sd->bl == bl) if(&sd->bl == bl)
@ -4557,7 +4580,7 @@ int clif_insight(struct block_list *bl,va_list ap)
clif_getareachar_item(tsd,(struct flooritem_data*)bl); clif_getareachar_item(tsd,(struct flooritem_data*)bl);
break; break;
case BL_SKILL: case BL_SKILL:
clif_getareachar_skillunit(tsd,(TBL_SKILL*)bl); clif_getareachar_skillunit(1,tsd,(TBL_SKILL*)bl);
break; break;
default: default:
clif_getareachar_unit(tsd,bl); clif_getareachar_unit(tsd,bl);
@ -4672,24 +4695,22 @@ void clif_deleteskill(struct map_session_data *sd, int id)
clif_skillinfoblock(sd); clif_skillinfoblock(sd);
} }
/// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE). /// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE).
/// 010e <skill id>.W <level>.W <sp cost>.W <attack range>.W <upgradable>.B /// 010e <skill id>.W <level>.W <sp cost>.W <attack range>.W <upgradable>.B
void clif_skillup(struct map_session_data *sd,uint16 skill_id) void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int range, int upgradable) {
{
int fd; int fd;
nullpo_retv(sd); nullpo_retv(sd);
fd=sd->fd; fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x10e)); WFIFOHEAD(fd, packet_len(0x10e));
WFIFOW(fd,0) = 0x10e; WFIFOW(fd, 0) = 0x10e;
WFIFOW(fd,2) = skill_id; WFIFOW(fd, 2) = skill_id;
WFIFOW(fd,4) = sd->status.skill[skill_id].lv; WFIFOW(fd, 4) = lv;
WFIFOW(fd,6) = skill_get_sp(skill_id,sd->status.skill[skill_id].lv); WFIFOW(fd, 6) = skill_get_sp(skill_id, lv);
WFIFOW(fd,8) = skill_get_range2(&sd->bl,skill_id,sd->status.skill[skill_id].lv); WFIFOW(fd, 8) = range;
WFIFOB(fd,10) = (sd->status.skill[skill_id].lv < skill_tree_get_max(sd->status.skill[skill_id].id, sd->status.class_)) ? 1 : 0; WFIFOB(fd, 10) = upgradable;
WFIFOSET(fd,packet_len(0x10e)); WFIFOSET(fd, packet_len(0x10e));
} }
@ -7878,29 +7899,6 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
clif_send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG); clif_send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG);
} }
/*==========================================
* Server tells client 'sd' that his guild skill 'skill_id' gone to level 'lv'
*------------------------------------------*/
int clif_guild_skillup(struct map_session_data *sd,uint16 skill_id,int lv)
{// TODO: Merge with clif_skillup (same packet).
int fd;
nullpo_ret(sd);
fd=sd->fd;
WFIFOHEAD(fd,11);
WFIFOW(fd,0) = 0x10e;
WFIFOW(fd,2) = skill_id;
WFIFOW(fd,4) = lv;
WFIFOW(fd,6) = skill_get_sp(skill_id,lv);
WFIFOW(fd,8) = skill_get_range(skill_id,lv);
WFIFOB(fd,10) = 1;
WFIFOSET(fd,11);
return 0;
}
/// Request for guild alliance (ZC_REQ_ALLY_GUILD). /// Request for guild alliance (ZC_REQ_ALLY_GUILD).
/// 0171 <inviter account id>.L <guild name>.24B /// 0171 <inviter account id>.L <guild name>.24B
void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name) void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name)
@ -12267,7 +12265,7 @@ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd)
struct guild* g; struct guild* g;
int guild_id = RFIFOL(fd,2); int guild_id = RFIFOL(fd,2);
if( (g = guild_search(guild_id)) != NULL ) if( (g = sd->guild) != NULL )
clif_guild_emblem(sd,g); clif_guild_emblem(sd,g);
} }

View File

@ -426,7 +426,7 @@ void clif_class_change(struct block_list *bl,int class_,int type);
#define clif_mob_class_change(md, class_) clif_class_change(&md->bl, class_, 1) #define clif_mob_class_change(md, class_) clif_class_change(&md->bl, class_, 1)
void clif_skillinfoblock(struct map_session_data *sd); void clif_skillinfoblock(struct map_session_data *sd);
void clif_skillup(struct map_session_data *sd,uint16 skill_id); void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int range, int upgradable);
void clif_skillinfo(struct map_session_data *sd,int skill, int inf); void clif_skillinfo(struct map_session_data *sd,int skill, int inf);
void clif_addskill(struct map_session_data *sd, int id); void clif_addskill(struct map_session_data *sd, int id);
void clif_deleteskill(struct map_session_data *sd, int id); void clif_deleteskill(struct map_session_data *sd, int id);
@ -541,7 +541,6 @@ void clif_guild_emblem(struct map_session_data *sd,struct guild *g);
void clif_guild_emblem_area(struct block_list* bl); void clif_guild_emblem_area(struct block_list* bl);
void clif_guild_notice(struct map_session_data* sd, struct guild* g); void clif_guild_notice(struct map_session_data* sd, struct guild* g);
void clif_guild_message(struct guild *g,int account_id,const char *mes,int len); void clif_guild_message(struct guild *g,int account_id,const char *mes,int len);
int clif_guild_skillup(struct map_session_data *sd,uint16 skill_id,int lv);
void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name); void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name);
void clif_guild_allianceack(struct map_session_data *sd,int flag); void clif_guild_allianceack(struct map_session_data *sd,int flag);
void clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag); void clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag);

View File

@ -717,7 +717,6 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag)
if( tsd ) clif_guild_inviteack(tsd,3); if( tsd ) clif_guild_inviteack(tsd,3);
return 0; return 0;
} }
sd->guild = g; sd->guild = g;
guild_makemember(&m,sd); guild_makemember(&m,sd);
intif_guild_addmember(guild_id, &m); intif_guild_addmember(guild_id, &m);
@ -1326,7 +1325,9 @@ int guild_skillupack(int guild_id,uint16 skill_id,int account_id)
if(g==NULL) if(g==NULL)
return 0; return 0;
if( sd != NULL ) { if( sd != NULL ) {
clif_guild_skillup(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv); int lv = g->skill[skill_id-GD_SKILLBASE].lv;
int range = skill_get_range(skill_id, lv);
clif_skillup(sd,skill_id,lv,range,1);
/* Guild Aura handling */ /* Guild Aura handling */
switch( skill_id ) { switch( skill_id ) {

View File

@ -379,6 +379,8 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
skill_unit_move(bl,tick,2); skill_unit_move(bl,tick,2);
status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER);
status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER);
status_change_end(bl, SC_TINDER_BREAKER, INVALID_TIMER);
status_change_end(bl, SC_TINDER_BREAKER2, INVALID_TIMER);
// status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... // status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure...
status_change_end(bl, SC_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_TATAMIGAESHI, INVALID_TIMER);
status_change_end(bl, SC_MAGICROD, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER);

View File

@ -2639,8 +2639,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL)); mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL));
// Remove all status changes before creating a respawn // Remove all status changes before creating a respawn
if( sc ) if( sc ){
for(i=0; i<SC_MAX; i++){
if(sc->data[i] && (sc->data[i]->timer != INVALID_TIMER))
delete_timer(sc->data[i]->timer, status_change_timer);
}
memset( sc, 0, sizeof( struct status_change ) ); memset( sc, 0, sizeof( struct status_change ) );
}
if( !rebirth ) if( !rebirth )
mob_setdelayspawn(md); //Set respawning. mob_setdelayspawn(md); //Set respawning.

View File

@ -1291,7 +1291,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) { if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) {
sd->status.skill[i].id = 0; sd->status.skill[i].id = 0;
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
break; break;
} }
@ -1520,12 +1520,12 @@ int pc_clean_skilltree(struct map_session_data *sd)
{ {
sd->status.skill[i].id = 0; sd->status.skill[i].id = 0;
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
else else
if (sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0){ if (sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0){
sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
} }
@ -6042,6 +6042,7 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id)
sd->status.skill[skill_id].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] sd->status.skill[skill_id].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
sd->status.skill[skill_id].lv < skill_tree_get_max(skill_id, sd->status.class_) ) sd->status.skill[skill_id].lv < skill_tree_get_max(skill_id, sd->status.class_) )
{ {
int lv,range, upgradable;
sd->status.skill[skill_id].lv++; sd->status.skill[skill_id].lv++;
sd->status.skill_point--; sd->status.skill_point--;
if( !skill_get_inf(skill_id) ) if( !skill_get_inf(skill_id) )
@ -6051,7 +6052,10 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id)
else else
pc_check_skilltree(sd, skill_id); // Check if a new skill can Lvlup pc_check_skilltree(sd, skill_id); // Check if a new skill can Lvlup
clif_skillup(sd,skill_id); lv = sd->status.skill[skill_id].lv;
range = skill_get_range2(&sd->bl, skill_id, lv);
upgradable = (lv < skill_tree_get_max(sd->status.skill[skill_id].id, sd->status.class_)) ? 1 : 0;
clif_skillup(sd,skill_id,lv,range,upgradable);
clif_updatestatus(sd,SP_SKILLPOINT); clif_updatestatus(sd,SP_SKILLPOINT);
if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */
clif_updatestatus(sd,SP_CARTINFO); clif_updatestatus(sd,SP_CARTINFO);
@ -6337,7 +6341,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
if( i == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) if( i == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE )
{ {
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
continue; continue;
} }
@ -6356,7 +6360,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
if( battle_config.quest_skill_reset && !(flag&2) ) if( battle_config.quest_skill_reset && !(flag&2) )
{ //Wipe them { //Wipe them
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
continue; continue;
} }
@ -6369,7 +6373,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
if( !(flag&2) ) if( !(flag&2) )
{// reset {// reset
sd->status.skill[i].lv = 0; sd->status.skill[i].lv = 0;
sd->status.skill[i].flag = 0; sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
} }
} }
@ -7364,7 +7368,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
if( sd->status.skill[sd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED ) { if( sd->status.skill[sd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED ) {
sd->status.skill[sd->cloneskill_id].id = 0; sd->status.skill[sd->cloneskill_id].id = 0;
sd->status.skill[sd->cloneskill_id].lv = 0; sd->status.skill[sd->cloneskill_id].lv = 0;
sd->status.skill[sd->cloneskill_id].flag = 0; sd->status.skill[sd->cloneskill_id].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,sd->cloneskill_id); clif_deleteskill(sd,sd->cloneskill_id);
} }
sd->cloneskill_id = 0; sd->cloneskill_id = 0;
@ -7376,7 +7380,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
if( sd->status.skill[sd->reproduceskill_id].flag == SKILL_FLAG_PLAGIARIZED ) { if( sd->status.skill[sd->reproduceskill_id].flag == SKILL_FLAG_PLAGIARIZED ) {
sd->status.skill[sd->reproduceskill_id].id = 0; sd->status.skill[sd->reproduceskill_id].id = 0;
sd->status.skill[sd->reproduceskill_id].lv = 0; sd->status.skill[sd->reproduceskill_id].lv = 0;
sd->status.skill[sd->reproduceskill_id].flag = 0; sd->status.skill[sd->reproduceskill_id].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(sd,sd->reproduceskill_id); clif_deleteskill(sd,sd->reproduceskill_id);
} }
sd->reproduceskill_id = 0; sd->reproduceskill_id = 0;

View File

@ -657,91 +657,35 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd)
if (hd->blockskill[idx] > 0) if (hd->blockskill[idx] > 0)
return 1; return 1;
switch(skill_id){ switch(skill_id){
case MH_LIGHT_OF_REGENE: case MH_LIGHT_OF_REGENE: //must be cordial
if(hd->homunculus.intimacy <= 750) //if not cordial if(hd->homunculus.intimacy <= 750) return 1;
return 1;
break; break;
case MH_OVERED_BOOST: case MH_OVERED_BOOST: //if we starving
if(hd->homunculus.hunger <= 1) //if we starving if(hd->homunculus.hunger <= 1) return 1;
return 1;
break; break;
case MH_GOLDENE_FERSE: //cant be used with angriff case MH_GOLDENE_FERSE: //cant be used with angriff
if(hd->sc.data[SC_ANGRIFFS_MODUS]) if(hd->sc.data[SC_ANGRIFFS_MODUS]) return 1;
return 1;
break; break;
case MH_ANGRIFFS_MODUS: case MH_ANGRIFFS_MODUS:
if(hd->sc.data[SC_GOLDENE_FERSE]) if(hd->sc.data[SC_GOLDENE_FERSE]) return 1;
return 1;
break; break;
case MH_TINDER_BREAKER: case MH_TINDER_BREAKER: //must be in grappling mode
case MH_CBC: if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) return 1;
case MH_EQC: break;
case MH_SONIC_CRAW: case MH_SONIC_CRAW: //must be in fighting mode
case MH_SILVERVEIN_RUSH: if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) return 1;
case MH_MIDNIGHT_FRENZY: { break;
struct status_change_entry *sce = hd->sc.data[SC_STYLE_CHANGE]; case MH_SILVERVEIN_RUSH:
TBL_PC *sd; if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)) return 1;
if(!(sd=hd->master) || !sce) return 1; //homon doesn't have status or a master
if((!sce->val3) && (skill_id != MH_SONIC_CRAW && skill_id != MH_TINDER_BREAKER))
return 1; // or it's not a combo
switch(skill_id){
case MH_SONIC_CRAW:
case MH_SILVERVEIN_RUSH:
case MH_TINDER_BREAKER:
case MH_CBC:
if(!hd->homunculus.spiritball) {
clif_colormes(sd,COLOR_RED,"Homon need some spiritballs");
return 1;
}
break; break;
case MH_MIDNIGHT_FRENZY: case MH_MIDNIGHT_FRENZY:
case MH_EQC: if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) return 1;
if(hd->homunculus.spiritball < 2) {
clif_colormes(sd,COLOR_RED,"Homon need at least 2 spiritballs");
return 1;
}
break; break;
}
switch(skill_id){
case MH_SONIC_CRAW:
case MH_SILVERVEIN_RUSH:
case MH_MIDNIGHT_FRENZY:
if (!(sce->val1 == MH_MD_FIGHTING)){
clif_colormes(sd,COLOR_RED,"Homon need to be in fighting mode to use that skill");
return 1;
}
break;
case MH_TINDER_BREAKER:
case MH_CBC: case MH_CBC:
case MH_EQC: if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) return 1;
if (!(sce->val1 == MH_MD_GRAPPLING)){
clif_colormes(sd,COLOR_RED,"Homon need to be in grappling mode to use that skill");
return 1;
}
break; break;
} case MH_EQC:
if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)) return 1;
//now let really be specific
switch(skill_id){
case MH_TINDER_BREAKER:
if(sce->val3 == MH_EQC && (gettick() - sce->val4 <= 2000)) break;
else break; //im not a combo what should I do ??
case MH_CBC: if(sce->val3 == MH_TINDER_BREAKER && (gettick() - sce->val4 <= 2000)) break;
case MH_EQC: if(sce->val3 == MH_CBC && (gettick() - sce->val4 <= 2000)) break;
case MH_SONIC_CRAW:
if(sce->val3 == MH_MIDNIGHT_FRENZY && (gettick() - sce->val4 <= 2000)) break;
else break; //im not a combo what should I do ??
case MH_SILVERVEIN_RUSH: if(sce->val3 == MH_SONIC_CRAW && (gettick() - sce->val4 <= 2000)) break;
case MH_MIDNIGHT_FRENZY: if(sce->val3 == MH_SILVERVEIN_RUSH && (gettick() - sce->val4 <= 2000)) break;
default:
return 1;
}
}
break; break;
} }
@ -1499,6 +1443,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
case MH_XENO_SLASHER: case MH_XENO_SLASHER:
sc_start4(src,bl,SC_BLEEDING,skill_lv,skill_lv,src->id,0,0,skill_get_time2(skill_id,skill_lv)); //@TODO need real duration sc_start4(src,bl,SC_BLEEDING,skill_lv,skill_lv,src->id,0,0,skill_get_time2(skill_id,skill_lv)); //@TODO need real duration
break; break;
case WL_HELLINFERNO:
sc_start4(src,bl,SC_BURNING,55+5*skill_lv,skill_lv,1000,src->id,0,skill_get_time(skill_id,skill_lv));
break;
} }
if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai)
@ -2257,6 +2204,141 @@ static int skill_magic_reflect(struct block_list* src, struct block_list* bl, in
return 0; return 0;
} }
/*
* Combo handler, start stop combo status
*/
void skill_combo_toogle_inf(struct block_list* bl, uint16 skill_id, int inf){
TBL_PC *sd = BL_CAST(BL_PC, bl);
switch (skill_id) {
case MH_MIDNIGHT_FRENZY:
case MH_EQC:{
int skill_id2 = ((skill_id==MH_EQC)?MH_TINDER_BREAKER:MH_SONIC_CRAW);
int idx = skill_get_index(skill_id2);
int flag = (inf?SKILL_FLAG_TMP_COMBO:SKILL_FLAG_PERMANENT);
TBL_HOM *hd = BL_CAST(BL_HOM, bl);
sd = hd->master;
// if (sd) clif_skillinfo(sd,skill_id2, inf);
hd->homunculus.hskill[idx].flag= SKILL_FLAG_TMP_COMBO;
if(sd) clif_homskillinfoblock(sd); //refresh info //@FIXME we only want to refresh one skill
}
break;
case MO_COMBOFINISH:
case CH_TIGERFIST:
case CH_CHAINCRUSH:
if (sd) clif_skillinfo(sd,MO_EXTREMITYFIST, inf);
break;
case TK_JUMPKICK:
if (sd) clif_skillinfo(sd,TK_JUMPKICK, inf);
break;
case MO_TRIPLEATTACK:
if (sd && pc_checkskill(sd, SR_DRAGONCOMBO) > 0)
clif_skillinfo(sd,SR_DRAGONCOMBO, inf);
break;
case SR_FALLENEMPIRE:
if (sd){
clif_skillinfo(sd,SR_GATEOFHELL, inf);
clif_skillinfo(sd,SR_TIGERCANNON, inf);
}
break;
}
}
void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int tick){
int duration = 0, delay=0; //Used to signal if this skill can be combo'ed later on.
struct status_change_entry *sce;
TBL_PC *sd = BL_CAST(BL_PC,src);
TBL_HOM *hd = BL_CAST(BL_HOM,src);
struct status_change *sc = status_get_sc(src);
if(sc == NULL) return;
//End previous combo state after skill is invoked
if ((sce = sc->data[SC_COMBO]) != NULL) {
switch (skill_id) {
case TK_TURNKICK:
case TK_STORMKICK:
case TK_DOWNKICK:
case TK_COUNTER:
if (sd && pc_famerank(sd->status.char_id,MAPID_TAEKWON)) {//Extend combo time.
sce->val1 = skill_id; //Update combo-skill
sce->val3 = skill_id;
if( sce->timer != INVALID_TIMER )
delete_timer(sce->timer, status_change_timer);
sce->timer = add_timer(tick+sce->val4, status_change_timer, src->id, SC_COMBO);
break;
}
unit_cancel_combo(src); // Cancel combo wait
break;
default:
if( src == dsrc ) // Ground skills are exceptions. [Inkfish]
status_change_end(src, SC_COMBO, INVALID_TIMER);
}
}
//start new combo
if(sd){ //player only
switch(skill_id) {
case MO_TRIPLEATTACK:
if (pc_checkskill(sd, MO_CHAINCOMBO) > 0 || pc_checkskill(sd, SR_DRAGONCOMBO) > 0)
duration=1;
break;
case MO_CHAINCOMBO:
if(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0)
duration=1;
break;
case MO_COMBOFINISH:
if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
party_skill_check(sd, sd->status.party_id, MO_COMBOFINISH, skill_lv);
if (pc_checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0)
duration=1;
case CH_TIGERFIST:
if (!duration && pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1)
duration=1;
case CH_CHAINCRUSH:
if (!duration && pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball > 0 && sd->sc.data[SC_EXPLOSIONSPIRITS])
duration=1;
break;
case AC_DOUBLE: {
unsigned char race = status_get_race(bl);
if( (race == RC_BRUTE || race == RC_INSECT) && pc_checkskill(sd, HT_POWER))
duration = 2000;
break;
}
case SR_DRAGONCOMBO:
if( pc_checkskill(sd, SR_FALLENEMPIRE) > 0 )
duration = 1;
break;
case SR_FALLENEMPIRE:
if( pc_checkskill(sd, SR_TIGERCANNON) > 0 || pc_checkskill(sd, SR_GATEOFHELL) > 0 )
duration = 1;
break;
}
}
else { //other
switch(skill_id) {
case MH_TINDER_BREAKER:
case MH_CBC:
case MH_SONIC_CRAW:
case MH_SILVERVEIN_RUSH:
if(hd->homunculus.spiritball > 0) duration = 2000;
delay=1;
break;
case MH_EQC:
case MH_MIDNIGHT_FRENZY:
if(hd->homunculus.spiritball >= 2) duration = 6000;
delay=1;
break;
}
}
if (duration) { //Possible to chain
if(sd) duration = DIFF_TICK(sd->ud.canact_tick, tick);
if (duration < 1) duration = 1;
sc_start4(src,src,SC_COMBO,100,skill_id,bl->id,delay,0,duration);
clif_combo_delay(src, duration);
}
}
/* /*
* ========================================================================= * =========================================================================
* Does a skill attack with the given properties. * Does a skill attack with the given properties.
@ -2405,76 +2487,27 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
//Skill hit type //Skill hit type
type=(skill_id==0)?5:skill_get_hit(skill_id); type=(skill_id==0)?5:skill_get_hit(skill_id);
if(damage < dmg.div_ switch(skill_id){
//Only skills that knockback even when they miss. [Skotlex] case SC_TRIANGLESHOT:
&& skill_id != CH_PALMSTRIKE) if(rnd()%100 > (1 + skill_lv) ) dmg.blewcount = 0;
dmg.blewcount = 0; break;
default:
if(skill_id == CR_GRANDCROSS||skill_id == NPC_GRANDDARKNESS) { if(damage < dmg.div_ && skill_lv != CH_PALMSTRIKE)
dmg.blewcount = 0; //only pushback when it hit
break;
}
switch(skill_id){
case CR_GRANDCROSS:
case NPC_GRANDDARKNESS:
if(battle_config.gx_disptype) dsrc = src; if(battle_config.gx_disptype) dsrc = src;
if(src == bl) type = 4; if(src == bl) type = 4;
else flag|=SD_ANIMATION; else flag|=SD_ANIMATION;
} break;
if(skill_id == NJ_TATAMIGAESHI) { case NJ_TATAMIGAESHI: //For correct knockback.
dsrc = src; //For correct knockback. dsrc = src;
flag|=SD_ANIMATION; flag|=SD_ANIMATION;
}
if(sd) {
int flag = 0; //Used to signal if this skill can be combo'ed later on.
struct status_change_entry *sce;
if ((sce = sd->sc.data[SC_COMBO])) {//End combo state after skill is invoked. [Skotlex]
switch (skill_id) {
case TK_TURNKICK:
case TK_STORMKICK:
case TK_DOWNKICK:
case TK_COUNTER:
if (pc_famerank(sd->status.char_id,MAPID_TAEKWON)) {//Extend combo time.
sce->val1 = skill_id; //Update combo-skill
sce->val3 = skill_id;
if( sce->timer != INVALID_TIMER )
delete_timer(sce->timer, status_change_timer);
sce->timer = add_timer(tick+sce->val4, status_change_timer, src->id, SC_COMBO);
break; break;
} case TK_COUNTER: { //bonus from SG_FRIEND [Komurka]
unit_cancel_combo(src); // Cancel combo wait
break;
default:
if( src == dsrc ) // Ground skills are exceptions. [Inkfish]
status_change_end(src, SC_COMBO, INVALID_TIMER);
}
}
switch(skill_id) {
case MO_TRIPLEATTACK:
if (pc_checkskill(sd, MO_CHAINCOMBO) > 0 || pc_checkskill(sd, SR_DRAGONCOMBO) > 0)
flag=1;
break;
case MO_CHAINCOMBO:
if(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0)
flag=1;
break;
case MO_COMBOFINISH:
if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
party_skill_check(sd, sd->status.party_id, MO_COMBOFINISH, skill_lv);
if (pc_checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0)
flag=1;
case CH_TIGERFIST:
if (!flag && pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1)
flag=1;
case CH_CHAINCRUSH:
if (!flag && pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball > 0 && sd->sc.data[SC_EXPLOSIONSPIRITS])
flag=1;
break;
case AC_DOUBLE:
if( (tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) && pc_checkskill(sd, HT_POWER))
{
//TODO: This code was taken from Triple Blows, is this even how it should be? [Skotlex]
sc_start2(src,src,SC_COMBO,100,HT_POWER,bl->id,2000);
clif_combo_delay(src,2000);
}
break;
case TK_COUNTER:
{ //bonus from SG_FRIEND [Komurka]
int level; int level;
if(sd->status.party_id>0 && (level = pc_checkskill(sd,SG_FRIEND))) if(sd->status.party_id>0 && (level = pc_checkskill(sd,SG_FRIEND)))
party_skill_check(sd, sd->status.party_id, TK_COUNTER,level); party_skill_check(sd, sd->status.party_id, TK_COUNTER,level);
@ -2489,23 +2522,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
//Can't attack nor use items until skill's delay expires. [Skotlex] //Can't attack nor use items until skill's delay expires. [Skotlex]
sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick; sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick;
break; break;
case SR_DRAGONCOMBO:
if( pc_checkskill(sd, SR_FALLENEMPIRE) > 0 )
flag = 1;
break;
case SR_FALLENEMPIRE:
if( pc_checkskill(sd, SR_TIGERCANNON) > 0 || pc_checkskill(sd, SR_GATEOFHELL) > 0 )
flag = 1;
break;
} //Switch End
if (flag) { //Possible to chain
flag = DIFF_TICK(sd->ud.canact_tick, tick);
if (flag < 1) flag = 1;
sc_start2(src,src,SC_COMBO,100,skill_id,bl->id,flag);
clif_combo_delay(src, flag);
}
} }
//combo handling
skill_combo(src,dsrc,bl,skill_id,skill_lv,tick);
//Display damage. //Display damage.
switch( skill_id ) switch( skill_id )
{ {
@ -2659,7 +2680,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if( tsd->reproduceskill_id && tsd->status.skill[tsd->reproduceskill_id].flag == SKILL_FLAG_PLAGIARIZED ) { if( tsd->reproduceskill_id && tsd->status.skill[tsd->reproduceskill_id].flag == SKILL_FLAG_PLAGIARIZED ) {
tsd->status.skill[tsd->reproduceskill_id].id = 0; tsd->status.skill[tsd->reproduceskill_id].id = 0;
tsd->status.skill[tsd->reproduceskill_id].lv = 0; tsd->status.skill[tsd->reproduceskill_id].lv = 0;
tsd->status.skill[tsd->reproduceskill_id].flag = 0; tsd->status.skill[tsd->reproduceskill_id].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(tsd,tsd->reproduceskill_id); clif_deleteskill(tsd,tsd->reproduceskill_id);
} }
@ -2676,7 +2697,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){ if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){
tsd->status.skill[tsd->cloneskill_id].id = 0; tsd->status.skill[tsd->cloneskill_id].id = 0;
tsd->status.skill[tsd->cloneskill_id].lv = 0; tsd->status.skill[tsd->cloneskill_id].lv = 0;
tsd->status.skill[tsd->cloneskill_id].flag = 0; tsd->status.skill[tsd->cloneskill_id].flag = SKILL_FLAG_PERMANENT;
clif_deleteskill(tsd,tsd->cloneskill_id); clif_deleteskill(tsd,tsd->cloneskill_id);
} }
@ -2712,12 +2733,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if( damage > 0 ) //Counter status effects [Skotlex] if( damage > 0 ) //Counter status effects [Skotlex]
skill_counter_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,tick); skill_counter_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,tick);
} }
// Hell Inferno burning status only starts if Fire part hits.
if( skill_id == WL_HELLINFERNO && dmg.damage > 0 )
sc_start4(src,bl,SC_BURNING,55+5*skill_lv,skill_lv,1000,src->id,0,skill_get_time(skill_id,skill_lv));
// Apply knock back chance in SC_TRIANGLESHOT skill.
else if( skill_id == SC_TRIANGLESHOT && rnd()%100 > (1 + skill_lv) )
dmg.blewcount = 0;
//Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex] //Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex]
//Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills) //Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills)
@ -4720,46 +4735,16 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case MH_STAHL_HORN: case MH_STAHL_HORN:
case MH_NEEDLE_OF_PARALYZE: case MH_NEEDLE_OF_PARALYZE:
skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
break;
case MH_SONIC_CRAW: case MH_SONIC_CRAW:
case MH_TINDER_BREAKER:
case MH_MIDNIGHT_FRENZY:
case MH_SILVERVEIN_RUSH:
case MH_CBC:
case MH_EQC: {
TBL_HOM *hd = BL_CAST(BL_HOM,src);
int8 k=0;
int duration=0;
struct status_change_entry *sce;
struct block_list *tbl = NULL; //target
if(!hd){
clif_colormes(sd,COLOR_RED,"Only homon are support this skill atm, can't used it by other");
map_freeblock_unlock();
return 1;
}
if(hd->sc.count && (sce=hd->sc.data[SC_STYLE_CHANGE])){
//val1 = mode
if(!sce->val2) sce->val2 = bl->id; //memo target (only sonic slaw and tinder should)
tbl = map_id2bl(sce->val2);
sce->val3 = skill_id;
sce->val4 = gettick();
}
switch(skill_id){
case MH_SONIC_CRAW: {
int nb_sphere = hd->homunculus.spiritball;
for(k=0; k<=nb_sphere; k++){ //attack for each sphere active
skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
}
// hom_delspiritball(hd, nb_sphere, 0); //remove them all if we remove can't coninue combo
break; break;
}
case MH_SILVERVEIN_RUSH:
case MH_MIDNIGHT_FRENZY: case MH_MIDNIGHT_FRENZY:
case MH_SILVERVEIN_RUSH:{
TBL_HOM *hd = BL_CAST(BL_HOM,src);
hom_delspiritball(hd,skill_id==MH_SILVERVEIN_RUSH?1:2,0); hom_delspiritball(hd,skill_id==MH_SILVERVEIN_RUSH?1:2,0);
skill_attack(skill_get_type(skill_id),src,src,tbl,skill_id,skill_lv,tick,flag); skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
break; break;
}
case MH_TINDER_BREAKER: case MH_TINDER_BREAKER:
if (unit_movepos(src, bl->x, bl->y, 1, 1)) { if (unit_movepos(src, bl->x, bl->y, 1, 1)) {
#if PACKETVER >= 20111005 #if PACKETVER >= 20111005
@ -4767,20 +4752,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
#else #else
clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick); clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick);
#endif #endif
} }
case MH_CBC: case MH_CBC:
case MH_EQC: case MH_EQC: {
int duration=0;
TBL_HOM *hd = BL_CAST(BL_HOM,src);
duration = max(skill_lv,(status_get_str(src)/7 - status_get_str(bl)/10))*1000; //Yommy formula duration = max(skill_lv,(status_get_str(src)/7 - status_get_str(bl)/10))*1000; //Yommy formula
hom_delspiritball(hd,skill_id==MH_EQC?2:1,0); //only EQC consume 2 in grp 2 hom_delspiritball(hd,skill_id==MH_EQC?2:1,0); //only EQC consume 2 in grp 2
if(skill_id==MH_TINDER_BREAKER) skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag);
sc_start2(src,src,status_skill2sc(skill_id),100,skill_lv,bl->id,duration); clif_skill_nodamage(src,bl,skill_id,skill_lv,
else sc_start4(src,bl,status_skill2sc(skill_id),100,skill_lv,src->id,0,0,duration));
sc_start(src,bl,status_skill2sc(skill_id),100,skill_lv,duration);
skill_attack(skill_get_type(skill_id),src,src,tbl,skill_id,skill_lv,tick,flag);
break;
}
break; break;
} }
case 0:/* no skill - basic/normal attack */ case 0:/* no skill - basic/normal attack */
if(sd) { if(sd) {
if (flag & 3){ if (flag & 3){
@ -9219,8 +9205,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv));
break; break;
case MH_SUMMON_LEGION: case MH_SUMMON_LEGION: {
{
int summons[5] = {2158, 2159, 2159, 2160, 2160}; int summons[5] = {2158, 2159, 2159, 2160, 2160};
int qty[5] = {3 , 3 , 4 , 4 , 5}; int qty[5] = {3 , 3 , 4 , 4 , 5};
struct mob_data *sum_md; struct mob_data *sum_md;

View File

@ -1899,4 +1899,7 @@ int skill_elementalanalysis(struct map_session_data *sd, int n, uint16 skill_lv,
int skill_changematerial(struct map_session_data *sd, int n, unsigned short *item_list); // Genetic Change Material. int skill_changematerial(struct map_session_data *sd, int n, unsigned short *item_list); // Genetic Change Material.
int skill_get_elemental_type(uint16 skill_id, uint16 skill_lv); int skill_get_elemental_type(uint16 skill_id, uint16 skill_lv);
void skill_combo_toogle_inf(struct block_list* bl, uint16 skill_id, int inf);
void skill_combo(struct block_list* src,struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int tick);
#endif /* _SKILL_H_ */ #endif /* _SKILL_H_ */

View File

@ -508,7 +508,8 @@ void initChangeTables(void) {
set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD);
add_sc(MH_STYLE_CHANGE, SC_STYLE_CHANGE); add_sc(MH_STYLE_CHANGE, SC_STYLE_CHANGE);
set_sc(MH_TINDER_BREAKER, SC_TINDER_BREAKER, SI_TINDER_BREAKER, SCB_FLEE); set_sc(MH_TINDER_BREAKER, SC_TINDER_BREAKER2, SI_TINDER_BREAKER, SCB_FLEE);
set_sc(MH_TINDER_BREAKER, SC_TINDER_BREAKER, SI_TINDER_BREAKER_POSTDELAY, SCB_FLEE);
set_sc(MH_CBC, SC_CBC, SI_CBC, SCB_FLEE); set_sc(MH_CBC, SC_CBC, SI_CBC, SCB_FLEE);
set_sc(MH_EQC, SC_EQC, SI_EQC, SCB_DEF2|SCB_BATK|SCB_MAXHP); set_sc(MH_EQC, SC_EQC, SI_EQC, SCB_DEF2|SCB_BATK|SCB_MAXHP);
@ -1006,6 +1007,8 @@ void initChangeTables(void) {
StatusChangeStateTable[SC_STOP] |= SCS_NOMOVE; StatusChangeStateTable[SC_STOP] |= SCS_NOMOVE;
StatusChangeStateTable[SC_CLOSECONFINE] |= SCS_NOMOVE; StatusChangeStateTable[SC_CLOSECONFINE] |= SCS_NOMOVE;
StatusChangeStateTable[SC_CLOSECONFINE2] |= SCS_NOMOVE; StatusChangeStateTable[SC_CLOSECONFINE2] |= SCS_NOMOVE;
StatusChangeStateTable[SC_TINDER_BREAKER] |= SCS_NOMOVE;
StatusChangeStateTable[SC_TINDER_BREAKER2] |= SCS_NOMOVE;
StatusChangeStateTable[SC_MADNESSCANCEL] |= SCS_NOMOVE; StatusChangeStateTable[SC_MADNESSCANCEL] |= SCS_NOMOVE;
StatusChangeStateTable[SC_GRAVITATION] |= SCS_NOMOVE|SCS_NOMOVECOND; StatusChangeStateTable[SC_GRAVITATION] |= SCS_NOMOVE|SCS_NOMOVECOND;
StatusChangeStateTable[SC_WHITEIMPRISON] |= SCS_NOMOVE; StatusChangeStateTable[SC_WHITEIMPRISON] |= SCS_NOMOVE;
@ -4813,6 +4816,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
if(!sc || !sc->count) if(!sc || !sc->count)
return cap_value(flee,1,SHRT_MAX); return cap_value(flee,1,SHRT_MAX);
if(sc->data[SC_TINDER_BREAKER] || sc->data[SC_TINDER_BREAKER2])
return 0; //0 flee
if(sc->data[SC_INCFLEE]) if(sc->data[SC_INCFLEE])
flee += sc->data[SC_INCFLEE]->val1; flee += sc->data[SC_INCFLEE]->val1;
@ -7210,6 +7215,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_BLEEDING: case SC_BLEEDING:
case SC_DPOISON: case SC_DPOISON:
case SC_CLOSECONFINE2: //Can't be re-closed in. case SC_CLOSECONFINE2: //Can't be re-closed in.
case SC_TINDER_BREAKER2:
case SC_MARIONETTE: case SC_MARIONETTE:
case SC_MARIONETTE2: case SC_MARIONETTE2:
case SC_NOCHAT: case SC_NOCHAT:
@ -7834,18 +7840,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
status_zap(bl, status->hp-1, val2?0:status->sp); status_zap(bl, status->hp-1, val2?0:status->sp);
return 1; return 1;
break; break;
case SC_TINDER_BREAKER2:
case SC_CLOSECONFINE2: case SC_CLOSECONFINE2:
{ {
struct block_list *src = val2?map_id2bl(val2):NULL; struct block_list *src = val2?map_id2bl(val2):NULL;
struct status_change *sc2 = src?status_get_sc(src):NULL; struct status_change *sc2 = src?status_get_sc(src):NULL;
struct status_change_entry *sce2 = sc2?sc2->data[SC_CLOSECONFINE]:NULL; int type2 = ((type == SC_TINDER_BREAKER2)?SC_TINDER_BREAKER:SC_CLOSECONFINE);
struct status_change_entry *sce2 = sc2?sc2->data[type2]:NULL;
if (src && sc2) { if (src && sc2) {
if (!sce2) //Start lock on caster. if (!sce2) //Start lock on caster.
sc_start4(src,src,SC_CLOSECONFINE,100,val1,1,0,0,tick+1000); sc_start4(src,src,type2,100,val1,1,0,0,tick+1000);
else { //Increase count of locked enemies and refresh time. else { //Increase count of locked enemies and refresh time.
(sce2->val2)++; (sce2->val2)++;
delete_timer(sce2->timer, status_change_timer); delete_timer(sce2->timer, status_change_timer);
sce2->timer = add_timer(gettick()+tick+1000, status_change_timer, src->id, SC_CLOSECONFINE); sce2->timer = add_timer(gettick()+tick+1000, status_change_timer, src->id, type2);
} }
} else //Status failed. } else //Status failed.
return 0; return 0;
@ -8723,8 +8732,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
if(sc->data[SC_PARALYSIS]) if(sc->data[SC_PARALYSIS])
sc_start(src,bl, SC_ENDURE, 100, val1, tick); //start endure for same duration sc_start(src,bl, SC_ENDURE, 100, val1, tick); //start endure for same duration
break; break;
case SC_STYLE_CHANGE: //[Lighta] need real info case SC_STYLE_CHANGE:
tick = -1; tick = -1; //infinite duration
break; break;
case SC_CBC: case SC_CBC:
val3 = 10; //drain sp % dmg val3 = 10; //drain sp % dmg
@ -8788,6 +8797,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_CONFUSION: case SC_CONFUSION:
case SC_CLOSECONFINE: case SC_CLOSECONFINE:
case SC_CLOSECONFINE2: case SC_CLOSECONFINE2:
case SC_TINDER_BREAKER:
case SC_TINDER_BREAKER2:
case SC_SPIDERWEB: case SC_SPIDERWEB:
case SC_ELECTRICSHOCKER: case SC_ELECTRICSHOCKER:
case SC_BITE: case SC_BITE:
@ -9064,7 +9075,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
} }
break; break;
case SC_COMBO: case SC_COMBO:
switch (sce->val1) { switch(sce->val1){
case TK_STORMKICK: case TK_STORMKICK:
clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1); clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
break; break;
@ -9077,37 +9088,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case TK_COUNTER: case TK_COUNTER:
clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
break; break;
case MO_COMBOFINISH: default: //rest just toogle inf to enable autotarget
case CH_TIGERFIST: skill_combo_toogle_inf(bl,sce->val1,INF_SELF_SKILL);
case CH_CHAINCRUSH:
if (sd)
clif_skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL);
break;
case TK_JUMPKICK:
if (sd)
clif_skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL);
break;
case MO_TRIPLEATTACK:
if (sd && pc_checkskill(sd, SR_DRAGONCOMBO) > 0)
clif_skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL);
break;
case SR_FALLENEMPIRE:
if (sd){
clif_skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL);
clif_skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL);
}
break; break;
} }
break; break;
case SC_RAISINGDRAGON: case SC_RAISINGDRAGON:
sce->val2 = status->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] sce->val2 = status->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie]
break; break;
case SC_TINDER_BREAKER:
sc_start2(src, map_id2bl(val2),SC_CLOSECONFINE2,100,val1,bl->id,tick);
break;
case SC_EQC: case SC_EQC:
sc_start2(src, bl,SC_STUN,100,val1,bl->id,(1000*status_get_lv(src))/50+500*val1); sc_start2(src, bl,SC_STUN,100,val1,bl->id,(1000*status_get_lv(src))/50+500*val1);
status_change_end(bl,SC_TINDER_BREAKER,INVALID_TIMER); status_change_end(bl,SC_TINDER_BREAKER2,INVALID_TIMER);
break; break;
} }
@ -9480,18 +9471,19 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL ); skill_castend_damage_id(src, bl, sce->val2, sce->val1, gettick(), SD_LEVEL );
} }
break; break;
case SC_TINDER_BREAKER: case SC_TINDER_BREAKER2:
case SC_CLOSECONFINE2: case SC_CLOSECONFINE2:{
{
struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL; struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL;
struct status_change *sc2 = src?status_get_sc(src):NULL; struct status_change *sc2 = src?status_get_sc(src):NULL;
if (src && sc2 && sc2->data[SC_CLOSECONFINE]) { int type2 = ((type==SC_CLOSECONFINE2)?SC_CLOSECONFINE:SC_TINDER_BREAKER);
if (src && sc2 && sc2->data[type2]) {
//If status was already ended, do nothing. //If status was already ended, do nothing.
//Decrease count //Decrease count
if (--(sc2->data[SC_CLOSECONFINE]->val1) <= 0) //No more holds, free him up. if (type==SC_TINDER_BREAKER2 || (--(sc2->data[type2]->val1) <= 0)) //No more holds, free him up.
status_change_end(src, SC_CLOSECONFINE, INVALID_TIMER); status_change_end(src, type2, INVALID_TIMER);
} }
} }
case SC_TINDER_BREAKER:
case SC_CLOSECONFINE: case SC_CLOSECONFINE:
if (sce->val2 > 0) { if (sce->val2 > 0) {
//Caster has been unlocked... nearby chars need to be unlocked. //Caster has been unlocked... nearby chars need to be unlocked.
@ -9503,27 +9495,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
} }
break; break;
case SC_COMBO: case SC_COMBO:
if( sd ) skill_combo_toogle_inf(bl,sce->val1,0);
switch (sce->val1) {
case MO_COMBOFINISH:
case CH_TIGERFIST:
case CH_CHAINCRUSH:
clif_skillinfo(sd, MO_EXTREMITYFIST, 0);
break; break;
case TK_JUMPKICK:
clif_skillinfo(sd, TK_JUMPKICK, 0);
break;
case MO_TRIPLEATTACK:
if (pc_checkskill(sd, SR_DRAGONCOMBO) > 0)
clif_skillinfo(sd, SR_DRAGONCOMBO, 0);
break;
case SR_FALLENEMPIRE:
clif_skillinfo(sd, SR_GATEOFHELL, 0);
clif_skillinfo(sd, SR_TIGERCANNON, 0);
break;
}
break;
case SC_MARIONETTE: case SC_MARIONETTE:
case SC_MARIONETTE2: /// Marionette target case SC_MARIONETTE2: /// Marionette target
if (sce->val1) if (sce->val1)
@ -10834,13 +10807,16 @@ int status_change_timer_sub(struct block_list* bl, va_list ap)
} }
} }
break; break;
case SC_CLOSECONFINE: case SC_TINDER_BREAKER:
case SC_CLOSECONFINE:{
int type2 = ((type==SC_CLOSECONFINE)?SC_CLOSECONFINE2:SC_TINDER_BREAKER2);
//Lock char has released the hold on everyone... //Lock char has released the hold on everyone...
if (tsc && tsc->data[SC_CLOSECONFINE2] && tsc->data[SC_CLOSECONFINE2]->val2 == src->id) { if (tsc && tsc->data[type2] && tsc->data[type2]->val2 == src->id) {
tsc->data[SC_CLOSECONFINE2]->val2 = 0; tsc->data[type2]->val2 = 0;
status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); status_change_end(bl, type2, INVALID_TIMER);
} }
break; break;
}
case SC_CURSEDCIRCLE_TARGET: case SC_CURSEDCIRCLE_TARGET:
if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) {
clif_bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0); clif_bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0);

View File

@ -1022,7 +1022,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
struct map_session_data *sd = NULL; struct map_session_data *sd = NULL;
struct block_list * target = NULL; struct block_list * target = NULL;
unsigned int tick = gettick(); unsigned int tick = gettick();
int temp = 0, range; int combo = 0, range;
nullpo_ret(src); nullpo_ret(src);
if(status_isdead(src)) if(status_isdead(src))
@ -1046,14 +1046,14 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
if( skill_get_inf(skill_id)&INF_SELF_SKILL && skill_get_nk(skill_id)&NK_NO_DAMAGE )// exploit fix if( skill_get_inf(skill_id)&INF_SELF_SKILL && skill_get_nk(skill_id)&NK_NO_DAMAGE )// exploit fix
target_id = src->id; target_id = src->id;
temp = 1; combo = 1;
} else } else
if ( target_id == src->id && if ( target_id == src->id &&
skill_get_inf(skill_id)&INF_SELF_SKILL && skill_get_inf(skill_id)&INF_SELF_SKILL &&
skill_get_inf2(skill_id)&INF2_NO_TARGET_SELF ) skill_get_inf2(skill_id)&INF2_NO_TARGET_SELF )
{ {
target_id = ud->target; //Auto-select target. [Skotlex] target_id = ud->target; //Auto-select target. [Skotlex]
temp = 1; combo = 1;
} }
if (sd) { if (sd) {
@ -1083,7 +1083,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
if (target) if (target)
target_id = target->id; target_id = target->id;
} }
if (src->type==BL_HOM) else if (src->type==BL_HOM)
switch(skill_id) switch(skill_id)
{ //Homun-auto-target skills. { //Homun-auto-target skills.
case HLIF_HEAL: case HLIF_HEAL:
@ -1093,6 +1093,16 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
target = battle_get_master(src); target = battle_get_master(src);
if (!target) return 0; if (!target) return 0;
target_id = target->id; target_id = target->id;
break;
case MH_SONIC_CRAW:
case MH_TINDER_BREAKER: {
int skill_id2 = ((skill_id==MH_SONIC_CRAW)?MH_MIDNIGHT_FRENZY:MH_EQC);
if(sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == skill_id2){ //it,s a combo
target_id = sc->data[SC_COMBO]->val2;
combo = 1;
}
break;
}
} }
if( !target ) // choose default target if( !target ) // choose default target
@ -1166,7 +1176,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
//Check range when not using skill on yourself or is a combo-skill during attack //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) //(these are supposed to always have the same range as your attack)
if( src->id != target_id && (!temp || ud->attacktimer == INVALID_TIMER) ) { if( src->id != target_id && (!combo || ud->attacktimer == INVALID_TIMER) ) {
if( skill_get_state(ud->skill_id) == ST_MOVE_ENABLE ) { if( skill_get_state(ud->skill_id) == ST_MOVE_ENABLE ) {
if( !unit_can_reach_bl(src, target, range + 1, 1, NULL, NULL) ) if( !unit_can_reach_bl(src, target, range + 1, 1, NULL, NULL) )
return 0; // Walk-path check failed. return 0; // Walk-path check failed.
@ -1178,7 +1188,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
} }
} }
if (!temp) //Stop attack on non-combo skills [Skotlex] if (!combo) //Stop attack on non-combo skills [Skotlex]
unit_stop_attack(src); unit_stop_attack(src);
else if(ud->attacktimer != INVALID_TIMER) //Elsewise, delay current attack sequence else if(ud->attacktimer != INVALID_TIMER) //Elsewise, delay current attack sequence
ud->attackabletime = tick + status_get_adelay(src); ud->attackabletime = tick + status_get_adelay(src);
@ -1186,12 +1196,12 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
ud->state.skillcastcancel = castcancel; ud->state.skillcastcancel = castcancel;
//temp: Used to signal force cast now. //temp: Used to signal force cast now.
temp = 0; combo = 0;
switch(skill_id){ switch(skill_id){
case ALL_RESURRECTION: case ALL_RESURRECTION:
if(battle_check_undead(tstatus->race,tstatus->def_ele)) { if(battle_check_undead(tstatus->race,tstatus->def_ele)) {
temp = 1; combo = 1;
} else if (!status_isdead(target)) } else if (!status_isdead(target))
return 0; //Can't cast on non-dead characters. return 0; //Can't cast on non-dead characters.
break; break;
@ -1205,17 +1215,17 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
sc->data[SC_COMBO]->val1 == CH_TIGERFIST || sc->data[SC_COMBO]->val1 == CH_TIGERFIST ||
sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH)) sc->data[SC_COMBO]->val1 == CH_CHAINCRUSH))
casttime = -1; casttime = -1;
temp = 1; combo = 1;
break; break;
case SR_GATEOFHELL: case SR_GATEOFHELL:
case SR_TIGERCANNON: case SR_TIGERCANNON:
if (sc && sc->data[SC_COMBO] && if (sc && sc->data[SC_COMBO] &&
sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE)
casttime = -1; casttime = -1;
temp = 1; combo = 1;
break; break;
case SA_SPELLBREAKER: case SA_SPELLBREAKER:
temp = 1; combo = 1;
break; break;
case ST_CHASEWALK: case ST_CHASEWALK:
if (sc && sc->data[SC_CHASEWALK]) if (sc && sc->data[SC_CHASEWALK])
@ -1279,7 +1289,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
unit_stop_walking(src,1);// eventhough this is not how official works but this will do the trick. bugreport:6829 unit_stop_walking(src,1);// eventhough this is not how official works but this will do the trick. bugreport:6829
// in official this is triggered even if no cast time. // in official this is triggered even if no cast time.
clif_skillcasting(src, src->id, target_id, 0,0, skill_id, skill_get_ele(skill_id, skill_lv), casttime); clif_skillcasting(src, src->id, target_id, 0,0, skill_id, skill_get_ele(skill_id, skill_lv), casttime);
if( casttime > 0 || temp ) if( casttime > 0 || combo )
{ {
if (sd && target->type == BL_MOB) if (sd && target->type == BL_MOB)
{ {
@ -2034,6 +2044,8 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
status_change_end(bl, SC_MARIONETTE2, INVALID_TIMER); status_change_end(bl, SC_MARIONETTE2, INVALID_TIMER);
status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER);
status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER);
status_change_end(bl, SC_TINDER_BREAKER, INVALID_TIMER);
status_change_end(bl, SC_TINDER_BREAKER2, INVALID_TIMER);
status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_HIDING, INVALID_TIMER);
// Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later
if ( bl->type != BL_PC ) if ( bl->type != BL_PC )