From 0623d4ff87906d9ea0aee7bf612da2d1afdee1cd Mon Sep 17 00:00:00 2001 From: Michieru Date: Mon, 24 Nov 2014 14:48:59 +0100 Subject: * 1st Transcendent Spirit, monster position lag fixes - 1st Transcendent Spirit will now work as on official servers (#116) * The max total stat that is granted by the skill is now BaseLevel-10 with a maximum of 50 instead of always 50 * It will now work as Marionette Control and calculate the bonus at cast time rather than overwrite all existing bonuses * Agi Up and Blessing will now cancel the soul link - Fixed various problems that caused position lags on the client (#118) * Added a define ACTIVEPATHSEARCH in mob.c; if active (default and official), monsters will only grab targets if the walk path to the target is shorter or equal their search range; search range depends on whether the monster is moving or not (range2 for standing monsters and range3 for walking monsters); this requires a lot of CPU load, if it causes trouble, just comment the define for old behavior * Fixed a bug that made monsters display "irregular movement with position lag" continuously when a status change ended that changed their walk speed * OFFICIAL_WALKPATH now also applies to monsters * If the path search fails while a unit is already moving, we will now issue of fixpos packet so that the unit does not only stop moving on the server, but also on the client * Direction fixes - Updated the config setting attack_direction_change from 15 to 0 (official value); that means that a unit's direction will no longer change when it attacks; knock-back effects from e.g. Firewall will depend on the last direction the target walked into instead (bugreport:1322) - Ensured that the default direction of a monster is always "north", so that immobile monsters will now always be knocked back to the south by e.g. Firewall on default settings, unless a skill like e.g. Backstab changes their direction (bugreport:1322) - Fixed a bug that stopped characters server-sided and caused position lag when closing a skill menu * Magnum Break damage fixed - Targets two cells away will now only take 100%+10%*level damage (#108) --- src/map/battle.c | 9 ++++---- src/map/mob.c | 10 +++++++++ src/map/mob.h | 9 ++++++++ src/map/skill.c | 11 +++++++--- src/map/status.c | 67 ++++++++++++++++++++++++++++++++++++++++---------------- src/map/unit.c | 25 +++++++++++++++++++-- 6 files changed, 102 insertions(+), 29 deletions(-) (limited to 'src/map') diff --git a/src/map/battle.c b/src/map/battle.c index 1563553d4..5a17c8d90 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1463,9 +1463,9 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block break; case WZ_FIREPILLAR: if (skill_lv > 10) - skillratio += 100; + skillratio += 2300; //200% MATK each hit else - skillratio -= 80; + skillratio += -60 + 20*skill_lv; //20% MATK each hit break; case WZ_SIGHTRASHER: skillratio += 20 * skill_lv; @@ -3384,11 +3384,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list switch(skill_id) { case MG_FIREWALL: - case NJ_KAENSIN: - ad.dmotion = 0; //No flinch animation. if ( tstatus->def_ele == ELE_FIRE || battle->check_undead(tstatus->race, tstatus->def_ele) ) ad.blewcount = 0; //No knockback break; + case NJ_KAENSIN: case PR_SANCTUARY: ad.dmotion = 0; //No flinch animation. break; @@ -3495,7 +3494,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list } //Constant/misc additions from skills if (skill_id == WZ_FIREPILLAR) - MATK_ADD(50); + MATK_ADD(100+50*skill_lv); if( sd && ( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ) && (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) diff --git a/src/map/mob.c b/src/map/mob.c index 28e70c5c0..cb22f71c0 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -941,6 +941,7 @@ int mob_spawn (struct mob_data *md) md->move_fail_count = 0; md->ud.state.attack_continue = 0; md->ud.target_to = 0; + md->ud.dir = 0; if( md->spawn_timer != INVALID_TIMER ) { timer->delete(md->spawn_timer, mob->delayspawn); @@ -1080,6 +1081,15 @@ int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap) ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) && battle->check_range(&md->bl,bl,md->db->range2) ) { //Pick closest target? +#ifdef ACTIVEPATHSEARCH + struct walkpath_data wpd; + if (!path->search(&wpd, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKNOPASS)) // Count walk path cells + return 0; + //Standing monsters use range2, walking monsters use range3 + if ((md->ud.walktimer == INVALID_TIMER && wpd.path_len > md->db->range2) + || (md->ud.walktimer != INVALID_TIMER && wpd.path_len > md->db->range3)) + return 0; +#endif (*target) = bl; md->target_id=bl->id; md->min_chase= dist + md->db->range3; diff --git a/src/map/mob.h b/src/map/mob.h index c61d29103..f79b33804 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -42,6 +42,15 @@ #define MAX_MOB_CHAT 250 //Max Skill's messages +// On official servers, monsters will only seek targets that are closer to walk to than their +// search range. The search range is affected depending on if the monster is walking or not. +// On some maps there can be a quite long path for just walking two cells in a direction and +// the client does not support displaying walk paths that are longer than 14 cells, so this +// option reduces position lag in such situation. But doing a complex search for every possible +// target, might be CPU intensive. +// Disable this to make monsters not do any path search when looking for a target (old behavior). +#define ACTIVEPATHSEARCH + //Mob skill states. enum MobSkillState { MSS_ANY = -1, diff --git a/src/map/skill.c b/src/map/skill.c index 938b36419..8c452252a 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -3762,8 +3762,6 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 case NPC_SPLASHATTACK: flag |= SD_PREAMBLE; // a fake packet will be sent for the first target to be hit case AS_SPLASHER: - case SM_MAGNUM: - case MS_MAGNUM: case HT_BLITZBEAT: case AC_SHOWER: case MA_SHOWER: @@ -3873,6 +3871,14 @@ int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint1 } break; + case SM_MAGNUM: + case MS_MAGNUM: + if( flag&1 ) { + //Damage depends on distance, so add it to flag if it is > 1 + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag|distance_bl(src, bl)); + } + break; + case KN_BRANDISHSPEAR: case ML_BRANDISH: //Coded apart for it needs the flag passed to the damage calculation. @@ -9900,7 +9906,6 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char } pc_stop_attack(sd); - pc_stop_walking(sd,0); if(battle_config.skill_log && battle_config.skill_log&BL_PC) ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,mapname); diff --git a/src/map/status.c b/src/map/status.c index e2eede490..1a726a415 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -3639,6 +3639,21 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { if (!bst || !st) return; + /** [Playtester] + * This needs to be done even if there is currently no status change active, because + * we need to update the speed on the client when the last status change ends. + **/ + if(flag&SCB_SPEED) { + struct unit_data *ud = unit->bl2ud(bl); + /** [Skotlex] + * Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER + * because if you step on something while walking, the moment this + * piece of code triggers the walk-timer is set on INVALID_TIMER) + **/ + if (ud) + ud->state.change_walk_target = ud->state.speed_changed = 1; + } + if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference. status_cpy(st, bst); return; @@ -3815,16 +3830,9 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { } if(flag&SCB_SPEED) { - struct unit_data *ud = unit->bl2ud(bl); st->speed = status->calc_speed(bl, sc, bst->speed); - //Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER - //because if you step on something while walking, the moment this - //piece of code triggers the walk-timer is set on INVALID_TIMER) [Skotlex] - if (ud) - ud->state.change_walk_target = ud->state.speed_changed = 1; - if( bl->type&BL_PC && !(sd && sd->state.permanent_speed) && st->speed < battle_config.max_walk_speed ) st->speed = battle_config.max_walk_speed; @@ -4200,8 +4208,6 @@ unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, } if(sc->data[SC_BEYOND_OF_WARCRY]) str += sc->data[SC_BEYOND_OF_WARCRY]->val3; - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && str < 50) - return 50; if(sc->data[SC_INCALLSTATUS]) str += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_CHASEWALK2]) @@ -4232,6 +4238,8 @@ unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, str -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>16)&0xFF; if(sc->data[SC_MARIONETTE]) str += ((sc->data[SC_MARIONETTE]->val3)>>16)&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + str += ((sc->data[SC_SOULLINK]->val3)>>16)&0xFF; if(sc->data[SC_GIANTGROWTH]) str += 30; if(sc->data[SC_SAVAGE_STEAK]) @@ -4257,8 +4265,6 @@ unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, agi -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(agi,0,USHRT_MAX); } - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && agi < 50) - return 50; if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE]) agi += (agi-sc->data[SC_CONCENTRATION]->val3)*sc->data[SC_CONCENTRATION]->val2/100; if(sc->data[SC_INCALLSTATUS]) @@ -4287,6 +4293,8 @@ unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, agi -= ((sc->data[SC_MARIONETTE_MASTER]->val3)>>8)&0xFF; if(sc->data[SC_MARIONETTE]) agi += ((sc->data[SC_MARIONETTE]->val3)>>8)&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + agi += ((sc->data[SC_SOULLINK]->val3)>>8)&0xFF; if(sc->data[SC_ADORAMUS]) agi -= sc->data[SC_ADORAMUS]->val2; if(sc->data[SC_DROCERA_HERB_STEAMED]) @@ -4315,8 +4323,6 @@ unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, vit -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(vit,0,USHRT_MAX); } - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && vit < 50) - return 50; if(sc->data[SC_INCALLSTATUS]) vit += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCVIT]) @@ -4335,6 +4341,8 @@ unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, vit -= sc->data[SC_MARIONETTE_MASTER]->val3&0xFF; if(sc->data[SC_MARIONETTE]) vit += sc->data[SC_MARIONETTE]->val3&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + vit += sc->data[SC_SOULLINK]->val3&0xFF; if(sc->data[SC_LAUDAAGNUS]) vit += 4 + sc->data[SC_LAUDAAGNUS]->val1; if(sc->data[SC_MINOR_BBQ]) @@ -4365,8 +4373,6 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, } if(sc->data[SC_MELODYOFSINK]) int_ -= sc->data[SC_MELODYOFSINK]->val3; - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && int_ < 50) - return 50; if(sc->data[SC_INCALLSTATUS]) int_ += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCINT]) @@ -4393,6 +4399,8 @@ unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int_ -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>16)&0xFF; if(sc->data[SC_MARIONETTE]) int_ += ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + int_ += ((sc->data[SC_SOULLINK]->val4)>>16)&0xFF; if(sc->data[SC_MANDRAGORA]) int_ -= 4 * sc->data[SC_MANDRAGORA]->val1; if(sc->data[SC_COCKTAIL_WARG_BLOOD]) @@ -4425,8 +4433,6 @@ unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, dex -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(dex,0,USHRT_MAX); } - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && dex < 50) - return 50; if(sc->data[SC_CONCENTRATION] && !sc->data[SC_QUAGMIRE]) dex += (dex-sc->data[SC_CONCENTRATION]->val4)*sc->data[SC_CONCENTRATION]->val2/100; if(sc->data[SC_INCALLSTATUS]) @@ -4457,6 +4463,8 @@ unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, dex -= ((sc->data[SC_MARIONETTE_MASTER]->val4)>>8)&0xFF; if(sc->data[SC_MARIONETTE]) dex += ((sc->data[SC_MARIONETTE]->val4)>>8)&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + dex += ((sc->data[SC_SOULLINK]->val4)>>8)&0xFF; if(sc->data[SC_SIROMA_ICE_TEA]) dex += sc->data[SC_SIROMA_ICE_TEA]->val1; if(sc->data[SC_INSPIRATION]) @@ -4487,8 +4495,6 @@ unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, } if(sc->data[SC_CURSE]) return 0; - if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && luk < 50) - return 50; if(sc->data[SC_INCALLSTATUS]) luk += sc->data[SC_INCALLSTATUS]->val1; if(sc->data[SC_INCLUK]) @@ -4505,6 +4511,8 @@ unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, luk -= sc->data[SC_MARIONETTE_MASTER]->val4&0xFF; if(sc->data[SC_MARIONETTE]) luk += sc->data[SC_MARIONETTE]->val4&0xFF; + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + luk += sc->data[SC_SOULLINK]->val4&0xFF; if(sc->data[SC_PUTTI_TAILS_NOODLES]) luk += sc->data[SC_PUTTI_TAILS_NOODLES]->val1; if(sc->data[SC_INSPIRATION]) @@ -7231,9 +7239,13 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) status_change_end(bl, SC_STONE, INVALID_TIMER); } + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; case SC_INC_AGI: status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; case SC_QUAGMIRE: status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); @@ -8051,6 +8063,23 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - tst->luk ); val4 |= cap_value(stat,0,0xFF); } break; + case SC_SOULLINK: + //1st Transcendent Spirit works similar to Marionette Control + if(sd && val2 == SL_HIGH) { + int stat,max_stat; + // Fetch target's stats + struct status_data* status2 = status_get_status_data(bl); // Battle status + val3 = 0; + val4 = 0; + max_stat = (status_get_lv(bl)-10<50)?status_get_lv(bl)-10:50; + stat = max(0, max_stat - status2->str ); val3 |= cap_value(stat,0,0xFF)<<16; + stat = max(0, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8; + stat = max(0, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF); + stat = max(0, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16; + stat = max(0, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8; + stat = max(0, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF); + } + break; case SC_SWORDREJECT: val2 = 15*val1; //Reflect chance val3 = 3; //Reflections diff --git a/src/map/unit.c b/src/map/unit.c index c00a0631d..aa71ad1fb 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -100,6 +100,13 @@ int unit_walktoxy_sub(struct block_list *bl) if( !path->search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) ) return 0; +#ifdef OFFICIAL_WALKPATH + if( !path->search_long(NULL, bl->m, bl->x, bl->y, ud->to_x, ud->to_y, CELL_CHKNOPASS) // Check if there is an obstacle between + && wpd.path_len > 14 // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett] + && (bl->type != BL_NPC) ) // If type is a NPC, please disregard. + return 0; +#endif + memcpy(&ud->walkpath,&wpd,sizeof(wpd)); if (ud->target_to && ud->chaserange>1) { @@ -391,8 +398,14 @@ int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) { ud->steptimer = timer->add(tick+i, unit->step_timer, bl->id, 0); } - if(ud->state.change_walk_target) - return unit->walktoxy_sub(bl); + if(ud->state.change_walk_target) { + if(unit_walktoxy_sub(bl)) { + return 1; + } else { + clif->fixpos(bl); + return 0; + } + } ud->walkpath.path_pos++; if(ud->walkpath.path_pos>=ud->walkpath.path_len) @@ -572,6 +585,10 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int ud->to_y = bl->y; ud->target_to = 0; return 0; + } else if (range == 0) { + //Should walk on the same cell as target (for looters) + ud->to_x = tbl->x; + ud->to_y = tbl->y; } ud->state.walk_easy = flag&1; @@ -1131,6 +1148,10 @@ int unit_set_walkdelay(struct block_list *bl, int64 tick, int delay, int type) { if (delay <= 0 || !ud) return 0; if (type) { + //Bosses can ignore skill induced walkdelay (but not damage induced) + if(bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS)) + return 0; + //Make sure walk delay is not decreased if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0) return 0; } else { -- cgit v1.2.3-60-g2f50