diff options
-rw-r--r-- | conf/battle/battle.conf | 7 | ||||
-rw-r--r-- | db/pre-re/skill_db.txt | 4 | ||||
-rw-r--r-- | db/re/skill_db.txt | 4 | ||||
-rw-r--r-- | db/re/skill_unit_db.txt | 2 | ||||
-rw-r--r-- | src/map/battle.c | 9 | ||||
-rw-r--r-- | src/map/mob.c | 10 | ||||
-rw-r--r-- | src/map/mob.h | 9 | ||||
-rw-r--r-- | src/map/skill.c | 11 | ||||
-rw-r--r-- | src/map/status.c | 67 | ||||
-rw-r--r-- | src/map/unit.c | 25 |
10 files changed, 113 insertions, 35 deletions
diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf index 2e84a23e5..42d9a7262 100644 --- a/conf/battle/battle.conf +++ b/conf/battle/battle.conf @@ -103,7 +103,12 @@ weapon_defense_type: 0 magic_defense_type: 0 // Change attacker's direction to face opponent on every attack? (Note 3) -attack_direction_change: 15 +// NOTE: On official servers knockback of some skills like Firewall is always based on the +// last direction walked. Even when attacking in a completely different direction, the +// knockback direction won't change, so e.g. if you walk north and then attack an enemy to +// the south you will still be knocked back to the south by Firewall. Immobile monsters +// will always be knocked back to the south as their default direction is north. +attack_direction_change: 0 // For those who is set, their innate attack element is "not elemental" // (100% versus on all defense-elements) (Note 3) diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt index 4c085b8df..371833d98 100644 --- a/db/pre-re/skill_db.txt +++ b/db/pre-re/skill_db.txt @@ -124,7 +124,7 @@ 77,5,6,1,6,0x28,0,10,1,yes,0,0,0,magic,0, PR_TURNUNDEAD,Turn Undead 78,9,6,1,0,0x1,0,1,0,yes,0,0,0,magic,0, PR_LEXAETERNA,Lex Aeterna 79,9,8,2,6,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, PR_MAGNUS,Magnus Exorcismus -80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,3:4:5:6:7:8:9:10:11:12:12,yes,0,0x80,5,magic,0, WZ_FIREPILLAR,Fire Pillar +80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,-3:-4:-5:-6:-7:-8:-9:-10:-11:-12:-12,yes,0,0x80,5,magic,0, WZ_FIREPILLAR,Fire Pillar 81,0,6,4,3,0,3,10,1,yes,0,0,0,magic,5, WZ_SIGHTRASHER,Sightrasher 83,9,8,2,3,0,3:3:3:3:3:3:3:3:3:3:14,10,1:1:2:2:3:3:4:4:5:5:15,yes,0,0,0,magic,0, WZ_METEOR,Meteor Storm 84,9,8,1,4,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,2:3:3:4:4:5:5:6:6:7, WZ_JUPITEL,Jupitel Thunder @@ -578,7 +578,7 @@ 532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0, NJ_BUNSINJYUTSU,Mirror Image 533,0,0,0,0,0,0,10,0,no,0,0,0,none,0, NJ_NINPOU,Spirit of the Blade 534,9,8,1,3,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, NJ_KOUENKA,Crimson Fire Petal -535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1, NJ_KAENSIN,Crimson Fire Formation +535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0, NJ_KAENSIN,Crimson Fire Formation 536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0, NJ_BAKUENRYU,Raging Fire Dragon 537,9,8,1,1,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,0, NJ_HYOUSENSOU,Spear of Ice 538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0, NJ_SUITON,Hidden Water diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index ebaf3ab6c..df1cf5c52 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -124,7 +124,7 @@ 77,5,6,1,6,0x28,0,10,1,yes,0,0,0,magic,0, PR_TURNUNDEAD,Turn Undead 78,9,6,1,0,0x1,0,1,0,yes,0,0,0,magic,0, PR_LEXAETERNA,Lex Aeterna 79,9,8,2,6,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, PR_MAGNUS,Magnus Exorcismus -80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,3:4:5:6:7:8:9:10:11:12:12,yes,0,0,5,magic,0, WZ_FIREPILLAR,Fire Pillar +80,9,8,2,3,0x20,1:1:1:1:1:2:2:2:2:2:2,10,-3:-4:-5:-6:-7:-8:-9:-10:-11:-12:-12,yes,0,0,5,magic,0, WZ_FIREPILLAR,Fire Pillar 81,0,6,4,3,0,3,10,1,yes,0,0,0,magic,5, WZ_SIGHTRASHER,Sightrasher 83,9,8,2,3,0,3:3:3:3:3:3:3:3:3:3:14,10,1:1:2:2:3:3:4:4:5:5:15,yes,0,0,0,magic,0, WZ_METEOR,Meteor Storm 84,9,8,1,4,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,2:3:3:4:4:5:5:6:6:7, WZ_JUPITEL,Jupitel Thunder @@ -578,7 +578,7 @@ 532,0,6,4,0,0x1,0,10,1,yes,0,0,0,magic,0, NJ_BUNSINJYUTSU,Mirror Image 533,0,0,0,0,0,0,10,0,no,0,0,0,none,0, NJ_NINPOU,Spirit of the Blade 534,9,8,1,3,0,0,10,1:2:3:4:5:6:7:8:9:10,yes,0,0,0,magic,0, NJ_KOUENKA,Crimson Fire Petal -535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,1, NJ_KAENSIN,Crimson Fire Formation +535,0,8,4,3,0,0,10,1,yes,0,0,0,magic,0, NJ_KAENSIN,Crimson Fire Formation 536,9,8,1,3,0x2,2,5,3,yes,0,0,0,magic,0, NJ_BAKUENRYU,Raging Fire Dragon 537,9,8,1,1,0,0,10,3:4:5:6:7:8:9:10:11:12,yes,0,0,0,magic,0, NJ_HYOUSENSOU,Spear of Ice 538,9,6,2,1,0x1,0,10,1,yes,0,0,0,magic,0, NJ_SUITON,Hidden Water diff --git a/db/re/skill_unit_db.txt b/db/re/skill_unit_db.txt index 87afd2da2..f0f359bcc 100644 --- a/db/re/skill_unit_db.txt +++ b/db/re/skill_unit_db.txt @@ -52,7 +52,7 @@ 125,0x99, , 0, 1,1000,all, 0x000 //HT_TALKIEBOX 140,0x92, , -1, 1,1000,enemy, 0x000 //AS_VENOMDUST 220,0xb0, , 0, 0, -1,all, 0x002 //RG_GRAFFITI -229,0xb1, , 0, 1,1000,enemy, 0x006 //AM_DEMONSTRATION +229,0xb1, , 0, 1, 500,enemy, 0x006 //AM_DEMONSTRATION 254,0x86, , -1, 0, 300,enemy, 0x010 //CR_GRANDCROSS 285,0x9a, , 3, 0, -1,all, 0x010 //SA_VOLCANO 286,0x9b, , 3, 0, -1,all, 0x010 //SA_DELUGE 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 { |