diff options
author | hemagx <ibrahem.h.basyone@gmail.com> | 2016-10-22 02:28:16 +0200 |
---|---|---|
committer | hemagx <ibrahem.h.basyone@gmail.com> | 2016-10-22 02:28:16 +0200 |
commit | f072f3c9771cf0154f3b207970d86cc857708050 (patch) | |
tree | 34579ba5f0b3f71f681489883939d0ac770c7c0a /src/map | |
parent | d8441a3522797a25b5bcc46d6e5b38adebd0a70b (diff) | |
parent | 431b8aad001d959225aaa41b8d0a80c4d5526229 (diff) | |
download | hercules-f072f3c9771cf0154f3b207970d86cc857708050.tar.gz hercules-f072f3c9771cf0154f3b207970d86cc857708050.tar.bz2 hercules-f072f3c9771cf0154f3b207970d86cc857708050.tar.xz hercules-f072f3c9771cf0154f3b207970d86cc857708050.zip |
Merge pull request #1458 from dastgir/2016-1_summoner
Introduces Summoner Class
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/battle.c | 65 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 24 | ||||
-rw-r--r-- | src/map/itemdb.c | 5 | ||||
-rw-r--r-- | src/map/itemdb.h | 2 | ||||
-rw-r--r-- | src/map/map.c | 1 | ||||
-rw-r--r-- | src/map/map.h | 1 | ||||
-rw-r--r-- | src/map/packets.h | 150 | ||||
-rw-r--r-- | src/map/pc.c | 39 | ||||
-rw-r--r-- | src/map/pc.h | 2 | ||||
-rw-r--r-- | src/map/script.c | 7 | ||||
-rw-r--r-- | src/map/skill.c | 217 | ||||
-rw-r--r-- | src/map/skill.h | 48 | ||||
-rw-r--r-- | src/map/status.c | 134 | ||||
-rw-r--r-- | src/map/status.h | 32 | ||||
-rw-r--r-- | src/map/unit.c | 5 |
16 files changed, 677 insertions, 57 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index 67ab8c9b8..8c1a3f364 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1666,8 +1666,29 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block break; #endif /** - * Arch Bishop - **/ + * Summoner + **/ + case SU_BITE: + skillratio += 100; + break; + case SU_SCRATCH: + skillratio += -50 + 50 * skill_lv; + break; + case SU_SCAROFTAROU: + skillratio += -100 + 100 * skill_lv; + break; + case SU_PICKYPECK: + case SU_PICKYPECK_DOUBLE_ATK: + skillratio += 100 + 100 * skill_lv; + if ((status_get_max_hp(target) / 100) <= 50) + skillratio *= 2; + break; + case SU_LUNATICCARROTBEAT: + skillratio += 100 + 100 * skill_lv; + break; + /** + * Arch Bishop + **/ case AB_JUDEX: skillratio = 300 + 20 * skill_lv; RE_LVL_DMOD(100); @@ -1886,6 +1907,12 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block pc->del_charm(sd, sd->charm_count, sd->charm_type); } break; + case SU_SV_STEMSPEAR: + skillratio += 600; + break; + case SU_CN_METEOR: + skillratio += 100 + 100 * skill_lv; + break; default: battle->calc_skillratio_magic_unknown(&attack_type, src, target, &skill_id, &skill_lv, &skillratio, &flag); break; @@ -3068,6 +3095,9 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam damage -= 50 * damage / 100;//50% reduction to physical ranged attacks } + if (sc->data[SC_SU_STOOP]) + damage -= damage * 90 / 100; + // Compressed code, fixed by map.h [Epoque] if (src->type == BL_MOB) { const struct mob_data *md = BL_UCCAST(BL_MOB, src); @@ -3176,6 +3206,19 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam status_change_end(bl, SC_KYRIE, INVALID_TIMER); } + if ((sce = sc->data[SC_TUNAPARTY]) != NULL && damage > 0) { + clif->specialeffect(bl, 336, AREA); + sce->val2 -= (int)cap_value(damage, INT_MIN, INT_MAX); + if (sce->val2 >= 0) { + damage = 0; + } else { + damage = -sce->val2; + } + if (sce->val2 <= 0) { + status_change_end(bl, SC_TUNAPARTY, INVALID_TIMER); + } + } + if( sc->data[SC_MEIKYOUSISUI] && rnd()%100 < 40 ) // custom value damage = 0; @@ -3676,6 +3719,12 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //Damage calculation from iRO wiki. [Jobbie] ad.damage = status->get_lv(src) * 10 + sstatus->int_; break; + /** + * Summoner + */ + case SU_SV_ROOTTWIST_ATK: + ad.damage = 100; + break; default: { unsigned int skillratio = 100; //Skill dmg modifiers. MATK_ADD( status->get_matk(src, 2) ); @@ -5199,8 +5248,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if (hd != NULL) ATK_ADD(hd->homunculus.spiritball * 3); } + if ((wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) { + if (sd != NULL && pc->checkskill(sd, SU_POWEROFLIFE) > 0) { + if (pc->checkskill(sd, SU_SCAROFTAROU) == 5 && pc->checkskill(sd, SU_PICKYPECK) == 5 && pc->checkskill(sd, SU_ARCLOUSEDASH) == 5 && pc->checkskill(sd, SU_LUNATICCARROTBEAT) == 5) { + ATK_ADDRATE(20); + } + } + } } + switch (skill_id) { case AS_SONICBLOW: if (sc && sc->data[SC_SOULLINK] && @@ -5263,6 +5320,9 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if( sc && sc->data[SC_MTF_RANGEATK] ) ATK_ADDRATE(sc->data[SC_MTF_RANGEATK]->val1);// temporary it should be 'bonus.long_attack_atk_rate' #endif + if (sc != NULL && sc->data[SC_ARCLOUSEDASH] != NULL && sc->data[SC_ARCLOUSEDASH]->val4 != 0) { + ATK_ADDRATE(sc->data[SC_ARCLOUSEDASH]->val4); + } if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) ATK_ADDRATE(-i); @@ -7258,6 +7318,7 @@ static const struct battle_data { { "save_body_style", &battle_config.save_body_style, 0, 0, 1, }, { "player_warp_keep_direction", &battle_config.player_warp_keep_direction, 0, 0, 1, }, { "atcommand_levelup_events", &battle_config.atcommand_levelup_events, 0, 0, 1, }, + { "max_summoner_parameter", &battle_config.max_summoner_parameter, 120, 10, 10000, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index ebfa0e305..7e7048a38 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -544,6 +544,8 @@ struct Battle_Config { int player_warp_keep_direction; int atcommand_levelup_events; // Enable atcommands trigger level up events for NPCs + + int max_summoner_parameter; // Summoner Max Stats }; /* criteria for battle_config.idletime_critera */ diff --git a/src/map/clif.c b/src/map/clif.c index b92c3185f..424d94205 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9819,11 +9819,9 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd) __attribute__((non void clif_parse_QuitGame(int fd, struct map_session_data *sd) { /* Rovert's prevent logout option fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && - (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) - { + if (!sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && !sd->sc.data[SC_SUHIDE] && + (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout)) { sockt->eof(fd); - clif->disconnect_ack(sd, 0); } else { clif->disconnect_ack(sd, 1); @@ -10055,7 +10053,7 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) { int emoticon = RFIFOB(fd,packet_db[RFIFOW(fd,0)].pos[0]); - if (battle_config.basic_skill_check == 0 || pc->checkskill(sd, NV_BASIC) >= 2) { + if (battle_config.basic_skill_check == 0 || pc->check_basicskill(sd, 2)) { if (emoticon == E_MUTE) {// prevent use of the mute emote [Valaris] clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 1); return; @@ -10115,7 +10113,8 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, sd->sc.data[SC_TRICKDEAD] || (sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) || sd->sc.data[SC_BLADESTOP] || - sd->sc.data[SC_DEEP_SLEEP] ) + sd->sc.data[SC_DEEP_SLEEP] || + sd->sc.data[SC_SUHIDE] ) ) return; @@ -10155,7 +10154,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, } break; case 0x02: // sitdown - if (battle_config.basic_skill_check && pc->checkskill(sd, NV_BASIC) < 3) { + if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 3)) { clif->skill_fail(sd, 1, USESKILL_FAIL_LEVEL, 2); break; } @@ -10240,7 +10239,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) { case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ if (!sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] - && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] + && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && !sd->sc.data[SC_SUHIDE] && (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { //Send to char-server for character selection. @@ -10428,6 +10427,7 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd) sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_BLADESTOP] || sd->sc.data[SC_CLOAKINGEXCEED] || + sd->sc.data[SC_SUHIDE] || pc_ismuted(&sd->sc, MANNER_NOITEM) ) ) break; @@ -10760,7 +10760,7 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) if (pc_ismuted(&sd->sc, MANNER_NOROOM)) return; - if(battle_config.basic_skill_check && pc->checkskill(sd,NV_BASIC) < 4) { + if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) { clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,3); return; } @@ -10877,7 +10877,7 @@ void clif_parse_TradeRequest(int fd,struct map_session_data *sd) { return; } - if( battle_config.basic_skill_check && pc->checkskill(sd,NV_BASIC) < 1) { + if( battle_config.basic_skill_check && !pc->check_basicskill(sd, 1)) { clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,0); return; } @@ -11923,7 +11923,7 @@ void clif_parse_CreateParty(int fd, struct map_session_data *sd) clif->message(fd, msg_fd(fd,227)); // Party modification is disabled in this map. return; } - if( battle_config.basic_skill_check && pc->checkskill(sd,NV_BASIC) < 7 ) { + if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 7)) { clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,4); return; } @@ -11945,7 +11945,7 @@ void clif_parse_CreateParty2(int fd, struct map_session_data *sd) clif->message(fd, msg_fd(fd,227)); // Party modification is disabled in this map. return; } - if( battle_config.basic_skill_check && pc->checkskill(sd,NV_BASIC) < 7 ) { + if (battle_config.basic_skill_check && !pc->check_basicskill(sd, 7)) { clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,4); return; } diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 2e44393fe..97f302b80 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -437,6 +437,9 @@ void itemdb_jobid2mapid(uint64 *bclass, int job_id, bool enable) case JOB_REBELLION: mask[1] = 1ULL << MAPID_GUNSLINGER; break; + case JOB_SUMMONER: + mask[0] = 1ULL << MAPID_SUMMONER; + break; // Other Classes case JOB_GANGSI: //Bongun/Munak mask[0] = 1ULL << MAPID_GANGSI; @@ -538,6 +541,8 @@ void itemdb_jobmask2mapid(uint64 *bclass, uint64 jobmask) bclass[1] |= 1ULL<<MAPID_NINJA; if (jobmask & 1ULL<<30) //Rebellion bclass[1] |= 1ULL<<MAPID_GUNSLINGER; + if (jobmask & 1ULL<<31) //Summoner + bclass[0] |= 1ULL<<MAPID_SUMMONER; } void create_dummy_data(void) diff --git a/src/map/itemdb.h b/src/map/itemdb.h index d33805174..16dca9e58 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -54,6 +54,7 @@ enum item_itemid { ITEMID_WHITE_POTION = 504, ITEMID_BLUE_POTION = 505, ITEMID_APPLE = 512, + ITEMID_CARROT = 515, ITEMID_HOLY_WATER = 523, ITEMID_PUMPKIN = 535, ITEMID_RED_SLIM_POTION = 545, @@ -113,6 +114,7 @@ enum item_itemid { ITEMID_GOLD_KEY77 = 7782, ITEMID_SILVER_KEY77 = 7783, ITEMID_TRAP_ALLOY = 7940, + ITEMID_CATNIP_FRUIT = 11602, ITEMID_RED_POUCH_OF_SURPRISE = 12024, ITEMID_BLOODY_DEAD_BRANCH = 12103, ITEMID_PORING_BOX = 12109, diff --git a/src/map/map.c b/src/map/map.c index 0a60a92b4..4eebafde0 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -337,6 +337,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { //status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); + status_change_end(bl, SC_SU_STOOP, INVALID_TIMER); if (sc && sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER); diff --git a/src/map/map.h b/src/map/map.h index 723691971..c186dab4a 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -88,6 +88,7 @@ enum { MAPID_XMAS, MAPID_SUMMER, MAPID_GANGSI, + MAPID_SUMMONER, //2-1 Jobs MAPID_SUPER_NOVICE = JOBL_2_1|0x0, MAPID_KNIGHT, diff --git a/src/map/packets.h b/src/map/packets.h index 8b0a733c7..3dc23cb24 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -2930,6 +2930,140 @@ packet(0x96e,-1,clif->ackmergeitems); packet(0x0980,7,clif->pSelectCart); // CZ_SELECTCART #endif +// 2015-10-01bRagexeRE +#if PACKETVER >= 20151001 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); +// packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); +// packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x0860,36,clif->pStoragePassword,0); +#endif + +// 2015-10-29aRagexe +#if PACKETVER >= 20151029 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x0860,36,clif->pStoragePassword,0); + packet(0x0a39,36); +#endif + +// 2015-11-04aRagexe +#if PACKETVER >= 20151104 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0363,5,clif->pWalkToXY,2); + packet(0x0886,6,clif->pTickSend,2); + packet(0x0928,5,clif->pChangeDir,2,4); + packet(0x0964,6,clif->pTakeItem,2); + packet(0x0437,6,clif->pDropItem,2,4); + packet(0x088B,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x0887,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0815,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0436,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x023B,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0811,18,clif->pPartyBookingRegisterReq,2,4,6); + packet(0x0939,8); // CZ_JOIN_BATTLE_FIELD + packet(0x093A,-1,clif->pItemListWindowSelected,2,4,8,12); + packet(0x0360,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x08A5,26,clif->pPartyInvite2,2); + packet(0x08A3,4); // CZ_GANGSI_RANK CZ_GANGSI_RANK + packet(0x07EC,26,clif->pFriendsListAdd,2); + packet(0x088D,5,clif->pHomMenu,2,4); + packet(0x0940,36,clif->pStoragePassword,2,4,20); + packet(0x0a39,36); +#endif + +// 2015-12-16aRagexe +#if PACKETVER >= 20151216 + packet(0x089D,7,clif->pActionRequest,2,6); + packet(0x0968,10,clif->pUseSkillToId,2,4,6); + packet(0x08A2,5,clif->pWalkToXY,2); + packet(0x085B,6,clif->pTickSend,2); + packet(0x022D,5,clif->pChangeDir,2,4); + packet(0x08A9,6,clif->pTakeItem,2); + packet(0x0966,6,clif->pDropItem,2,4); + packet(0x08AC,8,clif->pMoveToKafra,2,4); + packet(0x0864,8,clif->pMoveFromKafra,2,4); + packet(0x0865,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0874,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x088B,6,clif->pGetCharNameRequest,2); + packet(0x089E,6,clif->pSolveCharName,2); + packet(0x0436,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0960,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0944,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0954,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0361,6,clif->pReqClickBuyingStore,2); + packet(0x083C,2,clif->pReqCloseBuyingStore,0); + packet(0x0870,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + packet(0x086A,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0949,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0947,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x086E,26,clif->pPartyInvite2,2); + packet(0x0364,4); // CZ_GANGSI_RANK + packet(0x091D,26,clif->pFriendsListAdd,2); + packet(0x0362,5,clif->pHomMenu,2,4); + packet(0x0885,36,clif->pStoragePassword,0); +#endif + /* PacketKeys: http://herc.ws/board/topic/1105-hercules-wpe-free-june-14th-patch/ */ #if PACKETVER >= 20110817 packetKeys(0x053D5CED,0x3DED6DED,0x6DED6DED); /* Thanks to Shakto */ @@ -3175,6 +3309,22 @@ packet(0x96e,-1,clif->ackmergeitems); packetKeys(0x62C86D09,0x75944F17,0x112C133D); /* Dastgir */ #endif +#if PACKETVER >= 20151001 + packetKeys(0x5CFF4561,0x32514AD1,0x06D126D1); /* Dastgir */ +#endif + +#if PACKETVER >= 20151029 + packetKeys(0x45B945B9,0x45B945B9,0x45B945B9); /* Dastgir */ +#endif + +#if PACKETVER >= 20151104 + packetKeys(0x4C17382A,0x7ED174C9,0x29961E4F); /* ossi0110 */ +#endif + +#if PACKETVER >= 20151216 + packetKeys(0x25DD643D,0x61AC39DE,0x77A8206D); /* Dastgir */ +#endif + #if defined(OBFUSCATIONKEY1) && defined(OBFUSCATIONKEY2) && defined(OBFUSCATIONKEY3) packetKeys(OBFUSCATIONKEY1,OBFUSCATIONKEY2,OBFUSCATIONKEY3); #endif diff --git a/src/map/pc.c b/src/map/pc.c index 0674f0137..bfd6c0ea5 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1749,7 +1749,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) sd->sktree.second = sd->sktree.third = 0; // limit 1st class and above to novice job levels - if(skill_point < novice_skills) { + if(skill_point < novice_skills && (sd->class_&MAPID_BASEMASK) != MAPID_SUMMONER) { c = MAPID_NOVICE; } // limit 2nd class and above to first class job levels (super novices are exempt) @@ -4965,6 +4965,7 @@ int pc_useitem(struct map_session_data *sd,int n) { sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC_COLD] || + sd->sc.data[SC_SUHIDE] || pc_ismuted(&sd->sc, MANNER_NOITEM) )) return 0; @@ -5881,6 +5882,7 @@ int pc_jobid2mapid(unsigned short b_class) case JOB_XMAS: return MAPID_XMAS; case JOB_SUMMER: return MAPID_SUMMER; case JOB_GANGSI: return MAPID_GANGSI; + case JOB_SUMMONER: return MAPID_SUMMONER; //2-1 Jobs case JOB_SUPER_NOVICE: return MAPID_SUPER_NOVICE; case JOB_KNIGHT: return MAPID_KNIGHT; @@ -6023,6 +6025,7 @@ int pc_mapid2jobid(unsigned short class_, int sex) case MAPID_XMAS: return JOB_XMAS; case MAPID_SUMMER: return JOB_SUMMER; case MAPID_GANGSI: return JOB_GANGSI; + case MAPID_SUMMONER: return JOB_SUMMONER; //2-1 Jobs case MAPID_SUPER_NOVICE: return JOB_SUPER_NOVICE; case MAPID_KNIGHT: return JOB_KNIGHT; @@ -6362,6 +6365,9 @@ const char* job_name(int class_) case JOB_REBELLION: return msg_txt(655); + case JOB_SUMMONER: + return msg_txt(669); + default: return msg_txt(620); // "Unknown Job" } @@ -6487,6 +6493,7 @@ int pc_check_job_name(const char *name) { { "Kagerou", JOB_KAGEROU }, { "Oboro", JOB_OBORO }, { "Rebellion", JOB_REBELLION }, + { "Summoner", JOB_SUMMONER }, }; nullpo_retr(-1, name); @@ -7398,6 +7405,9 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) ) homun->vaporize(sd, HOM_ST_REST); + + if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE))) + status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER); } for( i = 1; i < MAX_SKILL; i++ ) { @@ -7422,7 +7432,9 @@ int pc_resetskill(struct map_session_data* sd, int flag) } // do not reset basic skill - if( skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) + if (skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE) + continue; + if (skill_id == SU_BASIC_SKILL && (sd->class_&MAPID_BASEMASK) != MAPID_SUMMONER) continue; if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) @@ -8396,6 +8408,9 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) if( sd->sc.data[SC_EXTREMITYFIST2] ) sp = 0; #endif + if (sd->sc.data[SC_BITESCAR]) { + hp = 0; + } } return status->heal(&sd->bl, hp, sp, 1); @@ -8618,6 +8633,9 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN)) homun->vaporize(sd, HOM_ST_REST); + if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE))) + status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER); + if(sd->status.manner < 0) clif->changestatus(sd,SP_MANNER,sd->status.manner); @@ -11644,7 +11662,8 @@ bool pc_db_checkid(unsigned int class_) || (class_ >= JOB_BABY_RUNE && class_ <= JOB_BABY_MECHANIC2 ) || (class_ >= JOB_SUPER_NOVICE_E && class_ <= JOB_SUPER_BABY_E ) || (class_ >= JOB_KAGEROU && class_ <= JOB_OBORO ) - || (class_ >= JOB_REBELLION && class_ < JOB_MAX ); + || (class_ == JOB_REBELLION) + || (class_ >= JOB_SUMMONER && class_ < JOB_MAX ); } /** @@ -11662,6 +11681,18 @@ int pc_have_magnifier(struct map_session_data *sd) } /** + * Checks if player have basic skills learned. + * @param sd Player Data + * @param level Required Level of Novice Skill + * @return bool true, if requirement is satisfied + */ +bool pc_check_basicskill(struct map_session_data *sd, int level) { + if (pc->checkskill(sd, NV_BASIC) >= level || pc->checkskill(sd, SU_BASIC_SKILL)) + return true; + return false; +} + +/** * Verifies a chat message, searching for atcommands, checking if the sender * character can chat, and updating the idle timer. * @@ -12117,4 +12148,6 @@ void pc_defaults(void) { pc->update_idle_time = pc_update_idle_time; pc->have_magnifier = pc_have_magnifier; + + pc->check_basicskill = pc_check_basicskill; } diff --git a/src/map/pc.h b/src/map/pc.h index fd446813f..5d1404b2a 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -635,6 +635,7 @@ END_ZEROED_BLOCK; #define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle->bc->natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ( \ + ((sd)->class_&MAPID_BASEMASK) == MAPID_SUMMONER ? battle->bc->max_summoner_parameter : \ ( ((sd)->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO \ || ((sd)->class_&MAPID_UPPERMASK) == MAPID_REBELLION \ || ((sd)->class_&MAPID_THIRDMASK) == MAPID_SUPER_NOVICE_E \ @@ -1094,6 +1095,7 @@ END_ZEROED_BLOCK; /* End */ bool (*process_chat_message) (struct map_session_data *sd, const char *message); void (*check_supernovice_call) (struct map_session_data *sd, const char *message); + bool (*check_basicskill) (struct map_session_data *sd, int level); }; #ifdef HERCULES_CORE diff --git a/src/map/script.c b/src/map/script.c index d1aee29bf..2a39bc832 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -6721,13 +6721,16 @@ BUILDIN(percentheal) } sd = script->rid2sd(st); - if( sd == NULL ) + if (sd == NULL) return true; #ifdef RENEWAL if( sd->sc.data[SC_EXTREMITYFIST2] ) sp = 0; #endif - pc->percentheal(sd,hp,sp); + if (sd->sc.data[SC_BITESCAR]) { + hp = 0; + } + pc->percentheal(sd, hp, sp); return true; } diff --git a/src/map/skill.c b/src/map/skill.c index 2559a7a5b..4c57fbc56 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -131,7 +131,7 @@ int skill_get_index (uint16 skill_id) skill_id = (1077) + skill_id - 2201; else if ( skill_id < 3036 ) // 2549 - 3000 are empty - 1020+57+348 skill_id = (1425) + skill_id - 3001; - else if ( skill_id < 5019 ) // 3036 - 5000 are empty - 1020+57+348+35 + else if ( skill_id < 5044 ) // 3036 - 5000 are empty - 1020+57+348+35 skill_id = (1460) + skill_id - 5001; else ShowWarning("skill_get_index: skill id '%d' is not being handled!\n",skill_id); @@ -365,7 +365,10 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk nullpo_ret(src); - switch( skill_id ) { + switch (skill_id) { + case SU_TUNABELLY: + hp = status_get_max_hp(target) * ((20 * skill_lv) - 10) / 100; + break; case BA_APPLEIDUN: #ifdef RENEWAL hp = 100+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery @@ -397,6 +400,11 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk hp += hp * skill2_lv * 2 / 100; else if (src->type == BL_HOM && (skill2_lv = homun->checkskill(BL_UCAST(BL_HOM, src), HLIF_BRAIN)) > 0) hp += hp * skill2_lv * 2 / 100; + if (sd != NULL && ((skill2_lv = pc->checkskill(sd, SU_POWEROFSEA)) > 0)) { + hp += hp * 10 / 100; + if (pc->checkskill(sd, SU_TUNABELLY) == 5 && pc->checkskill(sd, SU_TUNAPARTY) == 5 && pc->checkskill(sd, SU_BUNCHOFSHRIMP) == 5 && pc->checkskill(sd, SU_FRESHSHRIMP) == 5) + hp += hp * 20 / 100; + } break; } @@ -466,8 +474,11 @@ int can_copy (struct map_session_data *sd, uint16 skill_id, struct block_list* b skill_id == MER_INCAGI || skill_id == MER_BLESSING)) return 0; - // Couldn't preserve 3rd Class skills except only when using Reproduce skill. [Jobbie] - if( !(sd->sc.data[SC__REPRODUCE]) && ((skill_id >= RK_ENCHANTBLADE && skill_id <= LG_OVERBRAND_PLUSATK) || (skill_id >= RL_GLITTERING_GREED && skill_id <= OB_AKAITSUKI) || (skill_id >= GC_DARKCROW && skill_id <= NC_MAGMA_ERUPTION_DOTDAMAGE))) + // Couldn't preserve 3rd Class/Summoner skills except only when using Reproduce skill. [Jobbie] + if (!(sd->sc.data[SC__REPRODUCE]) && + ((skill_id >= RK_ENCHANTBLADE && skill_id <= LG_OVERBRAND_PLUSATK) || + (skill_id >= RL_GLITTERING_GREED && skill_id <= OB_AKAITSUKI) || + (skill_id >= GC_DARKCROW && skill_id <= SU_FRESHSHRIMP))) return 0; // Reproduce will only copy skills according on the list. [Jobbie] else if( sd->sc.data[SC__REPRODUCE] && !skill->dbs->reproduce_db[skill->get_index(skill_id)] ) @@ -1415,6 +1426,25 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case MH_XENO_SLASHER: sc_start2(src, bl, SC_BLOODING, 10 * skill_lv, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); break; + /** + * Summoner + */ + case SU_SCRATCH: + sc_start2(src, bl, SC_BLOODING, (skill_lv * 3), skill_lv, src->id, skill->get_time(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_SV_STEMSPEAR: + sc_start2(src, bl, SC_BLOODING, 10, skill_lv, src->id, skill->get_time(skill_id, skill_lv)); + break; + case SU_CN_METEOR: + sc_start(src, bl, SC_CURSE, 10, skill_lv, skill->get_time2(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_SCAROFTAROU: + sc_start(src, bl, SC_STUN, 10, skill_lv, skill->get_time2(skill_id, skill_lv)); // TODO: What's the chance/time? + break; + case SU_LUNATICCARROTBEAT: + if (skill->area_temp[3] == 1) + sc_start(src, bl, SC_STUN, 10, skill_lv, skill_get_time(skill_id, skill_lv)); // TODO: What's the chance/time? + break; default: skill->additional_effect_unknown(src, bl, &skill_id, &skill_lv, &attack_type, &dmg_lv, &tick); break; @@ -2088,6 +2118,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int int skill_blown(struct block_list* src, struct block_list* target, int count, int8 dir, int flag) { int dx = 0, dy = 0; + struct status_change *tsc = status->get_sc(target); nullpo_ret(src); @@ -2135,6 +2166,9 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in dy = -diry[dir]; } + if (tsc != NULL && tsc->data[SC_SU_STOOP]) // Any knockback will cancel it. + status_change_end(target, SC_SU_STOOP, INVALID_TIMER); + return unit->blown(target, dx, dy, count, flag); // send over the proper flag } @@ -3442,7 +3476,8 @@ int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { break; switch( skl->skill_id ) { case WZ_METEOR: - if( skl->type >= 0 ) { + case SU_CN_METEOR: + if (skl->type >= 0) { int x = skl->type>>16, y = skl->type&0xFFFF; if( path->search_long(NULL, src, src->m, src->x, src->y, x, y, CELL_CHKWALL) ) skill->unitsetting(src,skl->skill_id,skl->skill_lv,x,y,skl->flag); @@ -3961,7 +3996,17 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; - //Splash attack skills. + case SU_BITE: + skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + if (status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); + break; + + case SU_PICKYPECK: + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + break; + + // Splash attack skills. case AS_GRIMTOOTH: case MC_CARTREVOLUTION: case NPC_SPLASHATTACK: @@ -4014,7 +4059,9 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case KO_BAKURETSU: case GN_ILLUSIONDOPING: case MH_XENO_SLASHER: - if( flag&1 ) {//Recursive invocation + case SU_SCRATCH: + case SU_LUNATICCARROTBEAT: + if (flag&1) { //Recursive invocation // skill->area_temp[0] holds number of targets in area // skill->area_temp[1] holds the id of the original target // skill->area_temp[2] counts how many targets have already been processed @@ -4029,15 +4076,19 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 break; heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); - if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) { + if (skill_id == NPC_VAMPIRE_GIFT && heal > 0) { clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); status->heal(src,heal,0,0); } + if (skill_id == SU_SCRATCH && status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); } else { switch ( skill_id ) { case NJ_BAKUENRYU: case LG_EARTHDRIVE: case GN_CARTCANNON: + case SU_SCRATCH: + case SU_LUNATICCARROTBEAT: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case SR_TIGERCANNON: @@ -4056,13 +4107,19 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->area_temp[0] = 0; skill->area_temp[1] = bl->id; skill->area_temp[2] = 0; - if( skill_id == WL_CRIMSONROCK ) { + if (skill_id == WL_CRIMSONROCK) { skill->area_temp[4] = bl->x; skill->area_temp[5] = bl->y; } + if (skill_id == SU_LUNATICCARROTBEAT) { + skill->area_temp[3] = 0; + } - if( skill_id == NC_VULCANARM ) - if (sd) pc->overheat(sd,1); + if (skill_id == NC_VULCANARM) { + if (sd != NULL) { + pc->overheat(sd,1); + } + } // if skill damage should be split among targets, count them //SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets @@ -4072,6 +4129,15 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 // recursive invocation of skill->castend_damage_id() with flag|1 map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), skill->splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); + + if (sd && skill_id == SU_LUNATICCARROTBEAT) { + short item_idx = pc->search_inventory(sd, ITEMID_CARROT); + + if (item_idx >= 0) { + pc->delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_CONSUME); + skill->area_temp[3] = 1; + } + } } break; @@ -4881,6 +4947,15 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; + case SU_SV_STEMSPEAR: + skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + if (status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. + skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, (skill_id == SU_SV_STEMSPEAR) ? BF_MAGIC : BF_WEAPON, flag); + break; + case SU_SCAROFTAROU: + sc_start(src, bl, status->skill2sc(skill_id), 10, skill_lv, skill->get_time(skill_id, skill_lv)); // TODO: What's the activation chance for the effect? + break; + case 0:/* no skill - basic/normal attack */ if(sd) { if (flag & 3){ @@ -5018,6 +5093,8 @@ int skill_castend_id(int tid, int64 tick, int id, intptr_t data) ud->skilltimer=tid; return skill->castend_pos(tid,tick,id,data); case GN_WALLOFTHORN: + case SU_CN_POWDERING: + case SU_SV_ROOTTWIST: ud->skillx = target->x; ud->skilly = target->y; ud->skilltimer = tid; @@ -5480,6 +5557,10 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin * Arch Bishop **/ case AB_HIGHNESSHEAL: + /** + * Summoner + */ + case SU_TUNABELLY: { int heal = skill->calc_heal(src, bl, (skill_id == AB_HIGHNESSHEAL)?AL_HEAL:skill_id, (skill_id == AB_HIGHNESSHEAL)?10:skill_lv, true); int heal_get_jobexp; @@ -5509,6 +5590,9 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin else if (tsc->data[SC_BERSERK]) heal = 0; //Needed so that it actually displays 0 when healing. } + if (skill_id == AL_HEAL) { + status_change_end(bl, SC_BITESCAR, INVALID_TIMER); + } clif->skill_nodamage (src, bl, skill_id, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) heal = ~heal + 1; @@ -5888,6 +5972,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case PR_KYRIE: case MER_KYRIE: + case SU_TUNAPARTY: clif->skill_nodamage(bl, bl, skill_id, -1, sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; @@ -6004,9 +6089,18 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case RK_ABUNDANCE: case RK_CRUSHSTRIKE: case ALL_ODINS_POWER: + case SU_FRESHSHRIMP: + case SU_ARCLOUSEDASH: clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; + // Works just like the above list of skills, except animation caused by + // status must trigger AFTER the skill cast animation or it will cancel + // out the status's animation. + case SU_STOOP: + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + break; case KN_AUTOCOUNTER: sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); skill->addtimerskill(src, tick + 100, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); @@ -6661,7 +6755,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin status_change_end(bl, SC_SILENCE, INVALID_TIMER); status_change_end(bl, SC_BLIND, INVALID_TIMER); status_change_end(bl, SC_CONFUSION, INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(bl, SC_BITESCAR, INVALID_TIMER); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); break; case TF_DETOXIFY: @@ -8923,6 +9018,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case LG_TRAMPLE: clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, BDT_SKILL); map->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); + status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER); break; case LG_REFLECTDAMAGE: @@ -9452,6 +9548,26 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, 0, 1, skill_id, -2, BDT_SKILL); break; + case SU_HIDE: + if (tsce != NULL) { + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + status_change_end(bl, type, INVALID_TIMER); + map->freeblock_unlock(); + return 0; + } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + break; + break; + + case SU_BUNCHOFSHRIMP: + if (sd == NULL || sd->status.party_id == 0 || flag&1) { + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + } else if (sd != NULL) { + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + } + break; + case GM_SANDMAN: if( tsc ) { if( tsc->opt1 == OPT1_SLEEP ) @@ -10352,6 +10468,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case HW_GANBANTEIN: case LG_EARTHDRIVE: case SC_ESCAPE: + case SU_CN_METEOR: break; //Effect is displayed on respective switch case. default: skill->castend_pos2_effect_unknown(src, &x, &y, &skill_id, &skill_lv, &tick, &flag); @@ -10540,7 +10657,9 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SO_ELEMENTAL_SHIELD: case RL_B_TRAP: case MH_XENO_SLASHER: - flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). + case SU_CN_POWDERING: + case SU_SV_ROOTTWIST: + flag |= 1; // Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). FALLTHROUGH case GS_GROUNDDRIFT: //Ammo should be deleted right away. if ( skill_id == WM_SEVERE_RAINSTORM ) @@ -10593,11 +10712,24 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui break; case WZ_METEOR: + case SU_CN_METEOR: { int area = skill->get_splash(skill_id, skill_lv); short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0; int i; +#if 0 + // The Meteor should inflict curse if Catnip fruit is consumed. + // Currently Catnip fruit is added as requirement. + if (sd && skill_id == SU_CN_METEOR) { + short item_idx = pc->search_inventory(sd, ITEMID_CATNIP_FRUIT); + if (item_idx >= 0) { + pc->delitem(sd, item_idx, 1, 0, 1, LOG_TYPE_SKILL); + flag |= 1; + } + } +#endif + for( i = 0; i < 2 + (skill_lv>>1); i++ ) { // Creates a random Cell in the Splash Area tmpx = x - area + rnd()%(area * 2 + 1); @@ -10649,6 +10781,19 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } status_change_end(src, SC_HIDING, INVALID_TIMER); break; + case SU_LOPE: + { + if (map->list[src->m].flag.noteleport && !(map->list[src->m].flag.battleground || map_flag_gvg2(src->m))) { + x = src->x; + y = src->y; + } + clif->skill_nodamage(src, src, SU_LOPE, skill_lv, 1); + if(!map->count_oncell(src->m, x, y, BL_PC | BL_NPC | BL_MOB, 0) && map->getcell(src->m, src, x, y, CELL_CHKREACH)) { + clif->slide(src, x, y); + unit->movepos(src, x, y, 1, 0); + } + } + break; case AM_SPHEREMINE: case AM_CANNIBALIZE: { @@ -11232,7 +11377,7 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ nullpo_retr(NULL, st); sc = status->get_sc(src); // for traps, firewall and fogwall - celest - switch( skill_id ) { + switch (skill_id) { case SO_ELEMENTAL_SHIELD: val2 = 300 * skill_lv + 65 * (st->int_ + status->get_lv(src)) + st->max_sp; break; @@ -11969,6 +12114,13 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick sc_start(ss, bl, SC_VOLCANIC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); break; + case UNT_CATNIPPOWDER: + if (sg->src_id == bl->id || (status_get_mode(bl)&MD_BOSS)) + break; // Does not affect the caster or Boss. + if (sce == NULL && battle->check_target(&src->bl, bl, BCT_ENEMY) > 0) + sc_start(ss, bl, type, 100, sg->skill_lv, skill->get_time(sg->skill_id, sg->skill_lv)); + break; + case UNT_GD_LEADERSHIP: case UNT_GD_GLORYWOUNDS: case UNT_GD_SOULCOLD: @@ -12169,6 +12321,9 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 map->freeblock_unlock(); } break; + case WZ_HEAVENDRIVE: + status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER); + break; /** * The storm gust counter was dropped in renewal **/ @@ -12178,12 +12333,12 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 tsc->sg_counter++; //SG hit counter. if (skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0) <= 0 && tsc) tsc->sg_counter=0; //Attack absorbed. - break; + break; #endif case GS_DESPERADO: if (rnd()%100 < src->val1) skill->attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); - break; + break; default: skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); } @@ -12753,6 +12908,30 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 status->change_start(ss, bl, SC_BLIND, rnd() % 100 > sg->skill_lv * 10, sg->skill_lv, sg->skill_id, 0, 0, skill->get_time2(sg->skill_id, sg->skill_lv), SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE); break; + case UNT_SV_ROOTTWIST: + if (status_get_mode(bl)&MD_BOSS) { + break; + } + if (tsc) { + if (!sg->val2) { + int sec = skill->get_time(sg->skill_id, sg->skill_lv); + + if (sc_start2(ss, bl, type, 100, sg->skill_lv, sg->group_id, sec)) { + const struct TimerData* td = ((tsc->data[type])? timer->get(tsc->data[type]->timer) : NULL); + + if (td != NULL) + sec = DIFF_TICK32(td->tick, tick); + clif->fixpos(bl); + sg->val2 = bl->id; + } else { // Couldn't trap it? + sec = 7000; + } + sg->limit = DIFF_TICK32(tick, sg->tick) + sec; + } else if (tsc->data[type] && bl->id == sg->val2) { + skill->attack(skill->get_type(SU_SV_ROOTTWIST_ATK), ss, &src->bl, bl, SU_SV_ROOTTWIST_ATK, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION); + } + } + break; default: skill->unit_onplace_timer_unknown(src, bl, &tick); break; @@ -13342,7 +13521,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case SG_FUSION: case RA_WUGDASH: case KO_YAMIKUMO: - if( sc && sc->data[status->skill2sc(skill_id)] ) + case SU_HIDE: + if (sc && sc->data[status->skill2sc(skill_id)]) return 1; FALLTHROUGH default: @@ -14554,7 +14734,8 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 case TK_READYTURN: case SG_FUSION: case KO_YAMIKUMO: - if( sc && sc->data[status->skill2sc(skill_id)] ) + case SU_HIDE: + if (sc && sc->data[status->skill2sc(skill_id)]) return req; /* Fall through */ default: diff --git a/src/map/skill.h b/src/map/skill.h index c7761b082..b27d7ac3a 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1365,6 +1365,10 @@ enum e_skill { ITEM_OPTION_SPLASH_ATTACK, GM_FORCE_TRANSFER, GM_WIDE_RESURRECTION, + ALL_NIFLHEIM_RECALL, + ALL_PRONTERA_RECALL, + ALL_GLASTHEIM_RECALL, + ALL_THANATOS_RECALL, GC_DARKCROW = 5001, RA_UNLIMIT, @@ -1382,6 +1386,47 @@ enum e_skill { ALL_FULL_THROTTLE, NC_MAGMA_ERUPTION_DOTDAMAGE, + /** Summoner */ + SU_BASIC_SKILL = 5018, + SU_BITE, + SU_HIDE, + SU_SCRATCH, + SU_STOOP, + SU_LOPE, + SU_SPRITEMABLE, + SU_POWEROFLAND, + SU_SV_STEMSPEAR, + SU_CN_POWDERING, + SU_CN_METEOR, + SU_SV_ROOTTWIST, + SU_SV_ROOTTWIST_ATK, + SU_POWEROFLIFE, + SU_SCAROFTAROU, + SU_PICKYPECK, + SU_PICKYPECK_DOUBLE_ATK, + SU_ARCLOUSEDASH, + SU_LUNATICCARROTBEAT, + SU_POWEROFSEA, + SU_TUNABELLY, + SU_TUNAPARTY, + SU_BUNCHOFSHRIMP, + SU_FRESHSHRIMP, + SU_CN_METEOR2, + SU_LUNATICCARROTBEAT2, + SU_SOULATTACK, + SU_POWEROFFLOCK, + SU_SVG_SPIRIT, + SU_HISS, + SU_NYANGGRASS, + SU_GROOMING, + SU_PURRING, + SU_SHRIMPARTY, + SU_SPIRITOFLIFE, + SU_MEOWMEOW, + SU_SPIRITOFLAND, + SU_CHATTERING, + SU_SPIRITOFSEA, + HLIF_HEAL = 8001, HLIF_AVOID, HLIF_BRAIN, @@ -1651,6 +1696,9 @@ enum { UNT_B_TRAP, UNT_FIRE_RAIN, + UNT_CATNIPPOWDER, + UNT_SV_ROOTTWIST, + /** * Guild Auras **/ diff --git a/src/map/status.c b/src/map/status.c index 37efe1f93..46df84473 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -719,6 +719,24 @@ void initChangeTables(void) status->set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE ); status->set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT ); + /** + * Summoner + */ + status->set_sc(SU_HIDE, SC_SUHIDE, SI_SUHIDE, SCB_SPEED); + add_sc(SU_SCRATCH, SC_BLOODING); + status->set_sc(SU_STOOP, SC_SU_STOOP, SI_SU_STOOP, SCB_NONE); + status->set_sc(SU_FRESHSHRIMP, SC_FRESHSHRIMP, SI_FRESHSHRIMP, SCB_NONE); + add_sc(SU_SV_STEMSPEAR, SC_BLOODING); + status->set_sc(SU_CN_POWDERING, SC_CATNIPPOWDER, SI_CATNIPPOWDER, SCB_WATK | SCB_SPEED | SCB_REGEN); + add_sc(SU_CN_METEOR, SC_CURSE); + set_sc_with_vfx(SU_SV_ROOTTWIST, SC_SV_ROOTTWIST, SI_SV_ROOTTWIST, SCB_NONE); + add_sc(SU_SCAROFTAROU, SC_STUN ); + status->set_sc(SU_SCAROFTAROU, SC_BITESCAR, SI_BITESCAR, SCB_NONE); + status->set_sc(SU_ARCLOUSEDASH, SC_ARCLOUSEDASH, SI_ARCLOUSEDASH, SCB_AGI | SCB_SPEED); + add_sc(SU_LUNATICCARROTBEAT, SC_STUN); + status->set_sc(SU_TUNAPARTY, SC_TUNAPARTY, SI_TUNAPARTY, SCB_NONE); + status->set_sc(SU_BUNCHOFSHRIMP, SC_SHRIMP, SI_SHRIMP, SCB_BATK | SCB_MATK); + // Elemental Spirit summoner's 'side' status changes. status->set_sc( EL_CIRCLE_OF_FIRE , SC_CIRCLE_OF_FIRE_OPTION, SI_CIRCLE_OF_FIRE_OPTION, SCB_NONE ); status->set_sc( EL_FIRE_CLOAK , SC_FIRE_CLOAK_OPTION , SI_FIRE_CLOAK_OPTION , SCB_ALL ); @@ -997,6 +1015,9 @@ void initChangeTables(void) status->dbs->IconChangeTable[SC_MAGICAL_FEATHER] = SI_MAGICAL_FEATHER; status->dbs->IconChangeTable[SC_BLOSSOM_FLUTTERING] = SI_BLOSSOM_FLUTTERING; + // Summoner + status->dbs->IconChangeTable[SC_SPRITEMABLE] = SI_SPRITEMABLE; + // Other SC which are not necessarily associated to skills. status->dbs->ChangeFlagTable[SC_ATTHASTE_POTION1] |= SCB_ASPD; status->dbs->ChangeFlagTable[SC_ATTHASTE_POTION2] |= SCB_ASPD; @@ -1347,6 +1368,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(target, SC_SUHIDE, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4 && !sc->data[SC_LKCONCENTRATION]) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] @@ -1802,6 +1824,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin (sc->data[SC_TRICKDEAD] && skill_id != NV_TRICKDEAD) || (sc->data[SC_AUTOCOUNTER] && !flag && skill_id) || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF && skill_id != PA_GOSPEL) + || (sc->data[SC_SUHIDE] && skill_id != SU_HIDE) ) return 0; @@ -2381,7 +2404,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) //Give them all modes except these (useful for clones) bstatus->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); - bstatus->size = (sd->class_&JOBL_BABY)?SZ_SMALL:SZ_MEDIUM; + bstatus->size = (sd->class_&JOBL_BABY || (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER)?SZ_SMALL:SZ_MEDIUM; if (battle_config.character_size && (pc_isridingpeco(sd) || pc_isridingdragon(sd))) { //[Lupus] if (sd->class_&JOBL_BABY) { if (battle_config.character_size&SZ_BIG) @@ -2393,7 +2416,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) } bstatus->aspd_rate = 1000; bstatus->ele_lv = 1; - bstatus->race = RC_PLAYER; + bstatus->race = ((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER)?RC_BRUTE:RC_PLAYER; // Autobonus pc->delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),true); @@ -2696,6 +2719,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->dex += skill_lv; if((skill_lv = pc->checkskill(sd,RA_RESEARCHTRAP))>0) bstatus->int_ += skill_lv; + if ((pc->checkskill(sd,SU_POWEROFLAND)) > 0) + bstatus->int_ += 20; // Bonuses from cards and equipment as well as base stat, remember to avoid overflows. i = bstatus->str + sd->status.str + sd->param_bonus[0] + sd->param_equip[0]; @@ -2733,9 +2758,12 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->max_hp = (unsigned int)cap_value(i64, 0, INT_MAX); // Absolute modifiers from passive skills - if((skill_lv=pc->checkskill(sd,CR_TRUST))>0) + if ((skill_lv=pc->checkskill(sd,CR_TRUST)) > 0) bstatus->max_hp += skill_lv*200; + if ((pc->checkskill(sd,SU_SPRITEMABLE)) > 0) + bstatus->max_hp += 1000; + // Apply relative modifiers from equipment if(sd->hprate < 0) sd->hprate = 0; @@ -2768,6 +2796,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->max_sp += 200 + 20 * skill_lv; if( (skill_lv = pc->checkskill(sd,WM_LESSON)) > 0 ) bstatus->max_sp += 30 * skill_lv; + if ((pc->checkskill(sd,SU_SPRITEMABLE)) > 0) + bstatus->max_sp += 100; // Apply relative modifiers from equipment if(sd->sprate < 0) @@ -2840,6 +2870,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) sd->critical_rate = 0; if(sd->critical_rate != 100) bstatus->cri = bstatus->cri * sd->critical_rate/100; + if (pc->checkskill(sd, SU_POWEROFLIFE) > 0) + bstatus->cri += 20; if(sd->flee2_rate < 0) sd->flee2_rate = 0; @@ -2872,6 +2904,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->hit += 3*skill_lv; if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && (skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0) bstatus->hit += 2*skill_lv; + if (pc->checkskill(sd, SU_POWEROFLIFE) > 0) + bstatus->hit += 20; // ----- FLEE CALCULATION ----- @@ -2880,6 +2914,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->flee += skill_lv*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3); if((skill_lv=pc->checkskill(sd,MO_DODGE))>0) bstatus->flee += (skill_lv*3)>>1; + if (pc->checkskill(sd, SU_POWEROFLIFE) > 0) + bstatus->flee += 20; // ----- EQUIPMENT-DEF CALCULATION ----- // Apply relative modifiers from equipment @@ -3175,6 +3211,12 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) clif->updatestatus(sd,SP_CARTINFO); } + // Spirit Marble status activates automatically for a infinite + // amount of time when the skill is learned. Felt this was the + // best place to put this. [Rytech] + if (pc->checkskill(sd, SU_SPRITEMABLE)) + sc_start(&sd->bl, &sd->bl, SC_SPRITEMABLE, 100, 1, INFINITE_DURATION); + calculating = 0; return 0; @@ -3584,6 +3626,10 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str regen->rate.hp += regen->rate.hp * sc->data[SC_BUCHEDENOEL]->val1 / 100; regen->rate.sp += regen->rate.sp * sc->data[SC_BUCHEDENOEL]->val2 / 100; } + if (sc->data[SC_CATNIPPOWDER]) { + regen->rate.hp *= 2; + regen->rate.sp *= 2; + } } #define status_get_homstr(st, hd) ((st)->str + (hd)->homunculus.str_value) @@ -4581,9 +4627,12 @@ unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, if (sc->data[SC_2011RWC]) agi += sc->data[SC_2011RWC]->val1; - if(sc->data[SC_MARSHOFABYSS]) + if (sc->data[SC_MARSHOFABYSS]) agi -= agi * sc->data[SC_MARSHOFABYSS]->val2 / 100; + if (sc->data[SC_ARCLOUSEDASH]) + agi += sc->data[SC_ARCLOUSEDASH]->val2; + return (unsigned short)cap_value(agi,0,USHRT_MAX); } @@ -4916,6 +4965,9 @@ unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, if (sc->data[SC_STEAMPACK]) batk += sc->data[SC_STEAMPACK]->val1; + if (sc->data[SC_SHRIMP]) + batk += batk * sc->data[SC_SHRIMP]->val2 / 100; + return (unsigned short)cap_value(batk,0,USHRT_MAX); } @@ -5008,6 +5060,8 @@ unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, watk += watk * sc->data[SC_ANGRIFFS_MODUS]->val2/100; if( sc->data[SC_FLASHCOMBO] ) watk += sc->data[SC_FLASHCOMBO]->val2; + if (sc->data[SC_CATNIPPOWDER]) + watk -= watk * sc->data[SC_CATNIPPOWDER]->val2 / 100; return (unsigned short)cap_value(watk,0,USHRT_MAX); } @@ -5035,6 +5089,8 @@ unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 if(sc->data[SC_IZAYOI]) matk += 25 * sc->data[SC_IZAYOI]->val1; + if (sc->data[SC_SHRIMP]) + matk += matk * sc->data[SC_SHRIMP]->val2 / 100; return (unsigned short)cap_value(matk,0,USHRT_MAX); #else return 0; @@ -5721,6 +5777,8 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc if (sc->data[SC_DEC_AGI] || sc->data[SC_QUAGMIRE] || sc->data[SC_DONTFORGETME]) return 0; } + if (sc->data[SC_CATNIPPOWDER]) + val = max(val, sc->data[SC_CATNIPPOWDER]->val3); if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate > 0 ) // permanent item-based speedup val = max( val, sd->bonus.speed_rate + sd->bonus.speed_add_rate ); @@ -5771,6 +5829,8 @@ unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc val = max(val, sc->data[SC_MOVHASTE_HORSE]->val1); if( sd && sd->bonus.speed_rate + sd->bonus.speed_add_rate < 0 ) // permanent item-based speedup val = max( val, -(sd->bonus.speed_rate + sd->bonus.speed_add_rate) ); + if (sc->data[SC_ARCLOUSEDASH]) + val = max(val, sc->data[SC_ARCLOUSEDASH]->val3); speed_rate -= val; } @@ -7507,6 +7567,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t return 0; break; case SC_KYRIE: + case SC_TUNAPARTY: if (bl->type == BL_MOB) return 0; break; @@ -7770,12 +7831,12 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t case SC_OBLIVIONCURSE: case SC_LEECHESEND: - // Ranger Effects + // Ranger Effects case SC_WUGBITE: case SC_ELECTRICSHOCKER: case SC_MAGNETICFIELD: - // Masquerades + // Masquerades case SC__ENERVATION: case SC__GROOMY: case SC__LAZINESS: @@ -7786,7 +7847,9 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t // Other Effects case SC_VACUUM_EXTREME: case SC_NETHERWORLD: - + case SC_FRESHSHRIMP: + case SC_SV_ROOTTWIST: + case SC_BITESCAR: return 0; } } @@ -9744,6 +9807,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t if (!mob->db_checkid(val1)) val1 = MOBID_PORING; break; + case SC_SPRITEMABLE: case SC_ALL_RIDING: tick = INFINITE_DURATION; break; @@ -9754,6 +9818,36 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t **/ val2 = 20+(20*val1); break; + /** + * Summoner + */ + case SC_FRESHSHRIMP: + val4 = tick / (10000 - ((val1 - 1) * 1000)); + tick_time = 10000 - ((val1 - 1) * 1000); + if (val4 <= 0) // Prevents a negeative value from happening + val4 = 0; + break; + case SC_ARCLOUSEDASH: + val2 = 15 + 5 * val1; // AGI + val3 = 25; // Move speed increase + if (sd && (sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) + val4 = 10; // Ranged ATK increase + break; + case SC_TUNAPARTY: + val2 = (st->max_hp * (val1 * 10) / 100); // %Max HP to absorb + break; + case SC_BITESCAR: + val2 = 2 * val1; // MHP% damage + val4 = tick / 1000; + tick_time = 1000; + break; + case SC_SHRIMP: + val2 = 10; // BATK%, MATK% + break; + case SC_CATNIPPOWDER: + val2 = 50; // WATK%, MATK% + val3 = 25 * val1; // Move speed reduction + break; default: if (calc_flag == SCB_NONE && status->dbs->SkillChangeTable[type] == 0 && status->dbs->IconChangeTable[type] == 0) { //Status change with no calc, no icon, and no skill associated...? @@ -9966,6 +10060,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t case SC_NEEDLE_OF_PARALYZE: case SC_DEATHBOUND: case SC_NETHERWORLD: + case SC_SV_ROOTTWIST: unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS); break; case SC_ANKLESNARE: @@ -9980,6 +10075,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t case SC_CAMOUFLAGE: case SC_SIREN: case SC_ALL_RIDING: + case SC_SUHIDE: unit->stop_attack(bl); break; case SC_SILENCE: @@ -10823,10 +10919,11 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_NEUTRALBARRIER_MASTER: case SC_STEALTHFIELD_MASTER: - if( sce->val2 ) { + case SC_SV_ROOTTWIST: + if (sce->val2) { struct skill_unit_group* group = skill->id2group(sce->val2); sce->val2 = 0; - if( group ) /* might have been cleared before status ended, e.g. land protector */ + if (group) /* might have been cleared before status ended, e.g. land protector */ skill->del_unitgroup(group,ALC_MARK); } break; @@ -12018,6 +12115,19 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) return 0; } break; + case SC_FRESHSHRIMP: + if (--(sce->val4) >= 0) { + status_heal(bl, st->max_hp / 100, 0, 2); + sc_timer_next((10000 - ((sce->val1 - 1) * 1000)) + tick, status->change_timer, bl->id, data); + } + break; + case SC_BITESCAR: + if (--(sce->val4) >= 0) { + status_percent_damage(bl, bl, -(sce->val2), 0, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; } // default for all non-handled control paths is to end the status @@ -12204,6 +12314,10 @@ void status_get_matk_sub(struct block_list *bl, int flag, unsigned short *matk_m // Any +MATK you get from skills and cards, including cards in weapon, is added here. if ( sd && sd->bonus.ematk > 0 && flag != 3 ) *matk_min += sd->bonus.ematk; + if (sd && pc->checkskill(sd, SU_POWEROFLAND) > 0) { + if (pc->checkskill(sd, SU_SV_STEMSPEAR) == 5 && pc->checkskill(sd, SU_CN_POWDERING) == 5 && pc->checkskill(sd, SU_CN_METEOR) == 5 && pc->checkskill(sd, SU_SV_ROOTTWIST) == 5) + *matk_min += *matk_min * 20 / 100; + } if ( flag != 3 ) *matk_min = status->calc_ematk(bl, sc, *matk_min); @@ -12215,6 +12329,8 @@ void status_get_matk_sub(struct block_list *bl, int flag, unsigned short *matk_m if ( (st->rhw.matk + st->lhw.matk) > 0 ) { int wMatk = st->rhw.matk + st->lhw.matk; // Left and right matk stacks int variance = wMatk * st->rhw.wlv / 10; // Only use right hand weapon level + if (sc != NULL && sc->data[SC_CATNIPPOWDER]) + wMatk -= wMatk * sc->data[SC_CATNIPPOWDER]->val2 / 100; *matk_min += wMatk - variance; *matk_max += wMatk + variance; } diff --git a/src/map/status.h b/src/map/status.h index e4a326e88..b16539015 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -828,6 +828,18 @@ typedef enum sc_type { SC_M_LIFEPOTION, SC_G_LIFEPOTION, // 640 SC_MYSTICPOWDER, + + // Summoner + SC_SUHIDE, + SC_SU_STOOP, + SC_SPRITEMABLE, + SC_CATNIPPOWDER, + SC_SV_ROOTTWIST, + SC_BITESCAR, + SC_ARCLOUSEDASH, + SC_TUNAPARTY, + SC_SHRIMP, // 650 + SC_FRESHSHRIMP, #ifndef SC_MAX SC_MAX, //Automatically updated max, used in for's to check we are within bounds. #endif @@ -1747,10 +1759,10 @@ enum si_type { //SI_HEALTHSTATE_HEAVYPOISON = 890, //SI_HEALTHSTATE_FEAR = 891, //SI_CHERRY_BLOSSOM_CAKE = 892, - //SI_SU_STOOP = 893, - //SI_CATNIPPOWDER = 894, + SI_SU_STOOP = 893, + SI_CATNIPPOWDER = 894, SI_BLOSSOM_FLUTTERING = 895, - //SI_SV_ROOTTWIST = 896, + SI_SV_ROOTTWIST = 896, //SI_ATTACK_PROPERTY_NOTHING = 897, //SI_ATTACK_PROPERTY_WATER = 898, //SI_ATTACK_PROPERTY_GROUND = 899, @@ -1772,11 +1784,11 @@ enum si_type { //SI_RESIST_PROPERTY_DARKNESS = 914, //SI_RESIST_PROPERTY_TELEKINESIS = 915, //SI_RESIST_PROPERTY_UNDEAD = 916, - //SI_BITESCAR = 917, - //SI_ARCLOUSEDASH = 918, - //SI_TUNAPARTY = 919, - //SI_SHRIMP = 920, - //SI_FRESHSHRIMP = 921, + SI_BITESCAR = 917, + SI_ARCLOUSEDASH = 918, + SI_TUNAPARTY = 919, + SI_SHRIMP = 920, + SI_FRESHSHRIMP = 921, //SI_PERIOD_RECEIVEITEM = 922, //SI_PERIOD_PLUSEXP = 923, //SI_PERIOD_PLUSJOBEXP = 924, @@ -1788,11 +1800,11 @@ enum si_type { //SI_HELM_ISIA = 930, //SI_HELM_ASIR = 931, //SI_HELM_URJ = 932, - //SI_SUHIDE = 933, + SI_SUHIDE = 933, //SI_ = 934, //SI_DORAM_BUF_01 = 935, //SI_DORAM_BUF_02 = 936, - //SI_SPRITEMABLE = 937, + SI_SPRITEMABLE = 937, //SI_EP16_2_BUFF_SS = 963, //SI_EP16_2_BUFF_SC = 964, //SI_EP16_2_BUFF_AC = 965, diff --git a/src/map/unit.c b/src/map/unit.c index 5364a9547..0f3631792 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1127,6 +1127,7 @@ int unit_can_move(struct block_list *bl) || sc->data[SC_VACUUM_EXTREME] || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0) || sc->data[SC_NETHERWORLD] + || sc->data[SC_SUHIDE] || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) || (sc->data[SC_CLOAKING] && sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) //Need wall at level 1-2 || ( @@ -1543,7 +1544,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } break; case GD_EMERGENCYCALL: //Emergency Call double cast when the user has learned Leap [Daegaladh] - if( sd && pc->checkskill(sd,TK_HIGHJUMP) ) + if (sd && (pc->checkskill(sd,TK_HIGHJUMP) || pc->checkskill(sd,SU_LOPE) >= 3)) casttime *= 2; break; case RA_WUGDASH: @@ -2464,6 +2465,8 @@ int unit_remove_map(struct block_list *bl, clr_type clrtype, const char* file, i status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER); status_change_end(bl, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); //callme before warp status_change_end(bl, SC_NETHERWORLD, INVALID_TIMER); + status_change_end(bl, SC_SUHIDE, INVALID_TIMER); + status_change_end(bl, SC_SV_ROOTTWIST, INVALID_TIMER); } if (bl->type&(BL_CHAR|BL_PET)) { |