From 7bc683e21e77b8e91a5e43d6c8400c90fdc99e7d Mon Sep 17 00:00:00 2001 From: glighta Date: Thu, 4 Apr 2013 00:18:59 +0000 Subject: [PATCH] -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 --- db/re/skill_db.txt | 4 +- src/common/mmo.h | 1 + src/map/atcommand.c | 4 +- src/map/battle.c | 25 +- src/map/chrif.c | 240 ++++++++--------- src/map/clif.c | 134 +++++----- src/map/clif.h | 3 +- src/map/guild.c | 109 ++++---- src/map/map.c | 2 + src/map/mob.c | 11 +- src/map/pc.c | 24 +- src/map/skill.c | 635 +++++++++++++++++++++----------------------- src/map/skill.h | 3 + src/map/status.c | 272 +++++++++---------- src/map/unit.c | 38 ++- 15 files changed, 748 insertions(+), 757 deletions(-) diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index 0e2e170fb6..b571318a9a 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -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 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 -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 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 @@ -1136,7 +1136,7 @@ 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 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 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 diff --git a/src/common/mmo.h b/src/common/mmo.h index 8b3d89b571..6c0adae95e 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -217,6 +217,7 @@ enum e_skill_flag SKILL_FLAG_PLAGIARIZED, 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_TMP_COMBO, //@FIXME for homon combo atm //... }; diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 5788b91700..ad3e3ab47b 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -3159,7 +3159,7 @@ ACMD_FUNC(lostskill) } 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_displaymessage(fd, msg_txt(71)); // You have forgotten the skill. @@ -8707,7 +8707,7 @@ ACMD_FUNC(cart) { #define MC_CART_MDFY(x) \ sd->status.skill[MC_PUSHCART].id = x?MC_PUSHCART: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); bool need_skill = pc_checkskill(sd, MC_PUSHCART) ? false : true; diff --git a/src/map/battle.c b/src/map/battle.c index 74ab997c1c..9c59c71cc4 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1131,9 +1131,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) pc_addspiritball(sd,skill_get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); if (sc->data[SC_STYLE_CHANGE]) { - TBL_HOM *hd = BL_CAST(BL_HOM,bl); //when being hit - if (hd && (rnd()%100<(status_get_lv(bl)/2)) ) hom_addspiritball(hd, 10); //add a sphere - } + TBL_HOM *hd = BL_CAST(BL_HOM,bl); //when being hit + if (hd && (rnd()%100<(status_get_lv(bl)/2)) ) hom_addspiritball(hd, 10); //add a sphere + } if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) status_change_spread(bl, src); // Deadly infect attacked side @@ -1193,10 +1193,10 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag sc_start(src,bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON, 1)); if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) status_change_spread(src, bl); - if (sc->data[SC_STYLE_CHANGE]) { - TBL_HOM *hd = BL_CAST(BL_HOM,src); //when attacking - if (hd && (rnd()%100<(20+status_get_lv(bl)/5)) ) hom_addspiritball(hd, 10); - } + if (sc->data[SC_STYLE_CHANGE]) { + TBL_HOM *hd = BL_CAST(BL_HOM,src); //when attacking + if (hd && (rnd()%100<(20+status_get_lv(bl)/5)) ) hom_addspiritball(hd, 10); + } } if (battle_config.pk_mode && sd && bl->type == BL_PC && damage && map[bl->m].flag.pvp) @@ -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); switch(skill_id) { + case MH_SONIC_CRAW:{ + TBL_HOM *hd = BL_CAST(BL_HOM,src); + wd.div_ = hd->homunculus.spiritball; + } + break; case MO_FINGEROFFENSIVE: if(sd) { if (battle_config.finger_offensive_type) @@ -3124,9 +3129,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo } } if(sc->data[SC_STYLE_CHANGE]){ - TBL_HOM *hd = BL_CAST(BL_HOM,src); - if (hd) ATK_ADD(hd->homunculus.spiritball * 3); - } + TBL_HOM *hd = BL_CAST(BL_HOM,src); + if (hd) ATK_ADD(hd->homunculus.spiritball * 3); + } } switch (skill_id) { diff --git a/src/map/chrif.c b/src/map/chrif.c index b87931d44c..0f03741808 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -139,28 +139,28 @@ struct auth_node* chrif_search(int account_id) { struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state) { struct auth_node *node = chrif_search(account_id); - + return ( node && node->char_id == char_id && node->state == state ) ? node : NULL; } bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { struct auth_node *node; - + if ( (node = chrif_auth_check(account_id, char_id, state) ) ) { int fd = node->sd ? node->sd->fd : node->fd; - + if ( session[fd] && session[fd]->session_data == node->sd ) session[fd]->session_data = NULL; - + if ( node->char_dat ) aFree(node->char_dat); - + if ( node->sd ) aFree(node->sd); - + ers_free(auth_db_ers, node); idb_remove(auth_db,account_id); - + return true; } return false; @@ -169,14 +169,14 @@ bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { //Moves the sd character to the auth_db structure. static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) { struct auth_node *node; - + if ( chrif_search(sd->status.account_id) ) return false; //Already exists? node = ers_alloc(auth_db_ers, struct auth_node); - + memset(node, 0, sizeof(struct auth_node)); - + node->account_id = sd->status.account_id; node->char_id = sd->status.char_id; node->login_id1 = sd->login_id1; @@ -188,33 +188,33 @@ static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) { node->state = state; sd->state.active = 0; - + idb_put(auth_db, node->account_id, node); - + return true; } static bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) { - + if(sd->fd && state == ST_LOGOUT) { //Disassociate player, and free it after saving ack returns. [Skotlex] //fd info must not be lost for ST_MAPCHANGE as a final packet needs to be sent to the player. if ( session[sd->fd] ) session[sd->fd]->session_data = NULL; sd->fd = 0; } - + return chrif_sd_to_auth(sd, state); } bool chrif_auth_finished(TBL_PC* sd) { struct auth_node *node= chrif_search(sd->status.account_id); - + if ( node && node->sd == sd && node->state == ST_LOGIN ) { node->sd = NULL; - + return chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); } - + return false; } // sets char-server's user id @@ -239,17 +239,17 @@ void chrif_checkdefaultlogin(void) { // sets char-server's ip address int chrif_setip(const char* ip) { char ip_str[16]; - + if ( !( char_ip = host2ip(ip) ) ) { ShowWarning("Failed to Resolve Char Server Address! (%s)\n", ip); - + return 0; } - + safestrncpy(char_ip_str, ip, sizeof(char_ip_str)); - + ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(char_ip, ip_str)); - + return 1; } @@ -290,7 +290,7 @@ int chrif_save(struct map_session_data *sd, int flag) { if (flag) sd->state.storage_flag = 0; //Force close it. - //Saving of registry values. + //Saving of registry values. if (sd->state.reg_dirty&4) intif_saveregistry(sd, 3); //Save char regs if (sd->state.reg_dirty&2) @@ -314,7 +314,7 @@ int chrif_save(struct map_session_data *sd, int flag) { if( sd->md && mercenary_get_lifetime(sd->md) > 0 ) mercenary_save(sd->md); if( sd->ed && elemental_get_lifetime(sd->ed) > 0 ) - elemental_save(sd->ed); + elemental_save(sd->ed); if( sd->save_quest ) intif_quest_save(sd); @@ -339,9 +339,9 @@ int chrif_connect(int fd) { // sends maps to char-server int chrif_sendmap(int fd) { int i; - + ShowStatus("Sending maps to char server...\n"); - + // Sending normal maps, not instances WFIFOHEAD(fd, 4 + instance_start * 4); WFIFOW(fd,0) = 0x2afa; @@ -362,12 +362,12 @@ int chrif_recvmap(int fd) { for(i = 10, j = 0; i < RFIFOW(fd,2); i += 4, j++) { map_setipport(RFIFOW(fd,i), ip, port); } - + if (battle_config.etc_log) ShowStatus("Received maps from %d.%d.%d.%d:%d (%d maps)\n", CONVIP(ip), port, j); other_mapserver_count++; - + return 0; } @@ -381,10 +381,10 @@ int chrif_removemap(int fd) { map_eraseipport(RFIFOW(fd, i), ip, port); other_mapserver_count--; - + if(battle_config.etc_log) ShowStatus("remove map of server %d.%d.%d.%d:%d (%d maps)\n", CONVIP(ip), port, j); - + return 0; } @@ -420,7 +420,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { WFIFOL(char_fd,31) = htonl(session[sd->fd]->client_addr); WFIFOL(char_fd,35) = sd->group_id; WFIFOSET(char_fd,39); - + return 0; } @@ -428,7 +428,7 @@ int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { /// R 2b06 .L .L .L .L .W .W .W .L .W int chrif_changemapserverack(int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port) { struct auth_node *node; - + if ( !( node = chrif_auth_check(account_id, char_id, ST_MAPCHANGE) ) ) return -1; @@ -476,7 +476,7 @@ int chrif_connectack(int fd) { */ static int chrif_reconnect(DBKey key, DBData *data, va_list ap) { struct auth_node *node = db_data2ptr(data); - + switch (node->state) { case ST_LOGIN: if ( node->sd && node->char_dat == NULL ) {//Since there is no way to request the char auth, make it fail. @@ -493,16 +493,16 @@ static int chrif_reconnect(DBKey key, DBData *data, va_list ap) { struct map_session_data *sd = node->sd; uint32 ip; uint16 port; - + if( map_mapname2ipport(sd->mapindex,&ip,&port) == 0 ) chrif_changemapserver(sd, ip, port); else //too much lag/timeout is the closest explanation for this error. clif_authfail_fd(sd->fd, 3); - + break; } } - + return 0; } @@ -510,9 +510,9 @@ static int chrif_reconnect(DBKey key, DBData *data, va_list ap) { /// Called when all the connection steps are completed. void chrif_on_ready(void) { ShowStatus("Map Server is now online.\n"); - + chrif_state = 2; - + chrif_check_shutdown(); //If there are players online, send them to the char-server. [Skotlex] @@ -533,16 +533,16 @@ void chrif_on_ready(void) { * *------------------------------------------*/ int chrif_sendmapack(int fd) { - + if (RFIFOB(fd,2)) { ShowFatalError("chrif : send map list to char server failed %d\n", RFIFOB(fd,2)); exit(EXIT_FAILURE); } memcpy(wisp_server_name, RFIFOP(fd,3), NAME_LENGTH); - + chrif_on_ready(); - + return 0; } @@ -550,7 +550,7 @@ int chrif_sendmapack(int fd) { * Request sc_data from charserver [Skotlex] *------------------------------------------*/ int chrif_scdata_request(int account_id, int char_id) { - + #ifdef ENABLE_SC_SAVING chrif_check(-1); @@ -560,7 +560,7 @@ int chrif_scdata_request(int account_id, int char_id) { WFIFOL(char_fd,6) = char_id; WFIFOSET(char_fd,10); #endif - + return 0; } @@ -617,7 +617,7 @@ void chrif_authok(int fd) { //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. if ( ( sd = map_id2sd(account_id) ) != NULL ) return; - + if ( ( node = chrif_search(account_id) ) == NULL ) return; // should not happen @@ -646,7 +646,7 @@ void chrif_authok(int fd) { } else { //Auth Failed pc_authfail(sd); } - + chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. chrif_auth_delete(account_id, char_id, ST_LOGIN); } @@ -664,7 +664,7 @@ void chrif_authfail(int fd) {/* HELLO WORLD. ip in RFIFOL 15 is not being used ( sex = RFIFOB(fd,14); node = chrif_search(account_id); - + if( node != NULL && node->account_id == account_id && node->char_id == char_id && @@ -685,7 +685,7 @@ void chrif_authfail(int fd) {/* HELLO WORLD. ip in RFIFOL 15 is not being used ( int auth_db_cleanup_sub(DBKey key, DBData *data, va_list ap) { struct auth_node *node = db_data2ptr(data); const char* states[] = { "Login", "Logout", "Map change" }; - + if(DIFF_TICK(gettick(),node->node_created)>60000) { switch (node->state) { case ST_LOGOUT: @@ -719,7 +719,7 @@ int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip) { if( !sd || !sd->bl.id || !sd->login_id1 ) return -1; - + chrif_check(-1); WFIFOHEAD(char_fd,18); @@ -737,10 +737,10 @@ int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip) { * Search Char trough id on char serv *------------------------------------------*/ int chrif_searchcharid(int char_id) { - + if( !char_id ) return -1; - + chrif_check(-1); WFIFOHEAD(char_fd,6); @@ -755,7 +755,7 @@ int chrif_searchcharid(int char_id) { * Change Email *------------------------------------------*/ int chrif_changeemail(int id, const char *actual_email, const char *new_email) { - + if (battle_config.etc_log) ShowInfo("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", id, actual_email, new_email); @@ -778,7 +778,7 @@ int chrif_changeemail(int id, const char *actual_email, const char *new_email) { * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5) *------------------------------------------*/ int chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second) { - + chrif_check(-1); WFIFOHEAD(char_fd,44); @@ -786,7 +786,7 @@ int chrif_char_ask_name(int acc, const char* character_name, unsigned short oper WFIFOL(char_fd,2) = acc; safestrncpy((char*)WFIFOP(char_fd,6), character_name, NAME_LENGTH); WFIFOW(char_fd,30) = operation_type; - + if ( operation_type == 2 ) { WFIFOW(char_fd,32) = year; WFIFOW(char_fd,34) = month; @@ -795,14 +795,14 @@ int chrif_char_ask_name(int acc, const char* character_name, unsigned short oper WFIFOW(char_fd,40) = minute; WFIFOW(char_fd,42) = second; } - + WFIFOSET(char_fd,44); return 0; } int chrif_changesex(struct map_session_data *sd) { chrif_check(-1); - + WFIFOHEAD(char_fd,44); WFIFOW(char_fd,0) = 0x2b0e; WFIFOL(char_fd,2) = sd->status.account_id; @@ -834,9 +834,9 @@ static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 struct map_session_data* sd; char action[25]; char output[256]; - + sd = map_id2sd(acc); - + if( acc < 0 || sd == NULL ) { ShowError("chrif_char_ask_name_answer failed - player not online.\n"); return; @@ -854,7 +854,7 @@ static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 case 3 : sprintf(output, msg_txt(427), action, NAME_LENGTH, player_name); break; default: output[0] = '\0'; break; } - + clif_displaymessage(sd->fd, output); } @@ -867,13 +867,13 @@ int chrif_changedsex(int fd) { acc = RFIFOL(fd,2); sex = RFIFOL(fd,6); - + if ( battle_config.etc_log ) ShowNotice("chrif_changedsex %d.\n", acc); - + sd = map_id2sd(acc); if ( sd ) { //Normally there should not be a char logged on right now! - if ( sd->status.sex == sex ) + if ( sd->status.sex == sex ) return 0; //Do nothing? Likely safe. sd->status.sex = !sd->status.sex; @@ -952,7 +952,7 @@ int chrif_divorceack(int char_id, int partner_id) { if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F) pc_delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER); } - + return 0; } /*========================================== @@ -965,7 +965,7 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) { sd->status.child = 0; sd->status.skill[WE_CALLBABY].id = 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); } @@ -973,7 +973,7 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) { sd->status.child = 0; sd->status.skill[WE_CALLBABY].id = 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); } @@ -988,10 +988,10 @@ int chrif_accountban(int fd) { struct map_session_data *sd; acc = RFIFOL(fd,2); - + if ( battle_config.etc_log ) ShowNotice("chrif_accountban %d.\n", acc); - + sd = map_id2sd(acc); if ( acc < 0 || sd == NULL ) { @@ -1006,8 +1006,8 @@ int chrif_accountban(int fd) { clif_displaymessage(sd->fd, msg_txt(411+ret_status)); else if(ret_status==100) clif_displaymessage(sd->fd, msg_txt(421)); - else - clif_displaymessage(sd->fd, msg_txt(420)); //"Your account has not more authorised." + else + clif_displaymessage(sd->fd, msg_txt(420)); //"Your account has not more authorised." } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban time_t timestamp; char tmpstr[2048]; @@ -1031,10 +1031,10 @@ int chrif_disconnectplayer(int fd) { sd = map_id2sd(account_id); if( sd == NULL ) { struct auth_node* auth = chrif_search(account_id); - + if( auth != NULL && chrif_auth_delete(account_id, auth->char_id, ST_LOGIN) ) return 0; - + return -1; } @@ -1061,7 +1061,7 @@ int chrif_disconnectplayer(int fd) { *------------------------------------------*/ int chrif_updatefamelist(struct map_session_data* sd) { char type; - + chrif_check(-1); switch(sd->class_ & MAPID_UPPERMASK) { @@ -1101,30 +1101,30 @@ int chrif_recvfamelist(int fd) { memset (taekwon_fame_list, 0, sizeof(taekwon_fame_list)); size = RFIFOW(fd, 6); //Blacksmith block size - + for (num = 0; len < size && num < MAX_FAME_LIST; num++) { memcpy(&smith_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } - + total += num; size = RFIFOW(fd, 4); //Alchemist block size - + for (num = 0; len < size && num < MAX_FAME_LIST; num++) { memcpy(&chemist_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } - + total += num; size = RFIFOW(fd, 2); //Total packet length - + for (num = 0; len < size && num < MAX_FAME_LIST; num++) { memcpy(&taekwon_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } - + total += num; ShowInfo("Received Fame List of '"CL_WHITE"%d"CL_RESET"' characters.\n", total); @@ -1137,21 +1137,21 @@ int chrif_recvfamelist(int fd) { int chrif_updatefamelist_ack(int fd) { struct fame_list* list; uint8 index; - + switch (RFIFOB(fd,2)) { case 1: list = smith_fame_list; break; case 2: list = chemist_fame_list; break; case 3: list = taekwon_fame_list; break; default: return 0; } - + index = RFIFOB(fd, 3); - + if (index >= MAX_FAME_LIST) return 0; - + list[index].fame = RFIFOL(fd,4); - + return 1; } @@ -1166,12 +1166,12 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the chrif_check(-1); tick = gettick(); - + WFIFOHEAD(char_fd, 14 + SC_MAX*sizeof(struct status_change_data)); WFIFOW(char_fd,0) = 0x2b1c; WFIFOL(char_fd,4) = sd->status.account_id; WFIFOL(char_fd,8) = sd->status.char_id; - + for (i = 0; i < SC_MAX; i++) { if (!sc->data[i]) continue; @@ -1191,15 +1191,15 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the &data, sizeof(struct status_change_data)); count++; } - + if (count == 0) return 0; //Nothing to save. - + WFIFOW(char_fd,12) = count; WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size WFIFOSET(char_fd,WFIFOW(char_fd,2)); #endif - + return 0; } @@ -1213,27 +1213,27 @@ int chrif_load_scdata(int fd) { aid = RFIFOL(fd,4); //Player Account ID cid = RFIFOL(fd,8); //Player Char ID - + sd = map_id2sd(aid); - + if ( !sd ) { ShowError("chrif_load_scdata: Player of AID %d not found!\n", aid); return -1; } - + if ( sd->status.char_id != cid ) { ShowError("chrif_load_scdata: Receiving data for account %d, char id does not matches (%d != %d)!\n", aid, sd->status.char_id, cid); return -1; } - + count = RFIFOW(fd,12); //sc_count - + for (i = 0; i < count; i++) { data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data)); status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 15); } #endif - + return 0; } @@ -1250,7 +1250,7 @@ int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate) { WFIFOL(char_fd,6) = job_rate; WFIFOL(char_fd,10) = drop_rate; WFIFOSET(char_fd,14); - + return 0; } @@ -1329,7 +1329,7 @@ void chrif_on_disconnect(void) { if( chrif_connected != 1 ) ShowWarning("Connection to Char Server lost.\n\n"); chrif_connected = 0; - + other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect. map_eraseallipport(); @@ -1340,19 +1340,19 @@ void chrif_on_disconnect(void) { void chrif_update_ip(int fd) { uint32 new_ip; - + WFIFOHEAD(fd,6); - + new_ip = host2ip(char_ip_str); - + if (new_ip && new_ip != char_ip) char_ip = new_ip; //Update char_ip new_ip = clif_refresh_ip(); - + if (!new_ip) return; //No change - + WFIFOW(fd,0) = 0x2736; WFIFOL(fd,2) = htonl(new_ip); WFIFOSET(fd,6); @@ -1400,7 +1400,7 @@ int chrif_parse(int fd) { if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { int r = intif_parse(fd); // Passed on to the intif - if (r == 1) continue; // Treated in intif + if (r == 1) continue; // Treated in intif if (r == 2) return 0; // Didn't have enough data (len==-1) ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); @@ -1477,20 +1477,20 @@ int send_users_tochar(void) { chrif_check(-1); users = map_usercount(); - + WFIFOHEAD(char_fd, 6+8*users); WFIFOW(char_fd,0) = 0x2aff; - + iter = mapit_getallusers(); - + for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) ) { WFIFOL(char_fd,6+8*i) = sd->status.account_id; WFIFOL(char_fd,6+8*i+4) = sd->status.char_id; i++; } - + mapit_free(iter); - + WFIFOW(char_fd,2) = 6 + 8*users; WFIFOW(char_fd,4) = users; WFIFOSET(char_fd, 6+8*users); @@ -1512,7 +1512,7 @@ static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_ chrif_state = 0; char_fd = make_connection(char_ip, char_port,false); - + if (char_fd == -1)//Attempt to connect later. [Skotlex] return 0; @@ -1546,7 +1546,7 @@ int chrif_removefriend(int char_id, int friend_id) { WFIFOL(char_fd,2) = char_id; WFIFOL(char_fd,6) = friend_id; WFIFOSET(char_fd,10); - + return 0; } @@ -1554,13 +1554,13 @@ void chrif_send_report(char* buf, int len) { #ifndef STATS_OPT_OUT WFIFOHEAD(char_fd,len + 2); - + WFIFOW(char_fd,0) = 0x3008; - + memcpy(WFIFOP(char_fd,2), buf, len); - + WFIFOSET(char_fd,len + 2); - + flush_fifo(char_fd); /* ensure it's sent now. */ #endif @@ -1571,15 +1571,15 @@ void chrif_send_report(char* buf, int len) { */ int auth_db_final(DBKey key, DBData *data, va_list ap) { struct auth_node *node = db_data2ptr(data); - + if (node->char_dat) aFree(node->char_dat); - + if (node->sd) aFree(node->sd); - + ers_free(auth_db_ers, node); - + return 0; } @@ -1587,16 +1587,16 @@ int auth_db_final(DBKey key, DBData *data, va_list ap) { * Destructor *------------------------------------------*/ int do_final_chrif(void) { - + if( char_fd != -1 ) { do_close(char_fd); char_fd = -1; } auth_db->destroy(auth_db, auth_db_final); - + ers_destroy(auth_db_ers); - + return 0; } @@ -1604,7 +1604,7 @@ int do_final_chrif(void) { * *------------------------------------------*/ int do_init_chrif(void) { - + auth_db = idb_alloc(DB_OPT_BASE); auth_db_ers = ers_new(sizeof(struct auth_node),"chrif.c::auth_db_ers",ERS_OPT_NONE); diff --git a/src/map/clif.c b/src/map/clif.c index 3864c3b330..aaa6119b0e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1481,9 +1481,10 @@ int clif_homskillinfoblock(struct map_session_data *sd) WFIFOW(fd,0)=0x235; for ( i = 0; i < MAX_HOMUNSKILL; i++){ if( (id = hd->homunculus.hskill[i].id) != 0 ){ + int combo = (hd->homunculus.hskill[i].flag)&SKILL_FLAG_TMP_COMBO; j = id - HM_SKILLBASE; 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+6) = 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. /// 011f .L .L .W .W .B .B (ZC_SKILL_ENTRY) /// 01c9 .L .L .W .W .B .B .B .80B (ZC_SKILL_ENTRY2) -static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit) +/// 08c7 .W L .L .W .W .B .W .B (ZC_SKILL_ENTRY3) +/// 099f .W L .L .W .W .L .W .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 header=0, unit_id=0, pos=0; if( unit->group->state.guildaura ) 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(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] - WFIFOHEAD(fd,packet_len(0x1c9)); - 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; + clif_getareachar_skillunit(2,sd,unit); } #endif - WFIFOHEAD(fd,packet_len(0x11f)); - WFIFOW(fd, 0)=0x11f; - 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; - if (battle_config.traps_setting&1 && skill_get_inf2(unit->group->skill_id)&INF2_TRAP) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else if (skill_get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else - WFIFOB(fd,14)=unit->group->unit_id; - WFIFOB(fd,15)=1; // ignored by client (always gets set to 1) - WFIFOSET(fd,packet_len(0x11f)); + WFIFOHEAD(fd,packet_len(header)); + WFIFOW(fd,pos)=header; + if(type==3 || type==4){ + WFIFOW(fd, pos+2)=packet_len(header); + pos +=2; + } + WFIFOL(fd,pos+2)=unit->bl.id; + WFIFOL(fd,pos+6)=unit->group->src_id; + WFIFOW(fd,pos+10)=unit->bl.x; + WFIFOW(fd,pos+12)=unit->bl.y; + switch(type){ + case 1: WFIFOB(fd,pos+14)=unit_id; + WFIFOB(fd,pos+15)=1; + 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) 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); break; case BL_SKILL: - clif_getareachar_skillunit(sd,(TBL_SKILL*)bl); + clif_getareachar_skillunit(1,sd,(TBL_SKILL*)bl); break; default: 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); break; case BL_SKILL: - clif_getareachar_skillunit(tsd,(TBL_SKILL*)bl); + clif_getareachar_skillunit(1,tsd,(TBL_SKILL*)bl); break; default: clif_getareachar_unit(tsd,bl); @@ -4672,24 +4695,22 @@ void clif_deleteskill(struct map_session_data *sd, int id) clif_skillinfoblock(sd); } - /// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE). /// 010e .W .W .W .W .B -void clif_skillup(struct map_session_data *sd,uint16 skill_id) -{ - int fd; +void clif_skillup(struct map_session_data *sd, uint16 skill_id, int lv, int range, int upgradable) { + int fd; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x10e)); - WFIFOW(fd,0) = 0x10e; - WFIFOW(fd,2) = skill_id; - WFIFOW(fd,4) = sd->status.skill[skill_id].lv; - WFIFOW(fd,6) = skill_get_sp(skill_id,sd->status.skill[skill_id].lv); - WFIFOW(fd,8) = skill_get_range2(&sd->bl,skill_id,sd->status.skill[skill_id].lv); - WFIFOB(fd,10) = (sd->status.skill[skill_id].lv < skill_tree_get_max(sd->status.skill[skill_id].id, sd->status.class_)) ? 1 : 0; - WFIFOSET(fd,packet_len(0x10e)); + fd = sd->fd; + WFIFOHEAD(fd, packet_len(0x10e)); + 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) = range; + WFIFOB(fd, 10) = upgradable; + WFIFOSET(fd, packet_len(0x10e)); } @@ -5378,7 +5399,7 @@ void clif_displaymessage(const int fd, const char* mes) WFIFOHEAD(fd, 5 + len); WFIFOW(fd,0) = 0x8e; WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate - safestrncpy((char *)WFIFOP(fd,4), line, len + 1); + safestrncpy((char *)WFIFOP(fd,4), line, len + 1); WFIFOSET(fd, 5 + len); } line = strtok(NULL, "\n"); @@ -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); } - -/*========================================== - * 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). /// 0171 .L .24B 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; int guild_id = RFIFOL(fd,2); - if( (g = guild_search(guild_id)) != NULL ) + if( (g = sd->guild) != NULL ) clif_guild_emblem(sd,g); } diff --git a/src/map/clif.h b/src/map/clif.h index 4345e65c4e..0ff6befe76 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -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) 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_addskill(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_notice(struct map_session_data* sd, struct guild* g); 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_allianceack(struct map_session_data *sd,int flag); void clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag); diff --git a/src/map/guild.c b/src/map/guild.c index 0039b5cbec..31d60f45a4 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -261,7 +261,7 @@ int guild_getposition(struct guild* g, struct map_session_data* sd) if( g == NULL && (g=sd->guild) == NULL ) return -1; - + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == sd->status.account_id && g->member[i].char_id == sd->status.char_id ); return( i < g->max_member ) ? g->member[i].position : -1; } @@ -297,7 +297,7 @@ int guild_payexp_timer_sub(DBKey key, DBData *data, va_list ap) { struct guild *g; c = db_data2ptr(data); - + if ( (g = guild_search(c->guild_id)) == NULL || (i = guild_getindex(g, c->account_id, c->char_id)) < 0 @@ -567,7 +567,7 @@ int guild_recv_info(struct guild *sg) ShowError("guild_recv_info: Received guild with %d members, but MAX_GUILD is only %d. Extra guild-members have been lost!\n", g->max_member, MAX_GUILD); g->max_member = MAX_GUILD; } - + for(i=bm=m=0;imax_member;i++){ if(g->member[i].account_id>0){ sd = g->member[i].sd = guild_sd_check(g->guild_id, g->member[i].account_id, g->member[i].char_id); @@ -579,30 +579,30 @@ int guild_recv_info(struct guild *sg) bm++; } - for (i = 0; i < g->max_member; i++) { //Transmission of information at all members + for (i = 0; i < g->max_member; i++) { //Transmission of information at all members sd = g->member[i].sd; if( sd==NULL ) continue; - if (before.guild_lv != g->guild_lv || bm != m || - before.max_member != g->max_member) { - clif_guild_basicinfo(sd); //Submit basic information - clif_guild_emblem(sd, g); //Submit emblem - } + if (before.guild_lv != g->guild_lv || bm != m || + before.max_member != g->max_member) { + clif_guild_basicinfo(sd); //Submit basic information + clif_guild_emblem(sd, g); //Submit emblem + } - if (bm != m) { //Send members information - clif_guild_memberlist(g->member[i].sd); - } + if (bm != m) { //Send members information + clif_guild_memberlist(g->member[i].sd); + } - if (before.skill_point != g->skill_point) - clif_guild_skillinfo(sd); //Submit information skills + if (before.skill_point != g->skill_point) + clif_guild_skillinfo(sd); //Submit information skills - if (guild_new) { // Send information and affiliation if unsent - clif_guild_belonginfo(sd, g); - clif_guild_notice(sd, g); - sd->guild_emblem_id = g->emblem_id; - } - } + if (guild_new) { // Send information and affiliation if unsent + clif_guild_belonginfo(sd, g); + clif_guild_notice(sd, g); + sd->guild_emblem_id = g->emblem_id; + } + } //Occurrence of an event if (guild_infoevent_db->remove(guild_infoevent_db, db_i2key(sg->guild_id), &data)) { @@ -622,8 +622,8 @@ int guild_recv_info(struct guild *sg) * Player sd send a guild invatation to player tsd to join his guild *--------------------------------------------*/ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) { - struct guild *g; - int i; + struct guild *g; + int i; nullpo_ret(sd); @@ -641,7 +641,7 @@ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) { return 0; } } - + if (!tsd->fd) { //You can't invite someone who has already disconnected. clif_guild_inviteack(sd,1); return 0; @@ -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); return 0; } - sd->guild = g; guild_makemember(&m,sd); intif_guild_addmember(guild_id, &m); @@ -882,7 +881,7 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c if(g == NULL) return 0; // no such guild (error!) - + i = guild_getindex(g, account_id, char_id); if( i == -1 ) return 0; // not a member (inconsistency!) @@ -916,7 +915,7 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c sd->status.guild_id = 0; sd->guild = NULL; sd->guild_emblem_id = 0; - + clif_charnameupdate(sd); //Update display name [Skotlex] //TODO: send emblem update to self and people around } @@ -926,9 +925,9 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c int guild_send_memberinfoshort(struct map_session_data *sd,int online) { // cleaned up [LuzZza] struct guild *g; - + nullpo_ret(sd); - + if(sd->status.guild_id <= 0) return 0; @@ -946,7 +945,7 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) ShowError("guild_send_memberinfoshort: Failed to locate member %d:%d in guild %d!\n", sd->status.account_id, sd->status.char_id, g->guild_id); return 0; } - + if(sd->state.connect_new) { //Note that this works because it is invoked in parse_LoadEndAck before connect_new is cleared. clif_guild_belonginfo(sd,g); @@ -958,13 +957,13 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int online,int lv,int class_) { // cleaned up [LuzZza] - + int i,alv,c,idx=-1,om=0,oldonline=-1; struct guild *g = guild_search(guild_id); - + if(g == NULL) return 0; - + for(i=0,alv=0,c=0,om=0;imax_member;i++){ struct guild_member *m=&g->member[i]; if(!m->account_id) continue; @@ -980,7 +979,7 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin if(m->online) om++; } - + if(idx == -1 || c == 0) { //Treat char_id who doesn't match guild_id (not found as member) struct map_session_data *sd = map_id2sd(account_id); @@ -991,23 +990,23 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); return 0; } - + g->average_lv=alv/c; g->connect_member=om; //Ensure validity of pointer (ie: player logs in/out, changes map-server) g->member[idx].sd = guild_sd_check(guild_id, account_id, char_id); - if(oldonline!=online) + if(oldonline!=online) clif_guild_memberlogin_notice(g, idx, online); - + if(!g->member[idx].sd) return 0; //Send XY dot updates. [Skotlex] //Moved from guild_send_memberinfoshort [LuzZza] for(i=0; i < g->max_member; i++) { - + if(!g->member[i].sd || i == idx || g->member[i].sd->bl.m != g->member[idx].sd->bl.m) continue; @@ -1066,7 +1065,7 @@ int guild_memberposition_changed(struct guild *g,int idx,int pos) g->member[idx].position=pos; clif_guild_memberpositionchanged(g,idx); - + // Update char position in client [LuzZza] if(g->member[idx].sd != NULL) clif_charnameupdate(g->member[idx].sd); @@ -1101,7 +1100,7 @@ int guild_position_changed(int guild_id,int idx,struct guild_position *p) return 0; memcpy(&g->position[idx],p,sizeof(struct guild_position)); clif_guild_positionchanged(g,idx); - + // Update char name in client [LuzZza] for(i=0;imax_member;i++) if(g->member[i].position == idx && g->member[i].sd != NULL) @@ -1244,29 +1243,29 @@ unsigned int guild_payexp(struct map_session_data *sd,unsigned int exp) struct guild *g; struct guild_expcache *c; int per; - + nullpo_ret(sd); if (!exp) return 0; - + if (sd->status.guild_id == 0 || (g = sd->guild) == NULL || (per = guild_getposition(g,sd)) < 0 || (per = g->position[per].exp_mode) < 1) return 0; - + if (per < 100) exp = exp * per / 100; //Otherwise tax everything. - + c = db_data2ptr(guild_expcache_db->ensure(guild_expcache_db, db_i2key(sd->status.char_id), create_expcache, sd)); if (c->exp > UINT64_MAX - exp) c->exp = UINT64_MAX; else c->exp += exp; - + return exp; } @@ -1326,7 +1325,9 @@ int guild_skillupack(int guild_id,uint16 skill_id,int account_id) if(g==NULL) return 0; 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 */ switch( skill_id ) { @@ -1763,7 +1764,7 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) if (sd->status.guild_id != guild_id) return 0; - + g=guild_search(guild_id); nullpo_ret(g); @@ -1807,7 +1808,7 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) clif_displaymessage(g->member[pos].sd->fd, msg_txt(678)); //"You no longer are the Guild Master." g->member[pos].sd->state.gmaster_flag = 0; } - + if (g->member[0].sd && g->member[0].sd->fd) { clif_displaymessage(g->member[0].sd->fd, msg_txt(679)); //"You have become the Guild Master!" g->member[0].sd->state.gmaster_flag = g; @@ -1961,7 +1962,7 @@ void guild_castle_reconnect_sub(void *key, void *data, va_list ap) } /** - * Saves pending guild castle data changes when char-server is + * Saves pending guild castle data changes when char-server is * disconnected. * On reconnect pushes all changes to char-server for saving. */ @@ -2088,7 +2089,7 @@ bool guild_isallied(int guild_id, int guild_id2) void guild_flag_add(struct npc_data *nd) { int i; - + /* check */ for( i = 0; i < guild_flags_count; i++ ) { if( guild_flags[i] && guild_flags[i]->bl.id == nd->bl.id ) { @@ -2119,11 +2120,11 @@ void guild_flag_remove(struct npc_data *nd) { for( i = 0, cursor = 0; i < guild_flags_count; i++ ) { if( guild_flags[i] == NULL ) continue; - + if( cursor != i ) { memmove(&guild_flags[cursor], &guild_flags[i], sizeof(struct npc_data*)); } - + cursor++; } @@ -2169,7 +2170,7 @@ void guild_flags_clear(void) { if( guild_flags[i] ) guild_flags[i] = NULL; } - + guild_flags_count = 0; } @@ -2179,9 +2180,9 @@ void do_init_guild(void) { guild_expcache_db = idb_alloc(DB_OPT_BASE); guild_infoevent_db = idb_alloc(DB_OPT_BASE); expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.c::expcache_ers",ERS_OPT_NONE); - + guild_flags_count = 0; - + sv_readdb(db_path, "castle_db.txt", ',', 4, 5, -1, &guild_read_castledb); memset(guild_skill_tree,0,sizeof(guild_skill_tree)); diff --git a/src/map/map.c b/src/map/map.c index fbaf5d4f82..07bdd816d3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -379,6 +379,8 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) skill_unit_move(bl,tick,2); status_change_end(bl, SC_CLOSECONFINE, 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_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); diff --git a/src/map/mob.c b/src/map/mob.c index d6df494473..6e5df8acb5 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2549,7 +2549,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } if (type&2 && !sd && md->class_ == MOBID_EMPERIUM) - //Emperium destroyed by script. Discard mvp character. [Skotlex] + //Emperium destroyed by script. Discard mvp character. [Skotlex] mvp_sd = NULL; rebirth = ( md->sc.data[SC_KAIZEL] || (md->sc.data[SC_REBIRTH] && !md->state.rebirth) ); @@ -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)); // Remove all status changes before creating a respawn - if( sc ) + if( sc ){ + for(i=0; idata[i] && (sc->data[i]->timer != INVALID_TIMER)) + delete_timer(sc->data[i]->timer, status_change_timer); + } memset( sc, 0, sizeof( struct status_change ) ); + } if( !rebirth ) mob_setdelayspawn(md); //Set respawning. @@ -2934,7 +2939,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) //Inherit the aggressive mode of the master. if (battle_config.slaves_inherit_mode && md->master_id) - { + { switch (battle_config.slaves_inherit_mode) { case 1: //Always aggressive if (!(md->status.mode&MD_AGGRESSIVE)) diff --git a/src/map/pc.c b/src/map/pc.c index a2257162d5..90cb7e7fb3 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1291,7 +1291,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) { sd->status.skill[i].id = 0; sd->status.skill[i].lv = 0; - sd->status.skill[i].flag = 0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } break; } @@ -1520,12 +1520,12 @@ int pc_clean_skilltree(struct map_session_data *sd) { sd->status.skill[i].id = 0; sd->status.skill[i].lv = 0; - sd->status.skill[i].flag = 0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } else 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].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].lv < skill_tree_get_max(skill_id, sd->status.class_) ) { + int lv,range, upgradable; sd->status.skill[skill_id].lv++; sd->status.skill_point--; if( !skill_get_inf(skill_id) ) @@ -6051,7 +6052,10 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) else 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); if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ 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 ) { sd->status.skill[i].lv = 0; - sd->status.skill[i].flag = 0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; continue; } @@ -6356,7 +6360,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( battle_config.quest_skill_reset && !(flag&2) ) { //Wipe them sd->status.skill[i].lv = 0; - sd->status.skill[i].flag = 0; + sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } continue; } @@ -6369,7 +6373,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( !(flag&2) ) {// reset 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 ) { sd->status.skill[sd->cloneskill_id].id = 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); } 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 ) { sd->status.skill[sd->reproduceskill_id].id = 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); } sd->reproduceskill_id = 0; @@ -9382,7 +9386,7 @@ int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_ int diff, rate = 100, i; nullpo_ret(sd); - + diff = mob_level - sd->status.base_level; if( diff < 0 ) diff --git a/src/map/skill.c b/src/map/skill.c index 476e0885d1..ad81ae8894 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -657,91 +657,35 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd) if (hd->blockskill[idx] > 0) return 1; switch(skill_id){ - case MH_LIGHT_OF_REGENE: - if(hd->homunculus.intimacy <= 750) //if not cordial - return 1; + case MH_LIGHT_OF_REGENE: //must be cordial + if(hd->homunculus.intimacy <= 750) return 1; break; - case MH_OVERED_BOOST: - if(hd->homunculus.hunger <= 1) //if we starving - return 1; + case MH_OVERED_BOOST: //if we starving + if(hd->homunculus.hunger <= 1) return 1; break; - case MH_GOLDENE_FERSE: //cant be used with angriff - if(hd->sc.data[SC_ANGRIFFS_MODUS]) - return 1; + case MH_GOLDENE_FERSE: //cant be used with angriff + if(hd->sc.data[SC_ANGRIFFS_MODUS]) return 1; break; - case MH_ANGRIFFS_MODUS: - if(hd->sc.data[SC_GOLDENE_FERSE]) - return 1; + case MH_ANGRIFFS_MODUS: + if(hd->sc.data[SC_GOLDENE_FERSE]) return 1; break; - case MH_TINDER_BREAKER: - case MH_CBC: - case MH_EQC: - case MH_SONIC_CRAW: - case MH_SILVERVEIN_RUSH: - case MH_MIDNIGHT_FRENZY: { - struct status_change_entry *sce = hd->sc.data[SC_STYLE_CHANGE]; - TBL_PC *sd; - 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; - - case MH_MIDNIGHT_FRENZY: - case MH_EQC: - if(hd->homunculus.spiritball < 2) { - clif_colormes(sd,COLOR_RED,"Homon need at least 2 spiritballs"); - return 1; - } - 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_EQC: - 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; - } - - //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; - } - } + case MH_TINDER_BREAKER: //must be in grappling mode + if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_GRAPPLING)) return 1; + break; + case MH_SONIC_CRAW: //must be in fighting mode + if(!(hd->sc.data[SC_STYLE_CHANGE] && hd->sc.data[SC_STYLE_CHANGE]->val1 == MH_MD_FIGHTING)) return 1; + break; + case MH_SILVERVEIN_RUSH: + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SONIC_CRAW)) return 1; + break; + case MH_MIDNIGHT_FRENZY: + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_SILVERVEIN_RUSH)) return 1; + break; + case MH_CBC: + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_TINDER_BREAKER)) return 1; + break; + case MH_EQC: + if(!(hd->sc.data[SC_COMBO] && hd->sc.data[SC_COMBO]->val1 == MH_CBC)) return 1; break; } @@ -1499,6 +1443,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint 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 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) @@ -2257,6 +2204,141 @@ static int skill_magic_reflect(struct block_list* src, struct block_list* bl, in 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. @@ -2405,106 +2487,45 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds //Skill hit type type=(skill_id==0)?5:skill_get_hit(skill_id); - if(damage < dmg.div_ - //Only skills that knockback even when they miss. [Skotlex] - && skill_id != CH_PALMSTRIKE) - dmg.blewcount = 0; - - if(skill_id == CR_GRANDCROSS||skill_id == NPC_GRANDDARKNESS) { + switch(skill_id){ + case SC_TRIANGLESHOT: + if(rnd()%100 > (1 + skill_lv) ) dmg.blewcount = 0; + break; + default: + 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(src == bl) type = 4; else flag|=SD_ANIMATION; - } - if(skill_id == NJ_TATAMIGAESHI) { - dsrc = src; //For correct knockback. + break; + case NJ_TATAMIGAESHI: //For correct knockback. + dsrc = src; flag|=SD_ANIMATION; + break; + case TK_COUNTER: { //bonus from SG_FRIEND [Komurka] + int level; + if(sd->status.party_id>0 && (level = pc_checkskill(sd,SG_FRIEND))) + party_skill_check(sd, sd->status.party_id, TK_COUNTER,level); + } + break; + case SL_STIN: + case SL_STUN: + if (skill_lv >= 7 && !sd->sc.data[SC_SMA]) + sc_start(src,src,SC_SMA,100,skill_lv,skill_get_time(SL_SMA, skill_lv)); + break; + case GS_FULLBUSTER: + //Can't attack nor use items until skill's delay expires. [Skotlex] + sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick; + break; } - 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; - } - 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; - if(sd->status.party_id>0 && (level = pc_checkskill(sd,SG_FRIEND))) - party_skill_check(sd, sd->status.party_id, TK_COUNTER,level); - } - break; - case SL_STIN: - case SL_STUN: - if (skill_lv >= 7 && !sd->sc.data[SC_SMA]) - sc_start(src,src,SC_SMA,100,skill_lv,skill_get_time(SL_SMA, skill_lv)); - break; - case GS_FULLBUSTER: - //Can't attack nor use items until skill's delay expires. [Skotlex] - sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick; - 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. 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 ) { tsd->status.skill[tsd->reproduceskill_id].id = 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); } @@ -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){ tsd->status.skill[tsd->cloneskill_id].id = 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); } @@ -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] 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] //Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills) @@ -4720,67 +4735,38 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case MH_STAHL_HORN: case MH_NEEDLE_OF_PARALYZE: + case MH_SONIC_CRAW: skill_attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; - case MH_SONIC_CRAW: - case MH_TINDER_BREAKER: case MH_MIDNIGHT_FRENZY: - case MH_SILVERVEIN_RUSH: - case MH_CBC: - case MH_EQC: { + case MH_SILVERVEIN_RUSH:{ 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); - } - // hom_delspiritball(hd, nb_sphere, 0); //remove them all if we remove can't coninue combo - break; - } - case MH_SILVERVEIN_RUSH: - case MH_MIDNIGHT_FRENZY: - 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); - break; - case MH_TINDER_BREAKER: - if (unit_movepos(src, bl->x, bl->y, 1, 1)) { -#if PACKETVER >= 20111005 - clif_snap(src, bl->x, bl->y); -#else - clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick); -#endif - } - case MH_CBC: - case MH_EQC: - 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 - if(skill_id==MH_TINDER_BREAKER) - sc_start2(src,src,status_skill2sc(skill_id),100,skill_lv,bl->id,duration); - else - 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; - } + hom_delspiritball(hd,skill_id==MH_SILVERVEIN_RUSH?1:2,0); + skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); break; } + case MH_TINDER_BREAKER: + if (unit_movepos(src, bl->x, bl->y, 1, 1)) { +#if PACKETVER >= 20111005 + clif_snap(src, bl->x, bl->y); +#else + clif_skill_poseffect(src,skill_id,skill_lv,bl->x,bl->y,tick); +#endif + + } + case MH_CBC: + 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 + hom_delspiritball(hd,skill_id==MH_EQC?2:1,0); //only EQC consume 2 in grp 2 + skill_attack(skill_get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); + clif_skill_nodamage(src,bl,skill_id,skill_lv, + sc_start4(src,bl,status_skill2sc(skill_id),100,skill_lv,src->id,0,0,duration)); + break; + } + + case 0:/* no skill - basic/normal attack */ if(sd) { if (flag & 3){ @@ -9136,61 +9122,61 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; - case MH_SILENT_BREEZE: { - struct status_change *ssc = status_get_sc(src); - struct block_list *m_bl = battle_get_master(src); - const enum sc_type scs[] = { - SC_MANDRAGORA, SC_HARMONIZE, SC_DEEPSLEEP, SC_VOICEOFSIREN, SC_SLEEP, SC_CONFUSION, SC_HALLUCINATION - }; - int heal; - if(tsc){ - for (i = 0; i < ARRAYLENGTH(scs); i++) { - if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); - } - if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target - status_change_start(src,bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); - } - heal = status_get_sp(src) + status_get_lv(src); //cur_sp+blvl @TODO need real value - status_heal(bl, heal, 0, 7); + case MH_SILENT_BREEZE: { + struct status_change *ssc = status_get_sc(src); + struct block_list *m_bl = battle_get_master(src); + const enum sc_type scs[] = { + SC_MANDRAGORA, SC_HARMONIZE, SC_DEEPSLEEP, SC_VOICEOFSIREN, SC_SLEEP, SC_CONFUSION, SC_HALLUCINATION + }; + int heal; + if(tsc){ + for (i = 0; i < ARRAYLENGTH(scs); i++) { + if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); + } + if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target + status_change_start(src,bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); + } + heal = status_get_sp(src) + status_get_lv(src); //cur_sp+blvl @TODO need real value + status_heal(bl, heal, 0, 7); - //now inflict silence on everyone - if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun - status_change_start(src, src, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); - if(m_bl){ - struct status_change *msc = status_get_sc(m_bl); - if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master - status_change_start(src, m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); - } - if (hd) - skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); - } - break; - case MH_OVERED_BOOST: - if (hd){ - struct block_list *s_bl = battle_get_master(src); - if(hd->homunculus.hunger>50) //reduce hunger - hd->homunculus.hunger = hd->homunculus.hunger/2; - else - hd->homunculus.hunger = min(1,hd->homunculus.hunger); - if(s_bl && s_bl->type==BL_PC){ - status_set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp - clif_send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info - sc_start(src,s_bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); //gene bonus - } - sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); - skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); - } - break; - case MH_GRANITIC_ARMOR: - case MH_PYROCLASTIC: { - struct block_list *s_bl = battle_get_master(src); - if(s_bl) sc_start2(src, s_bl, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); //start on master - sc_start2(src, bl, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); - if (hd) skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); - } - break; + //now inflict silence on everyone + if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun + status_change_start(src, src, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); + if(m_bl){ + struct status_change *msc = status_get_sc(m_bl); + if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master + status_change_start(src, m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill_get_time(skill_id, skill_lv),1|2|8); + } + if (hd) + skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); + } + break; + case MH_OVERED_BOOST: + if (hd){ + struct block_list *s_bl = battle_get_master(src); + if(hd->homunculus.hunger>50) //reduce hunger + hd->homunculus.hunger = hd->homunculus.hunger/2; + else + hd->homunculus.hunger = min(1,hd->homunculus.hunger); + if(s_bl && s_bl->type==BL_PC){ + status_set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp + clif_send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info + sc_start(src,s_bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); //gene bonus + } + sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); + } + break; + case MH_GRANITIC_ARMOR: + case MH_PYROCLASTIC: { + struct block_list *s_bl = battle_get_master(src); + if(s_bl) sc_start2(src, s_bl, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); //start on master + sc_start2(src, bl, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); + if (hd) skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); + } + break; - case MH_LIGHT_OF_REGENE: //self + case MH_LIGHT_OF_REGENE: //self sc_start2(src, src, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); if(hd){ hd->homunculus.intimacy = 251; //change to neutral (can't be cast if < 750) @@ -9212,40 +9198,39 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } break; } - case MH_MAGMA_FLOW: - case MH_PAIN_KILLER: - sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); - if (hd) - skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); - break; + case MH_MAGMA_FLOW: + case MH_PAIN_KILLER: + sc_start(src,bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); + if (hd) + skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); + break; - case MH_SUMMON_LEGION: - { - int summons[5] = {2158, 2159, 2159, 2160, 2160}; - int qty[5] = {3 , 3 , 4 , 4 , 5}; - struct mob_data *sum_md; - int i,c=0; + case MH_SUMMON_LEGION: { + int summons[5] = {2158, 2159, 2159, 2160, 2160}; + int qty[5] = {3 , 3 , 4 , 4 , 5}; + struct mob_data *sum_md; + int i,c=0; int maxcount = qty[skill_lv-1]; i = map_foreachinmap(skill_check_condition_mob_master_sub ,hd->bl.m, BL_MOB, hd->bl.id, summons[skill_lv-1], skill_id, &c); if(c >= maxcount) return 0; //max qty already spawned - for(i=0; im, src->x, src->y, status_get_name(src), summons[skill_lv - 1], "", SZ_SMALL, AI_ATTACK); - if (sum_md) { - sum_md->master_id = src->id; - sum_md->special_state.ai = 5; - if (sum_md->deletetimer != INVALID_TIMER) - delete_timer(sum_md->deletetimer, mob_timer_delete); - sum_md->deletetimer = add_timer(gettick() + skill_get_time(skill_id, skill_lv), mob_timer_delete, sum_md->bl.id, 0); - mob_spawn(sum_md); //Now it is ready for spawning. - sc_start4(&sum_md->bl,&sum_md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); - } - } + for(i=0; im, src->x, src->y, status_get_name(src), summons[skill_lv - 1], "", SZ_SMALL, AI_ATTACK); + if (sum_md) { + sum_md->master_id = src->id; + sum_md->special_state.ai = 5; + if (sum_md->deletetimer != INVALID_TIMER) + delete_timer(sum_md->deletetimer, mob_timer_delete); + sum_md->deletetimer = add_timer(gettick() + skill_get_time(skill_id, skill_lv), mob_timer_delete, sum_md->bl.id, 0); + mob_spawn(sum_md); //Now it is ready for spawning. + sc_start4(&sum_md->bl,&sum_md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); + } + } if (hd) skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); - } - break; + } + break; default: ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id); clif_skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -9480,10 +9465,10 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) break; if (ud->state.running && ud->skill_id == TK_JUMPKICK) - { - ud->state.running = 0; - status_change_end(src, SC_RUN, INVALID_TIMER); - flag = 1; + { + ud->state.running = 0; + status_change_end(src, SC_RUN, INVALID_TIMER); + flag = 1; } if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH) @@ -13978,7 +13963,7 @@ int skill_castfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { if (battle_config.cast_rate != 100) time = time * battle_config.cast_rate / 100; // return final cast time - time = max(time, 0); + time = max(time, 0); // ShowInfo("Castime castfix = %d\n",time); return time; @@ -13997,8 +13982,8 @@ int skill_castfix_sc (struct block_list *bl, int time) if (sc && sc->count) { if (sc->data[SC_SLOWCAST]) time += time * sc->data[SC_SLOWCAST]->val2 / 100; - if (sc->data[SC_PARALYSIS]) - time += sc->data[SC_PARALYSIS]->val3; + if (sc->data[SC_PARALYSIS]) + time += sc->data[SC_PARALYSIS]->val3; if (sc->data[SC_SUFFRAGIUM]) { time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100; status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER); @@ -14013,7 +13998,7 @@ int skill_castfix_sc (struct block_list *bl, int time) if (sc->data[SC_IZAYOI]) time -= time * 50 / 100; } - time = max(time, 0); + time = max(time, 0); // ShowInfo("Castime castfix_sc = %d\n",time); return time; diff --git a/src/map/skill.h b/src/map/skill.h index 0193be2883..a89a72b475 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -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_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_ */ diff --git a/src/map/status.c b/src/map/status.c index c6be101198..b5cded3593 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -508,7 +508,8 @@ void initChangeTables(void) { set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); 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_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_CLOSECONFINE] |= 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_GRAVITATION] |= SCS_NOMOVE|SCS_NOMOVECOND; StatusChangeStateTable[SC_WHITEIMPRISON] |= SCS_NOMOVE; @@ -1314,18 +1317,18 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s return hp+sp; } - if(target->type == BL_PC){ - TBL_PC *sd = BL_CAST(BL_PC,target); - TBL_HOM *hd = sd->hd; - if(hd && hd->sc.data[SC_LIGHT_OF_REGENE]){ - clif_skillcasting(&hd->bl, hd->bl.id, target->id, 0,0, MH_LIGHT_OF_REGENE, skill_get_ele(MH_LIGHT_OF_REGENE, 1), 10); //just to display usage - clif_skill_nodamage(&sd->bl, target, ALL_RESURRECTION, 1, status_revive(&sd->bl,hd->sc.data[SC_LIGHT_OF_REGENE]->val2,0)); - status_change_end(&sd->hd->bl,SC_LIGHT_OF_REGENE,INVALID_TIMER); - return hp + sp; - } - } - if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) {// Ensure the monster has not already rebirthed before doing so. - status_revive(target, sc->data[SC_REBIRTH]->val2, 0); + if(target->type == BL_PC){ + TBL_PC *sd = BL_CAST(BL_PC,target); + TBL_HOM *hd = sd->hd; + if(hd && hd->sc.data[SC_LIGHT_OF_REGENE]){ + clif_skillcasting(&hd->bl, hd->bl.id, target->id, 0,0, MH_LIGHT_OF_REGENE, skill_get_ele(MH_LIGHT_OF_REGENE, 1), 10); //just to display usage + clif_skill_nodamage(&sd->bl, target, ALL_RESURRECTION, 1, status_revive(&sd->bl,hd->sc.data[SC_LIGHT_OF_REGENE]->val2,0)); + status_change_end(&sd->hd->bl,SC_LIGHT_OF_REGENE,INVALID_TIMER); + return hp + sp; + } + } + if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) {// Ensure the monster has not already rebirthed before doing so. + status_revive(target, sc->data[SC_REBIRTH]->val2, 0); status_change_clear(target,0); ((TBL_MOB*)target)->state.rebirth = 1; @@ -4813,6 +4816,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change if(!sc || !sc->count) 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]) 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_DPOISON: case SC_CLOSECONFINE2: //Can't be re-closed in. + case SC_TINDER_BREAKER2: case SC_MARIONETTE: case SC_MARIONETTE2: 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); return 1; break; + case SC_TINDER_BREAKER2: case SC_CLOSECONFINE2: { struct block_list *src = val2?map_id2bl(val2):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 (!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. (sce2->val2)++; 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. return 0; @@ -8682,69 +8691,69 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty status_zap(bl, hp * (lv*4) / 100, status_get_sp(bl) * (lv*3) / 100); } break; - case SC_ANGRIFFS_MODUS: - val2 = 50 + 20 * val1; //atk bonus - val3 = 40 + 20 * val1; // Flee reduction. - val4 = tick/1000; // hp/sp reduction timer - tick_time = 1000; - break; - case SC_GOLDENE_FERSE: - val2 = 10 + 10*val1; //flee bonus - val3 = 6 + 4 * val1; // Aspd Bonus - val4 = 2 + 2 * val1; // Chance of holy attack - break; - case SC_OVERED_BOOST: - val2 = 300 + 40*val1; //flee bonus - val3 = 179 + 2*val1; //aspd bonus - val4 = 50; //def reduc % - break; - case SC_GRANITIC_ARMOR: - val2 = 2*val1; //dmg hp reduction - val3 = (6*status_get_max_hp(src))/100; //dmg hp on status end - val4 = 5 * val1; //unknow formula - break; - case SC_MAGMA_FLOW: - val2 = 3*val1; //activation chance - break; - case SC_PYROCLASTIC: - val2 += 10*val1*status_get_lv(src); //atk bonus - val3 = 2*val1;//Chance To AutoCast Hammer Fall % - break; - case SC_PARALYSIS: //[Lighta] need real info - val2 = 2*val1; //def reduction - val3 = 500*val1; //varcast augmentation - break; - case SC_LIGHT_OF_REGENE: //Yommy leak need confirm - val2 = 20 * val1; //hp reco on death % - break; - case SC_PAIN_KILLER: //Yommy leak need confirm - val2 = 10 * val1; //aspd reduction % - val3 = (( 200 * val1 ) * status_get_lv(src)) / 150; //dmg reduction linear - if(sc->data[SC_PARALYSIS]) + case SC_ANGRIFFS_MODUS: + val2 = 50 + 20 * val1; //atk bonus + val3 = 40 + 20 * val1; // Flee reduction. + val4 = tick/1000; // hp/sp reduction timer + tick_time = 1000; + break; + case SC_GOLDENE_FERSE: + val2 = 10 + 10*val1; //flee bonus + val3 = 6 + 4 * val1; // Aspd Bonus + val4 = 2 + 2 * val1; // Chance of holy attack + break; + case SC_OVERED_BOOST: + val2 = 300 + 40*val1; //flee bonus + val3 = 179 + 2*val1; //aspd bonus + val4 = 50; //def reduc % + break; + case SC_GRANITIC_ARMOR: + val2 = 2*val1; //dmg hp reduction + val3 = (6*status_get_max_hp(src))/100; //dmg hp on status end + val4 = 5 * val1; //unknow formula + break; + case SC_MAGMA_FLOW: + val2 = 3*val1; //activation chance + break; + case SC_PYROCLASTIC: + val2 += 10*val1*status_get_lv(src); //atk bonus + val3 = 2*val1;//Chance To AutoCast Hammer Fall % + break; + case SC_PARALYSIS: //[Lighta] need real info + val2 = 2*val1; //def reduction + val3 = 500*val1; //varcast augmentation + break; + case SC_LIGHT_OF_REGENE: //Yommy leak need confirm + val2 = 20 * val1; //hp reco on death % + break; + case SC_PAIN_KILLER: //Yommy leak need confirm + val2 = 10 * val1; //aspd reduction % + val3 = (( 200 * val1 ) * status_get_lv(src)) / 150; //dmg reduction linear + if(sc->data[SC_PARALYSIS]) sc_start(src,bl, SC_ENDURE, 100, val1, tick); //start endure for same duration - break; - case SC_STYLE_CHANGE: //[Lighta] need real info - tick = -1; - break; - case SC_CBC: - val3 = 10; //drain sp % dmg - val4 = tick/1000; //dmg each sec - tick = 1000; - break; - case SC_EQC: - val2 = 5 * val1; //def % reduc - val3 = 5 * val1; //atk % reduc - val4 = 2 * val1; //maxhp % reduc - break; - case SC_ASH: - val2 = 50; //hit % reduc - val3 = 0;//def % reduc - val4 = 0;//atk flee & reduc - if(status_get_race(bl) == RC_PLANT) //plant type + break; + case SC_STYLE_CHANGE: + tick = -1; //infinite duration + break; + case SC_CBC: + val3 = 10; //drain sp % dmg + val4 = tick/1000; //dmg each sec + tick = 1000; + break; + case SC_EQC: + val2 = 5 * val1; //def % reduc + val3 = 5 * val1; //atk % reduc + val4 = 2 * val1; //maxhp % reduc + break; + case SC_ASH: + val2 = 50; //hit % reduc + val3 = 0;//def % reduc + val4 = 0;//atk flee & reduc + if(status_get_race(bl) == RC_PLANT) //plant type val3 = 50; - if(status_get_element(bl) == ELE_WATER) // defense water type + if(status_get_element(bl) == ELE_WATER) // defense water type val4 = 50; - break; + break; default: if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 ) { //Status change with no calc, no icon, and no skill associated...? @@ -8788,6 +8797,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_CONFUSION: case SC_CLOSECONFINE: case SC_CLOSECONFINE2: + case SC_TINDER_BREAKER: + case SC_TINDER_BREAKER2: case SC_SPIDERWEB: case SC_ELECTRICSHOCKER: case SC_BITE: @@ -9064,7 +9075,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty } break; case SC_COMBO: - switch (sce->val1) { + switch(sce->val1){ case TK_STORMKICK: clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1); break; @@ -9077,37 +9088,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case TK_COUNTER: clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); break; - case MO_COMBOFINISH: - case CH_TIGERFIST: - 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); - } + default: //rest just toogle inf to enable autotarget + skill_combo_toogle_inf(bl,sce->val1,INF_SELF_SKILL); break; } break; case SC_RAISINGDRAGON: sce->val2 = status->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] break; - case SC_TINDER_BREAKER: - sc_start2(src, map_id2bl(val2),SC_CLOSECONFINE2,100,val1,bl->id,tick); - break; case SC_EQC: 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; } @@ -9292,17 +9283,17 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const vd = status_get_viewdata(bl); calc_flag = StatusChangeFlagTable[type]; switch(type){ - case SC_GRANITIC_ARMOR:{ - int dammage = status->max_hp*sce->val3/100; - if(status->hp < dammage) //to not kill him - dammage = status->hp-1; - status_damage(NULL, bl, dammage,0,0,1); - break; - } - case SC_PYROCLASTIC: - if(bl->type == BL_PC) - skill_break_equip(bl,bl,EQP_WEAPON,10000,BCT_SELF); - break; + case SC_GRANITIC_ARMOR:{ + int dammage = status->max_hp*sce->val3/100; + if(status->hp < dammage) //to not kill him + dammage = status->hp-1; + status_damage(NULL, bl, dammage,0,0,1); + break; + } + case SC_PYROCLASTIC: + if(bl->type == BL_PC) + skill_break_equip(bl,bl,EQP_WEAPON,10000,BCT_SELF); + break; case SC_WEDDING: case SC_XMAS: case SC_SUMMER: @@ -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 ); } break; - case SC_TINDER_BREAKER: - case SC_CLOSECONFINE2: - { - struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL; - struct status_change *sc2 = src?status_get_sc(src):NULL; - if (src && sc2 && sc2->data[SC_CLOSECONFINE]) { - //If status was already ended, do nothing. - //Decrease count - if (--(sc2->data[SC_CLOSECONFINE]->val1) <= 0) //No more holds, free him up. - status_change_end(src, SC_CLOSECONFINE, INVALID_TIMER); - } + case SC_TINDER_BREAKER2: + case SC_CLOSECONFINE2:{ + struct block_list *src = sce->val2?map_id2bl(sce->val2):NULL; + struct status_change *sc2 = src?status_get_sc(src):NULL; + int type2 = ((type==SC_CLOSECONFINE2)?SC_CLOSECONFINE:SC_TINDER_BREAKER); + if (src && sc2 && sc2->data[type2]) { + //If status was already ended, do nothing. + //Decrease count + if (type==SC_TINDER_BREAKER2 || (--(sc2->data[type2]->val1) <= 0)) //No more holds, free him up. + status_change_end(src, type2, INVALID_TIMER); } + } + case SC_TINDER_BREAKER: case SC_CLOSECONFINE: if (sce->val2 > 0) { //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; case SC_COMBO: - if( sd ) - switch (sce->val1) { - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - clif_skillinfo(sd, MO_EXTREMITYFIST, 0); - 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; - } + skill_combo_toogle_inf(bl,sce->val1,0); break; - case SC_MARIONETTE: case SC_MARIONETTE2: /// Marionette target if (sce->val1) @@ -10799,7 +10772,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) tsc = status_get_sc(bl); switch( type ) { - case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ + case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); @@ -10809,7 +10782,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); break; - case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ + case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED] || tsc->data[SC__INVISIBILITY])) { //this sc should hit only @@ -10834,13 +10807,16 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) } } 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... - if (tsc && tsc->data[SC_CLOSECONFINE2] && tsc->data[SC_CLOSECONFINE2]->val2 == src->id) { - tsc->data[SC_CLOSECONFINE2]->val2 = 0; - status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); + if (tsc && tsc->data[type2] && tsc->data[type2]->val2 == src->id) { + tsc->data[type2]->val2 = 0; + status_change_end(bl, type2, INVALID_TIMER); } break; + } case SC_CURSEDCIRCLE_TARGET: 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); diff --git a/src/map/unit.c b/src/map/unit.c index 9995e756b4..a094167fdb 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -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 block_list * target = NULL; unsigned int tick = gettick(); - int temp = 0, range; + int combo = 0, range; nullpo_ret(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 target_id = src->id; - temp = 1; + combo = 1; } else if ( target_id == src->id && skill_get_inf(skill_id)&INF_SELF_SKILL && skill_get_inf2(skill_id)&INF2_NO_TARGET_SELF ) { target_id = ud->target; //Auto-select target. [Skotlex] - temp = 1; + combo = 1; } if (sd) { @@ -1083,7 +1083,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if (target) target_id = target->id; } - if (src->type==BL_HOM) + else if (src->type==BL_HOM) switch(skill_id) { //Homun-auto-target skills. 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); if (!target) return 0; 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 @@ -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 //(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( !unit_can_reach_bl(src, target, range + 1, 1, NULL, NULL) ) 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); else if(ud->attacktimer != INVALID_TIMER) //Elsewise, delay current attack sequence 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; //temp: Used to signal force cast now. - temp = 0; + combo = 0; switch(skill_id){ case ALL_RESURRECTION: if(battle_check_undead(tstatus->race,tstatus->def_ele)) { - temp = 1; + combo = 1; } else if (!status_isdead(target)) return 0; //Can't cast on non-dead characters. 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_CHAINCRUSH)) casttime = -1; - temp = 1; + combo = 1; break; case SR_GATEOFHELL: case SR_TIGERCANNON: if (sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE) casttime = -1; - temp = 1; + combo = 1; break; case SA_SPELLBREAKER: - temp = 1; + combo = 1; break; case ST_CHASEWALK: if (sc && sc->data[SC_CHASEWALK]) @@ -1243,7 +1253,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui case RA_WUGDASH: if (sc && sc->data[SC_WUGDASH]) casttime = -1; - break; + break; case EL_WIND_SLASH: case EL_HURRICANE: case EL_TYPOON_MIS: @@ -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 // 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); - if( casttime > 0 || temp ) + if( casttime > 0 || combo ) { 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_CLOSECONFINE, 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); // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later if ( bl->type != BL_PC )