diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 20 | ||||
-rw-r--r-- | src/common/mapindex.c | 2 | ||||
-rw-r--r-- | src/map/battle.c | 60 | ||||
-rw-r--r-- | src/map/battle.h | 1 | ||||
-rw-r--r-- | src/map/chrif.c | 2 | ||||
-rw-r--r-- | src/map/clif.c | 1 | ||||
-rw-r--r-- | src/map/npc.c | 2 | ||||
-rw-r--r-- | src/map/pc.c | 3 | ||||
-rw-r--r-- | src/map/script.c | 44 | ||||
-rw-r--r-- | src/map/skill.c | 144 | ||||
-rw-r--r-- | src/map/status.c | 111 | ||||
-rw-r--r-- | src/map/unit.c | 13 |
12 files changed, 270 insertions, 133 deletions
diff --git a/src/char/char.c b/src/char/char.c index 9abb17257..abebc5ff9 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -4749,8 +4749,7 @@ int parse_char(int fd) // checks the entered pin case 0x8b8: - if( RFIFOREST(fd) < 10 ) - return 0; + FIFOSD_CHECK(10); if( RFIFOL(fd,2) == sd->account_id ) pincode->check( fd, sd ); @@ -4760,8 +4759,8 @@ int parse_char(int fd) // request for PIN window case 0x8c5: - if( RFIFOREST(fd) < 6 ) - return 0; + FIFOSD_CHECK(6); + if( RFIFOL(fd,2) == sd->account_id ) pincode->sendstate( fd, sd, PINCODE_NOTSET ); @@ -4770,8 +4769,8 @@ int parse_char(int fd) // pincode change request case 0x8be: - if( RFIFOREST(fd) < 14 ) - return 0; + FIFOSD_CHECK(14); + if( RFIFOL(fd,2) == sd->account_id ) pincode->change( fd, sd ); @@ -4780,8 +4779,8 @@ int parse_char(int fd) // activate PIN system and set first PIN case 0x8ba: - if( RFIFOREST(fd) < 10 ) - return 0; + FIFOSD_CHECK(10); + if( RFIFOL(fd,2) == sd->account_id ) pincode->setnew( fd, sd ); RFIFOSKIP(fd,10); @@ -4789,9 +4788,8 @@ int parse_char(int fd) /* 0x8d4 <from>.W <to>.W <unused>.W (2+2+2+2) */ case 0x8d4: - if( RFIFOREST(fd) < 8 ) - return 0; - else { + FIFOSD_CHECK(8); + { bool ret; ret = char_slotchange(sd, fd, RFIFOW(fd, 2), RFIFOW(fd, 4)); WFIFOHEAD(fd, 8); diff --git a/src/common/mapindex.c b/src/common/mapindex.c index f540c98d8..0873b3e59 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -138,7 +138,7 @@ int mapindex_init(void) { char line[1024]; int last_index = -1; int index, total = 0; - char map_name[12]; + char map_name[13]; if( ( fp = fopen(mapindex->config_file,"r") ) == NULL ){ ShowFatalError("Unable to read mapindex config file %s!\n", mapindex->config_file); diff --git a/src/map/battle.c b/src/map/battle.c index 30b358492..07a195503 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -500,8 +500,13 @@ int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, u int64 battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) { int64 damage, batk; struct status_data *st = status->get_status_data(src); - - batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, status->get_sc(src), st->batk, false), nk, n_ele, ELE_NEUTRAL, ELE_NEUTRAL, false, flag); + struct status_change *sc = status->get_sc(src); + + // Property from mild wind bypasses it + if (sc && sc->data[SC_TK_SEVENWIND]) + batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, sc, st->batk, false), nk, n_ele, s_ele, s_ele_, false, flag); + else + batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, sc, st->batk, false), nk, n_ele, ELE_NEUTRAL, ELE_NEUTRAL, false, flag); if( type == EQI_HAND_L ) damage = batk + 3 * battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->lhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2) / 4; @@ -2197,12 +2202,12 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block break; case NC_VULCANARM: skillratio = 70 * skill_lv + status_get_dex(src); - RE_LVL_DMOD(100); + RE_LVL_DMOD(120); break; case NC_FLAMELAUNCHER: case NC_COLDSLOWER: - skillratio += 200 + 100 * skill_lv + status_get_str(src); - RE_LVL_DMOD(100); + skillratio += 200 + 300 * skill_lv; + RE_LVL_DMOD(150); break; case NC_ARMSCANNON: switch( tst->size ) { @@ -2233,13 +2238,16 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio = skillratio * 75 / 100; break; case SC_FATALMENACE: - skillratio = 100 * (skill_lv+1) * status->get_lv(src) / 100; + skillratio = 100 * (skill_lv+1); + RE_LVL_DMOD(100); break; case SC_TRIANGLESHOT: - skillratio = ( 300 + (skill_lv-1) * status_get_agi(src)/2 ) * status->get_lv(src) / 120; + skillratio = ( 300 + (skill_lv-1) * status_get_agi(src)/2 ); + RE_LVL_DMOD(120); break; case SC_FEINTBOMB: - skillratio = (skill_lv+1) * (st->dex/2) * (sd?sd->status.job_level:50)/10 * status->get_lv(src) / 120; + skillratio = (skill_lv+1) * (st->dex/2) * (sd?sd->status.job_level:50)/10; + RE_LVL_DMOD(120); break; case LG_CANNONSPEAR: skillratio = (50 + st->str) * skill_lv; @@ -2307,7 +2315,14 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block RE_LVL_DMOD(100); break; case LG_HESPERUSLIT: - skillratio += 120 * skill_lv - 100; + skillratio = 120 * skill_lv; + if( sc && sc->data[SC_BANDING] ) + skillratio += 200 * sc->data[SC_BANDING]->val2; + if( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 5 ) + skillratio = skillratio * 150 / 100; + if( sc && sc->data[SC_INSPIRATION] ) + skillratio += 600; + RE_LVL_DMOD(100); break; case SR_DRAGONCOMBO: skillratio += 40 * skill_lv; @@ -2797,7 +2812,11 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam } //Now damage increasing effects - if( sc->data[SC_LEXAETERNA] && skill_id != PF_SOULBURN ) + if( sc->data[SC_LEXAETERNA] && skill_id != PF_SOULBURN +#ifdef RENEWAL + && skill_id != CR_ACIDDEMONSTRATION && skill_id != ASC_BREAKER +#endif + ) { if( src->type != BL_MER || skill_id == 0 ) damage <<= 1; // Lex Aeterna only doubles damage of regular attacks from mercenaries @@ -3762,6 +3781,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage >>= 1; } md.damage -= totaldef; + if( tsc && tsc->data[SC_LEXAETERNA] ) { + md.damage <<= 1; + status_change_end(target, SC_LEXAETERNA, INVALID_TIMER); + } } #else // updated the formula based on a Japanese formula found to be exact [Reddozen] @@ -3816,6 +3839,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * ratio >>= 1; md.damage = (matk + atk) * ratio / 100; md.damage -= totaldef; + if( tsc && tsc->data[SC_LEXAETERNA] ) { + md.damage <<= 1; + status_change_end(target, SC_LEXAETERNA, INVALID_TIMER); + } #endif } break; @@ -4176,6 +4203,12 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case LK_SPIRALPIERCE: if (!sd) wd.flag=(wd.flag&~(BF_RANGEMASK|BF_WEAPONMASK))|BF_LONG|BF_MISC; break; + + //When in banding, the number of hits is equal to the number of Royal Guards in banding. + case LG_HESPERUSLIT: + if( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 3 ) + wd.div_ = sc->data[SC_BANDING]->val2; + break; case MO_INVESTIGATE: flag.pdef = flag.pdef2 = 2; @@ -4227,6 +4260,10 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case LK_SPIRALPIERCE: if (!sd) n_ele = false; //forced neutral for monsters break; + case LG_HESPERUSLIT: + if ( sc && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 == 5 ) + s_ele = ELE_HOLY; // Banding with 5 RGs: change atk element to Holy. + break; } if (!(nk & NK_NO_ELEFIX) && !n_ele) @@ -5424,7 +5461,7 @@ void battle_reflect_damage(struct block_list *target, struct block_list *src, st if( wd->dmg_lv >= ATK_BLOCK ) {/* yes block still applies, somehow gravity thinks it makes sense. */ if( sc ) { - if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) { + if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION && skill_id != GS_DESPERADO ) { NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100); #ifndef RENEWAL @@ -6733,6 +6770,7 @@ static const struct battle_data { { "mail_show_status", &battle_config.mail_show_status, 0, 0, 2, }, { "client_limit_unit_lv", &battle_config.client_limit_unit_lv, 0, 0, BL_ALL, }, { "client_emblem_max_blank_percent", &battle_config.client_emblem_max_blank_percent, 100, 0, 100, }, + { "song_timer_reset", &battle_config.song_timer_reset, 0, 0, 1, }, // BattleGround Settings { "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, }, { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, }, diff --git a/src/map/battle.h b/src/map/battle.h index 8d1a3cd39..161ddebc4 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -169,6 +169,7 @@ struct Battle_Config { int emergency_call; int guild_aura; int pc_invincible_time; + int song_timer_reset; int pet_catch_rate; int pet_rename; diff --git a/src/map/chrif.c b/src/map/chrif.c index ebdace226..4c8cd747b 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1178,7 +1178,7 @@ bool chrif_load_scdata(int fd) { 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, 7); + status->change_start(NULL, &sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 15); } pc->scdata_received(sd); diff --git a/src/map/clif.c b/src/map/clif.c index d9acf0792..26462afba 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -10173,6 +10173,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, if (sd->sc.count && ( sd->sc.data[SC_DANCING] || + sd->sc.data[SC_ANKLESNARE] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) )) //No sitting during these states either. break; diff --git a/src/map/npc.c b/src/map/npc.c index f1c6f4fbd..f4f20a60d 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -3447,7 +3447,7 @@ const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* st // w4=<mob id>,<amount>,<delay1>,<delay2>,<event>{,<mob size>,<mob ai>} if( sscanf(w1, "%31[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 || sscanf(w3, "%23[^,],%d", mobname, &mob_lv) < 1 - || sscanf(w4, "%d,%d,%u,%u,%127[^,],%d,%d[^\t\r\n]", &class_, &num, &mobspawn.delay1, &mobspawn.delay2, mobspawn.eventname, &size, &ai) < 2 + || sscanf(w4, "%d,%d,%u,%u,%50[^,],%d,%d[^\t\r\n]", &class_, &num, &mobspawn.delay1, &mobspawn.delay2, mobspawn.eventname, &size, &ai) < 2 ) { ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); if (retval) *retval = EXIT_FAILURE; diff --git a/src/map/pc.c b/src/map/pc.c index 2372d3105..25a15ce84 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -262,9 +262,6 @@ int pc_check_banding( struct block_list *bl, va_list ap ) { sc = status->get_sc(bl); - if( bl == src ) - return 0; - if( sc && sc->data[SC_BANDING] ) { b_sd[(*c)++] = tsd->bl.id; diff --git a/src/map/script.c b/src/map/script.c index 2c893219c..cbea20e55 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -7407,6 +7407,49 @@ BUILDIN(getguildmasterid) } /*========================================== + * Get the information of the members of a guild by type. + * getguildmember <guild_id>{,<type>}; + * @param guild_id: ID of guild + * @param type: + * 0 : name (default) + * 1 : character ID + * 2 : account ID + *------------------------------------------*/ +BUILDIN(getguildmember) +{ + struct guild *g = NULL; + int j = 0; + + g = guild->search(script_getnum(st,2)); + + if (g) { + int i, type = 0; + + if (script_hasdata(st,3)) + type = script_getnum(st,3); + + for ( i = 0; i < MAX_GUILD; i++ ) { + if ( g->member[i].account_id ) { + switch (type) { + case 2: + mapreg->setreg(reference_uid(script->add_str("$@guildmemberaid"), j),g->member[i].account_id); + break; + case 1: + mapreg->setreg(reference_uid(script->add_str("$@guildmembercid"), j), g->member[i].char_id); + break; + default: + mapreg->setregstr(reference_uid(script->add_str("$@guildmembername$"), j), g->member[i].name); + break; + } + j++; + } + } + } + mapreg->setreg(script->add_str("$@guildmembercount"), j); + return true; +} + +/*========================================== * Get char string information by type : * Return by @type : * 0 : char_name @@ -18800,6 +18843,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(getguildname,"i"), BUILDIN_DEF(getguildmaster,"i"), BUILDIN_DEF(getguildmasterid,"i"), + BUILDIN_DEF(getguildmember,"i?"), BUILDIN_DEF(strcharinfo,"i"), BUILDIN_DEF(strnpcinfo,"i"), BUILDIN_DEF(getequipid,"i"), diff --git a/src/map/skill.c b/src/map/skill.c index d0325fc4e..7d5f0d021 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -433,16 +433,12 @@ int can_copy (struct map_session_data *sd, uint16 skill_id, struct block_list* b 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 <= SR_RIDEINLIGHTNING) || (skill_id >= KO_YAMIKUMO && skill_id <= OB_AKAITSUKI))) + 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))) return 0; // Reproduce will only copy skills according on the list. [Jobbie] else if( sd->sc.data[SC__REPRODUCE] && !skill->reproduce_db[skill->get_index(skill_id)] ) return 0; - //Never copy new 3rd class skills By OmegaRed - if(skill_id >= GC_DARKCROW && skill_id <= ALL_FULL_THROTTLE) - return 0; - return 1; } @@ -842,9 +838,9 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 #ifdef RENEWAL sc_start(src,bl,SC_FREEZE,65-(5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); #else - // [Tharis] pointed out that this is normal freeze chance with a base of 300% + //On third hit, there is a 150% to freeze the target if(tsc->sg_counter >= 3 && - sc_start(src,bl,SC_FREEZE,300,skill_lv,skill->get_time2(skill_id,skill_lv))) + sc_start(src,bl,SC_FREEZE,150,skill_lv,skill->get_time2(skill_id,skill_lv))) tsc->sg_counter = 0; /** * being it only resets on success it'd keep stacking and eventually overflowing on mvps, so we reset at a high value @@ -1010,7 +1006,8 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case LK_SPIRALPIERCE: case ML_SPIRALPIERCE: - sc_start(src,bl,SC_ANKLESNARE,100,0,skill->get_time2(skill_id,skill_lv)); + if( dstsd || ( dstmd && !is_boss(bl) ) ) //Does not work on bosses + sc_start(src,bl,SC_STOP,100,0,skill_get_time2(skill_id,skill_lv)); break; case ST_REJECTSWORD: @@ -1210,6 +1207,14 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 rate = 30 + 8 * skill_lv + sstatus->dex / 10 + (sd? sd->status.job_level:0) / 4; sc_start(src, bl, SC_STUN, rate, skill_lv, skill->get_time(skill_id,skill_lv)); break; + case LG_HESPERUSLIT: + if ( sc && sc->data[SC_BANDING] ) { + if ( sc->data[SC_BANDING]->val2 == 4 ) // 4 banding RGs: Targets will be stunned at 100% chance for 4 ~ 8 seconds, irreducible by STAT. + status->change_start(src, bl, SC_STUN, 10000, skill_lv, 0, 0, 0, 1000*(4+rand()%4), 2); + else if ( sc->data[SC_BANDING]->val2 == 6 ) // 6 banding RGs: activate Pinpoint Attack Lv1-5 + skill->castend_damage_id(src,bl,LG_PINPOINTATTACK,1+rand()%5,tick,0); + } + break; case LG_PINPOINTATTACK: rate = 30 + 5 * (sd ? pc->checkskill(sd,LG_PINPOINTATTACK) : 1) + (sstatus->agi + status->get_lv(src)) / 10; switch( skill_lv ) { @@ -1667,6 +1672,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b int rate; struct map_session_data *sd=NULL; struct map_session_data *dstsd=NULL; + struct status_change *sc; nullpo_ret(src); nullpo_ret(bl); @@ -1675,6 +1681,7 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b sd = BL_CAST(BL_PC, src); dstsd = BL_CAST(BL_PC, bl); + sc = status->get_sc(src); if(dstsd && attack_type&BF_WEAPON) { //Counter effects. @@ -1723,6 +1730,13 @@ int skill_counter_additional_effect(struct block_list* src, struct block_list *b case NPC_GRANDDARKNESS: attack_type |= BF_WEAPON; break; + case LG_HESPERUSLIT: + if ( sc && sc->data[SC_FORCEOFVANGUARD] && sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 6 ) { + char i; + for( i = 0; i < sc->data[SC_FORCEOFVANGUARD]->val3; i++ && sc->fv_counter <= sc->data[SC_FORCEOFVANGUARD]->val3 ) + clif->millenniumshield(bl, sc->fv_counter++); + } + break; } if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR @@ -4068,7 +4082,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case SL_STIN: case SL_STUN: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { - status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,2); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -4507,7 +4521,7 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 tsc->data[SC_MELODYOFSINK] || tsc->data[SC_BEYOND_OF_WARCRY] || tsc->data[SC_UNLIMITED_HUMMING_VOICE] ) && rnd()%100 < 4 * skill_lv + 2 * (sd ? pc->checkskill(sd,WM_LESSON) : 10) + 10 * battle->calc_chorusbonus(sd)) { skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); - status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),0); + status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),8); status_change_end(bl, SC_SWING, INVALID_TIMER); status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); @@ -5184,7 +5198,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case RK_FIGHTINGSPIRIT: case RK_ABUNDANCE: if( sd && !pc->checkskill(sd, RK_RUNEMASTERY) ){ - if( status->change_start(src,&sd->bl, (sc_type)(rnd()%SC_CONFUSION), 1000, 1, 0, 0, 0, skill->get_time2(skill_id,skill_lv),0) ){ + if( status->change_start(src,&sd->bl, (sc_type)(rnd()%SC_CONFUSION), 1000, 1, 0, 0, 0, skill->get_time2(skill_id,skill_lv),8) ){ skill->consume_requirement(sd,skill_id,skill_lv,2); map->freeblock_unlock(); return 0; @@ -6213,7 +6227,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin || dstsd->status.char_id == sd->status.child ) ) { - status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,0); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,8); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -6261,25 +6275,24 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case GC_CLOAKINGEXCEED: case LG_FORCEOFVANGUARD: case SC_REPRODUCE: + case RA_CAMOUFLAGE: if (tsce) { int failure = status_change_end(bl, type, INVALID_TIMER); if( failure ) clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,failure); else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - if ( skill_id == LG_FORCEOFVANGUARD ) + if ( skill_id == LG_FORCEOFVANGUARD || skill_id == RA_CAMOUFLAGE ) break; map->freeblock_unlock(); return 0; + } else { + int failure = sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + if( failure ) + clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,failure); + else if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } - case RA_CAMOUFLAGE: - { - int failure = sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - if( failure ) - clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,failure); - else if( sd ) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - } break; case BD_ADAPTATION: @@ -6360,7 +6373,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (tsc->data[SC_STONE]) { status_change_end(bl, SC_STONE, INVALID_TIMER); - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; } if (sc_start4(src,bl,SC_STONE,(skill_lv*4+20)+brate, @@ -6732,7 +6745,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin sp += sp * i / 100; } } else { - hp = (1 + rnd()%400) * (100 + skill_lv*10) / 100; + //Maybe replace with potion_hp, but I'm unsure how that works [Playtester] + switch (skill_lv) { + case 1: hp = 45; break; + case 2: hp = 105; break; + case 3: hp = 175; break; + default: hp = 325; break; + } + hp = (hp + rnd()%(skill_lv*20+1)) * (150 + skill_lv*10) / 100; hp = hp * (100 + (tstatus->vit<<1)) / 100; if( dstsd ) hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; @@ -7265,7 +7285,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin return 0; } else - status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),0); + status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),8); } break; @@ -7671,7 +7691,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin if (tsce) { if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,10000,0); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,10000,8); status_change_end(bl, SC_SWOO, INVALID_TIMER); break; } @@ -7679,7 +7699,7 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case SL_SKE: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,2); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); break; } clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); @@ -8646,13 +8666,13 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin //If the target was successfully inflected with the Unlucky status, give 1 of 3 random status's. switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's regardless of resistance. case 0: - status->change_start(src,bl,SC_POISON,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),2); + status->change_start(src,bl,SC_POISON,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); break; case 1: - status->change_start(src,bl,SC_SILENCE,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),2); + status->change_start(src,bl,SC_SILENCE,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); break; case 2: - status->change_start(src,bl,SC_BLIND,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),2); + status->change_start(src,bl,SC_BLIND,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); } } } else if( sd ) @@ -9547,8 +9567,8 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin heal = 5 * status->get_lv(&hd->bl) + status->base_matk(&hd->battle_status, status->get_lv(&hd->bl)); status->heal(bl, heal, 0, 0); clif->skill_nodamage(src, src, skill_id, skill_lv, clif->skill_nodamage(src, bl, AL_HEAL, heal, 1)); - status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2); - status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2); + status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); + status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); } break; @@ -11018,9 +11038,17 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ } break; case BA_ASSASSINCROSS: - val1 = 10 + skill_lv + (st->agi/10); // ASPD increase if(sd) - val1 += (pc->checkskill(sd,BA_MUSICALLESSON) + 1) / 2; + val1 = (pc->checkskill(sd,BA_MUSICALLESSON) + 1) / 2; +#ifdef RENEWAL + // This formula was taken from a RE calculator + // and the changes published on irowiki + // Luckily, official tests show it's the right one + val1 += skill_lv + (st->agi/20); +#else + val1 += 10 + skill_lv + (st->agi/10); // ASPD increase + val1 *= 10; // ASPD works with 1000 as 100% +#endif break; case DC_FORTUNEKISS: val1 = 10+skill_lv+(st->luk/10); // Critical increase @@ -11135,6 +11163,10 @@ struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_ case SO_WARMER: skill->clear_group(src, 8); break; + case SO_VACUUM_EXTREME: + val1 = x; + val2 = y; + break; case GN_WALLOFTHORN: if( flag&1 ) limit = 3000; @@ -11340,7 +11372,7 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick break; } else if( sc && battle->check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) { int sec = skill->get_time2(sg->skill_id,sg->skill_lv); - if( status->change_start(ss, bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,0) ) { + if( status->change_start(ss, bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) { const struct TimerData* td = sc->data[type]?timer->get(sc->data[type]->timer):NULL; if( td ) sec = DIFF_TICK32(td->tick, tick); @@ -11438,10 +11470,12 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick if (!sce) sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); break; + case UNT_APPLEIDUN: // Apple of idun gets it from skill_unit_onplace_timer + if (!battle_config.song_timer_reset) + break; case UNT_WHISTLE: case UNT_ASSASSINCROSS: case UNT_POEMBRAGI: - case UNT_APPLEIDUN: case UNT_HUMMING: case UNT_DONTFORGETME: case UNT_FORTUNEKISS: @@ -11452,12 +11486,13 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick if (!sc) return 0; if (!sce) sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); - else if (sce->val4 == 1) { + else if (battle_config.song_timer_reset && sce->val4 == 1) { //Readjust timers since the effect will not last long. sce->val4 = 0; timer->delete(sce->timer, status->change_timer); sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); } + break; case UNT_FOGWALL: @@ -11721,7 +11756,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_MANHOLE: if( sg->val2 == 0 && tsc && (sg->unit_id == UNT_ANKLESNARE || bl->id != sg->src_id) ) { int sec = skill->get_time2(sg->skill_id,sg->skill_lv); - if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 0) ) { + if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) { const struct TimerData* td = tsc->data[type]?timer->get(tsc->data[type]->timer):NULL; if( td ) sec = DIFF_TICK32(td->tick, tick); @@ -11751,7 +11786,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 if( bl->id != ss->id ) { if( status_get_mode(bl)&MD_BOSS ) break; - if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id, sg->skill_lv), 0) ) { + if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id, sg->skill_lv), 8) ) { map->moveblock(bl, src->bl.x, src->bl.y, tick); clif->fixpos(bl); @@ -11840,6 +11875,12 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 heal = ~heal + 1; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); status->heal(bl, heal, 0, 0); + + if (!(battle_config.song_timer_reset) // songs don't reset prior timers + && !(sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) // Don't affect itself + && (!(tsc->data[type]) || (tsc->data[type] && tsc->data[type]->val4 != 1))) // Check for 20 seconds song effect + sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->interval + 100); + break; } @@ -12111,7 +12152,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_CLOUD_KILL: if(tsc && !tsc->data[type]) - status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),0); + status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),8); skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -12156,11 +12197,16 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 break; case UNT_VACUUM_EXTREME: - if ( tsc && tsc->data[SC_HALLUCINATIONWALK] ) { + if (tsc && (tsc->data[SC_HALLUCINATIONWALK] || tsc->data[SC_VACUUM_EXTREME])) { return 0; } else { sg->limit -= 100 * tstatus->str/20; sc_start(ss, bl, SC_VACUUM_EXTREME, 100, sg->skill_lv, sg->limit); + + if (unit->movepos(bl, sg->val1, sg->val2, 0, 0)) { + clif->slide(bl, sg->val1, sg->val2); + clif->fixpos(bl); + } } break; @@ -12205,7 +12251,7 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_POISON_MIST: skill->attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); - 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), 2); + 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), 2|8); break; } @@ -12264,6 +12310,16 @@ int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) } } break; + case UNT_WHISTLE: + case UNT_ASSASSINCROSS: + case UNT_POEMBRAGI: + case UNT_APPLEIDUN: + case UNT_HUMMING: + case UNT_DONTFORGETME: + case UNT_FORTUNEKISS: + case UNT_SERVICEFORYOU: + if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) + return -1; } return sg->skill_id; } @@ -12341,7 +12397,7 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { case DC_DONTFORGETME: case DC_FORTUNEKISS: case DC_SERVICEFORYOU: - if (sce) { + if ((battle_config.song_timer_reset && sce) || (!battle_config.song_timer_reset && sce && sce->val4 != 1)) { timer->delete(sce->timer, status->change_timer); //NOTE: It'd be nice if we could get the skill_lv for a more accurate extra time, but alas... //not possible on our current implementation. @@ -12404,8 +12460,8 @@ int skill_unit_effect(struct block_list* bl, va_list ap) { } else { if( flag&1 ) skill->unit_onplace(su,bl,tick); - else - skill->unit_onout(su,bl,tick); + else if (skill->unit_onout(su,bl,tick) == -1) + return 0; // Don't let a Bard/Dancer update their own song timer if( flag&4 ) skill->unit_onleft(skill_id, bl, tick); diff --git a/src/map/status.c b/src/map/status.c index 86be2e252..188b952ef 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1003,6 +1003,7 @@ void initChangeTables(void) { status->ChangeFlagTable[SC_REBOUND] |= SCB_SPEED|SCB_REGEN; status->ChangeFlagTable[SC_DEFSET] |= SCB_DEF|SCB_DEF2; status->ChangeFlagTable[SC_MDEFSET] |= SCB_MDEF|SCB_MDEF2; + status->ChangeFlagTable[SC_MYSTERIOUS_POWDER] |= SCB_MAXHP; status->ChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; status->ChangeFlagTable[SC_WEDDING] = SCB_SPEED; @@ -1789,16 +1790,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK); //You cannot hide from ground skills. - if( skill->get_ele(skill_id,1) == ELE_EARTH ) //TODO: Need Skill Lv here :/ + if( skill->get_ele(skill_id,1) == ELE_EARTH && skill_id != MG_STONECURSE) hide_flag &= ~OPTION_HIDE; - else { - switch ( skill_id ) { - case MO_ABSORBSPIRITS: // it works when already casted and target suddenly hides. - case SA_DISPELL: - hide_flag &= ~OPTION_HIDE; - break; - } - } switch( target->type ) { case BL_PC: { @@ -1809,6 +1802,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin return 0; if( tsc ) { if (tsc->option&hide_flag && !is_boss && + !(flag&1 && skill->get_nk(skill_id)&NK_NO_DAMAGE) && // Buff/debuff skills that started casting before hiding still applies ((sd->special_state.perfect_hiding || !is_detect) || (tsc->data[SC_CLOAKINGEXCEED] && is_detect))) return 0; @@ -4590,7 +4584,7 @@ unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, watk += sc->data[SC_SHIELDSPELL_DEF]->val2; if(sc->data[SC_INSPIRATION]) watk += sc->data[SC_INSPIRATION]->val2; - if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 ) + if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 1 ) watk += (10 + 10 * sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2); if( sc->data[SC_TROPIC_OPTION] ) watk += sc->data[SC_TROPIC_OPTION]->val2; @@ -4683,8 +4677,6 @@ unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, if( !viewable ){ /* some statuses that are hidden in the status window */ - if (sc->data[SC_MINDBREAKER]) - matk += matk * sc->data[SC_MINDBREAKER]->val2/100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } @@ -4709,6 +4701,8 @@ unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, if (sc->data[SC_IZAYOI]) matk += 25 * sc->data[SC_IZAYOI]->val1; #endif + if (sc->data[SC_MINDBREAKER]) + matk += matk * sc->data[SC_MINDBREAKER]->val2/100; if( sc->data[SC_ZANGETSU] ) matk += sc->data[SC_ZANGETSU]->val3; if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4) @@ -5046,7 +5040,7 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i return 0; if(sc->data[SC_SUN_COMFORT]) def2 += sc->data[SC_SUN_COMFORT]->val2; - if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 ) + if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 1 ) def2 += (5 + sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2); if(sc->data[SC_ANGELUS]) #ifdef RENEWAL //in renewal only the VIT stat bonus is boosted by angelus @@ -5401,7 +5395,25 @@ short status_calc_aspd(struct block_list *bl, struct status_change *sc, short fl skills1 = 5; } - if((sc->data[SC_BERSERK]) && skills1 < 15) + if( sc->data[SC_ASSNCROS] && skills1 < sc->data[SC_ASSNCROS]->val2){ + if (bl->type!=BL_PC) + skills1 = sc->data[SC_ASSNCROS]->val2; + else + switch(((TBL_PC*)bl)->status.weapon) + { + case W_BOW: + case W_REVOLVER: + case W_RIFLE: + case W_GATLING: + case W_SHOTGUN: + case W_GRENADE: + break; + default: + skills1 = sc->data[SC_ASSNCROS]->val2; + } + } + + if((sc->data[SC_BERSERK]) && skills1 < 15) skills1 = 15; else if(sc->data[SC_GS_MADNESSCANCEL] && skills1 < 20) skills1 = 20; @@ -5447,7 +5459,7 @@ short status_calc_aspd(struct block_list *bl, struct status_change *sc, short fl if( sc->data[SC_PAIN_KILLER] ) skills2 -= sc->data[SC_PAIN_KILLER]->val2; - if( sc->data[SC_SWING] ) + if( sc->data[SC_SWING] ) // TODO: SC_SWING shouldn't stack with skill1 modifiers skills2 += sc->data[SC_SWING]->val3; if( sc->data[SC_DANCE_WITH_WUG] ) skills2 += sc->data[SC_DANCE_WITH_WUG]->val3; @@ -5463,23 +5475,7 @@ short status_calc_aspd(struct block_list *bl, struct status_change *sc, short fl skills2 += sc->data[SC_GS_GATLINGFEVER]->val1; if( sc->data[SC_STAR_COMFORT] ) skills2 += 3 * sc->data[SC_STAR_COMFORT]->val1; - if( sc->data[SC_ASSNCROS] && !skills1){ - if (bl->type!=BL_PC) - skills2 += sc->data[SC_ASSNCROS]->val2; - else - switch(((TBL_PC*)bl)->status.weapon) - { - case W_BOW: - case W_REVOLVER: - case W_RIFLE: - case W_GATLING: - case W_SHOTGUN: - case W_GRENADE: - break; - default: - skills2 += sc->data[SC_ASSNCROS]->val2; - } - } + return ( flag&1? (skills1 + pots) : skills2 ); #else return 0; @@ -5568,7 +5564,8 @@ short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int max = sc->data[SC_ASSNCROS]->val2; } } - aspd_rate -= 10 * max; // let's multiply here for consistency + + aspd_rate -= max; if(sc->data[SC_BERSERK]) aspd_rate -= 300; @@ -6335,12 +6332,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ case SC_QUAGMIRE: case SC_NJ_SUITON: case SC_SWING: - case SC__ENERVATION: - case SC__GROOMY: - case SC__IGNORANCE: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: return 0; } @@ -6380,9 +6371,7 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ case SC_STUN: sc_def = st->vit*100; sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); -#ifdef RENEWAL tick_def2 = st->luk*10; -#endif break; case SC_POISON: case SC_DPOISON: @@ -6402,24 +6391,29 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ #ifdef RENEWAL sc_def = st->int_*100; sc_def2 = (st->vit + st->luk) * 5 + SCDEF_LVL_DIFF(bl, src, 99, 10); - tick_def2 = st->luk * 10; #else sc_def = st->vit*100; sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); #endif + tick_def2 = st->luk * 10; break; case SC_BLOODING: #ifdef RENEWAL sc_def = st->agi*100; - tick_def2 = st->luk*10; #else sc_def = st->vit*100; #endif sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def2 = st->luk*10; break; case SC_SLEEP: +#ifdef RENEWAL + sc_def = st->agi*100; + sc_def2 = (st->int_ + st->luk) * 5 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#else sc_def = st->int_*100; sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#endif tick_def2 = st->luk*10; break; case SC_DEEP_SLEEP: @@ -6433,7 +6427,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ sc_def = st->mdef*100; #ifndef RENEWAL sc_def2 = st->luk*10; - tick_def2 = 0; //No duration reduction #endif tick_def = 0; //No duration reduction break; @@ -6451,11 +6444,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ // Special property: immunity when luk is zero if (st->luk == 0) return 0; -#ifndef RENEWAL - // Special property: immunity when luk is greater than level - if (st->luk > status->get_lv(bl)) - return 0; -#endif sc_def = st->luk*100; sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(NULL, src, 99, 10); // Curse only has a level penalty and no resistance tick_def = st->vit*100; @@ -6718,7 +6706,8 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) { * &1: Cannot be avoided (it has to start) * &2: Tick should not be reduced (by vit, luk, lv, etc) * &4: sc_data loaded, no value has to be altered. -* &8: SI will not be sent to the client +* &8: rate should not be reduced (not evaluated here, but in some calls to other functions) +* &16: SI will not be sent to the client *------------------------------------------*/ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag) { struct map_session_data *sd = NULL; @@ -7531,10 +7520,10 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t int i; for( i = 0; i < 5; i++ ) { if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 17); } } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 17); } //val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) if( val4 ) @@ -7628,10 +7617,10 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t int i; for( i = 0; i < 5; i++ ) { if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 17); } } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 17); } break; case SC_NOEQUIPWEAPON: @@ -7886,11 +7875,11 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t if( sd ) { for( i = 0; i < 5; i++ ) { if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 17); } } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 9); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 17); } } break; @@ -8034,7 +8023,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t while( i >= 0 ) { type2 = types[i]; if( d_sc->data[type2] ) - status->change_start(bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, 0, skill->get_time(status->sc2skill(type2),d_sc->data[type2]->val1), (type2 != SC_DEFENDER) ? 8 : 0); + status->change_start(bl, bl, type2, 10000, d_sc->data[type2]->val1, 0, 0, 0, skill->get_time(status->sc2skill(type2),d_sc->data[type2]->val1), (type2 != SC_DEFENDER) ? 16 : 0); i--; } } @@ -8433,7 +8422,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t tick_time = 4000; // [GodLesZ] tick time break; case SC_PYREXIA: - status->change_start(src, bl,SC_BLIND,10000,val1,0,0,0,30000,3); // Blind status that last for 30 seconds + status->change_start(src, bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds val4 = tick / 3000; tick_time = 3000; // [GodLesZ] tick time break; @@ -8752,7 +8741,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t struct block_list * src2; val3 = st->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % if( (src2 = map->id2bl(val2)) ){ - val4 = ( 200/status_get_int(src2) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] + val4 = ( 200/status_get_int(src2)?status_get_int(src2):1 ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] val2 = ( status_get_dex(src2)/4 + status_get_str(src2)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] } } @@ -9443,7 +9432,7 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t calc_flag&=~SCB_DYE; } - if(!(flag&8) && !(flag&4 && status->DisplayType[type])) + if(!(flag&16) && !(flag&4 && status->DisplayType[type])) clif->status_change(bl,status->IconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); /** @@ -11636,7 +11625,7 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { data.val2 = sc->data[i]->val2; data.val3 = sc->data[i]->val3; data.val4 = sc->data[i]->val4; - status->change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2); + status->change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); flag = 1; } } diff --git a/src/map/unit.c b/src/map/unit.c index af0c0a948..8b74ff80c 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1241,6 +1241,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui casttime = -1; temp = 1; break; + case CR_DEVOTION: + if (sd) { + int i = 0, count = min(skill_lv, 5); + ARR_FIND(0, count, i, sd->devotion[i] == target_id); + if (i == count) { + ARR_FIND(0, count, i, sd->devotion[i] == 0); + if(i == count) { + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + return 0; // Can't cast on other characters when limit is reached + } + } + } + break; case SR_GATEOFHELL: case SR_TIGERCANNON: if (sc && sc->data[SC_COMBOATTACK] && |