diff options
-rw-r--r-- | conf/battle/monster.conf | 22 | ||||
-rw-r--r-- | conf/battle/skill.conf | 11 | ||||
-rw-r--r-- | db/re/skill_db.txt | 2 | ||||
-rw-r--r-- | src/map/battle.c | 3 | ||||
-rw-r--r-- | src/map/battle.h | 3 | ||||
-rw-r--r-- | src/map/mob.c | 31 | ||||
-rw-r--r-- | src/map/unit.c | 32 |
7 files changed, 68 insertions, 36 deletions
diff --git a/conf/battle/monster.conf b/conf/battle/monster.conf index 9ca8df825..6f63f55be 100644 --- a/conf/battle/monster.conf +++ b/conf/battle/monster.conf @@ -52,14 +52,14 @@ monster_ai: 0 // How often should a monster rethink its chase? // 0: Every 100ms (MIN_MOBTHINKTIME) -// 1: Every cell moved (official) +// 1: Every cell moved // 2: Every 2 cells moved -// 3: Every 3 cells moved (previous setting) +// 3: Every 3 cells moved (official) // x: Every x cells moved // Regardless of this setting, a monster will always rethink its chase if it has // reached its target. Increase this value if you want to make monsters continue // moving after they lost their target (hide, loot picked, etc.). -monster_chase_refresh: 1 +monster_chase_refresh: 3 // Should mobs be able to be warped (add as needed)? // 0: Disable. @@ -216,3 +216,19 @@ mvp_tomb_enabled: yes // This is only invoked under the 'monster' command, @monsterbig, and @monstersmall. (Note 1) // Default: no mob_size_influence: no + +// How should a monster be trapped by an icewall casted directly on it? +// On official servers, monsters can only leave an icewall to the west and south. If their target is north or east of +// them they will continously try to chase it but fail doing so. This brings them into a loop during which they will use +// idle and chase skills. Boss monsters on the other hand will behave like a trapped monster, do not move and will use +// idle and rudeattacked skills (when attacked). +// 0: Monster won't be stuck in icewall at all. +// 1: Monster will behave like a trapped monster. +// 2-255: Number of loops a monster will go through the behavior described above before it frees itself from icewall. +// NOTE: On some servers, normal monsters can free themselves after 15-35 second depending on their speed. On other +// servers, they will be stuck inside icewall until it expires. Also, many official servers (e.g. iRO) have casting +// icewall completely blocked on all maps that have boss monsters on them. +// Default (least exploitable): mob - 75, boss - 0 +// Default (most official): mob - 220, boss - 1 +mob_icewall_walk_block: 220 +boss_icewall_walk_block: 1
\ No newline at end of file diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index 1bb58211a..e6828749b 100644 --- a/conf/battle/skill.conf +++ b/conf/battle/skill.conf @@ -293,13 +293,4 @@ mob_max_skilllvl: 100 // 1: Gutter line system without demi gutter bug // 2-20: Area around caster (2 = 5x5, 3 = 7x7, 4 = 9x9, ..., 20 = 41x41) // Note: If you knock the target out of the area it will only be hit once and won't do splash damage -bowling_bash_area: 0 - -// How many attempts should a monster need until it can escape from an icewall casted directly on it? -// On official servers, monsters can only leave an icewall to the west and south. If their target is north or east of them -// they will continously try to chase it but fail doing so. This brings them into a loop during which they will cast idle -// and rudeattacked skills (if attacked). Official servers have a safety system that eventually allows monsters to escape -// when their walk routine failed many times in row so they won't stay on the loop endlessly. The time for this seems to be -// around 15 seconds for fast monsters and 35 seconds for slow monsters, this equals about 75 attempts. -// Set this to 0 if you don't want monsters to be stuck in icewalls at all. -icewall_walk_block: 75
\ No newline at end of file +bowling_bash_area: 0
\ No newline at end of file diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index 5f1e7c2f2..34639425e 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,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,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 diff --git a/src/map/battle.c b/src/map/battle.c index 88d83f91b..40ef15191 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -6838,7 +6838,8 @@ static const struct battle_data { { "song_timer_reset", &battle_config.song_timer_reset, 0, 0, 1, }, { "snap_dodge", &battle_config.snap_dodge, 0, 0, 1, }, { "monster_chase_refresh", &battle_config.mob_chase_refresh, 1, 0, 30, }, - { "icewall_walk_block", &battle_config.icewall_walk_block, 75, 0, 255, } + { "mob_icewall_walk_block", &battle_config.mob_icewall_walk_block, 75, 0, 255, }, + { "boss_icewall_walk_block", &battle_config.boss_icewall_walk_block, 0, 0, 255, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 6ac2df391..1b6321cbf 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -452,7 +452,8 @@ struct Battle_Config { int mob_size_influence; // Enable modifications on earned experience, drop rates and monster status depending on monster size. [mkbu95] int bowling_bash_area; int mob_chase_refresh; //How often a monster should refresh its chase [Playtester] - int icewall_walk_block; //How long a monster should stay trapped in icewall [Playtester] + int mob_icewall_walk_block; //How a normal monster should be trapped in icewall [Playtester] + int boss_icewall_walk_block; //How a boss monster should be trapped in icewall [Playtester] /** Hercules **/ int skill_trap_type; diff --git a/src/map/mob.c b/src/map/mob.c index eaf8c8468..23706d293 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1429,7 +1429,7 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { //No valid target if (mob->warpchase(md, tbl)) return true; //Chasing this target. - if(md->ud.walktimer != INVALID_TIMER && md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh) + if(md->ud.walktimer != INVALID_TIMER && (!can_move || md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh)) return true; //Walk at least "mob_chase_refresh" cells before dropping the target mob_unlocktarget(md, tick); //Unlock target tbl = NULL; @@ -1442,13 +1442,14 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { if( md->attacked_id == md->target_id ) { //Rude attacked check. if( !battle->check_range(&md->bl, tbl, md->status.rhw.range) - && ( //Can't attack back and can't reach back. + && ( //Can't attack back and can't reach back. (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) - || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] - || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. - || !mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) - || md->walktoxy_fail_count > 0 + || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] + || md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target. + || md->walktoxy_fail_count > 0) ) + || !mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) + ) && md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && !mob->skill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack && can_move && unit->escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape @@ -1466,11 +1467,12 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { || (battle_config.mob_ai&0x2 && !status->check_skilluse(&md->bl, abl, 0, 0)) // Cannot normal attack back to Attacker || (!battle->check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... && ( // Reach check - (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) - || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] - || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. - || !mob->can_reach(md, abl, dist+md->db->range3, MSS_RUSH) - || md->walktoxy_fail_count > 0 + (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) + || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] + || md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target. + || md->walktoxy_fail_count > 0) + ) + || !mob->can_reach(md, abl, dist+md->db->range3, MSS_RUSH) ) ) ) { @@ -1636,6 +1638,9 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { if(battle->check_range(&md->bl, tbl, md->status.rhw.range)) return true; + //Only update target cell / drop target after having moved at least "mob_chase_refresh" cells + if(md->ud.walktimer != INVALID_TIMER && (!can_move || md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh)) + return true; //Out of range... if (!(mode&MD_CANMOVE) || (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0)) @@ -1655,10 +1660,6 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { )) //Current target tile is still within attack range. return true; - //Only update target cell after having moved at least "mob_chase_refresh" cells - if(md->ud.walktimer != INVALID_TIMER && md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh) - return true; - //Follow up if possible. //Hint: Chase skills are handled in the walktobl routine if(!mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) || diff --git a/src/map/unit.c b/src/map/unit.c index 849e9348f..76a5853df 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -108,11 +108,11 @@ int unit_walktoxy_sub(struct block_list *bl) uint8 dir; //Trim the last part of the path to account for range, //but always move at least one cell when requested to move. - for (i = ud->chaserange*10; i > 0 && ud->walkpath.path_len>1;) { + for (i = (ud->chaserange*10)-10; i > 0 && ud->walkpath.path_len>1;) { ud->walkpath.path_len--; dir = ud->walkpath.path[ud->walkpath.path_len]; if(dir&1) - i -= MOVE_DIAGONAL_COST; + i -= MOVE_COST*20; //When chasing, units will target a diamond-shaped area in range [Playtester] else i -= MOVE_COST; ud->to_x -= dirx[dir]; @@ -211,6 +211,7 @@ int unit_step_timer(int tid, int64 tick, int id, intptr_t data) int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) { int i; int x,y,dx,dy; + unsigned char icewall_walk_block; uint8 dir; struct block_list *bl; struct map_session_data *sd; @@ -249,19 +250,29 @@ int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) { dx = dirx[(int)dir]; dy = diry[(int)dir]; + //Get icewall walk block depending on boss mode (players can't be trapped) + if(md && md->status.mode&MD_BOSS) + icewall_walk_block = battle_config.boss_icewall_walk_block; + else if(md) + icewall_walk_block = battle_config.mob_icewall_walk_block; + else + icewall_walk_block = 0; + //Monsters will walk into an icewall from the west and south if they already started walking if(map->getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS) - && (battle_config.icewall_walk_block == 0 || !map->getcell(bl->m,x+dx,y+dy,CELL_CHKICEWALL) || dx < 0 || dy < 0)) + && (icewall_walk_block == 0 || !map->getcell(bl->m,x+dx,y+dy,CELL_CHKICEWALL) || dx < 0 || dy < 0)) return unit->walktoxy_sub(bl); //Monsters can only leave icewalls to the west and south //But if movement fails more than icewall_walk_block times, they can ignore this rule - if(md && md->walktoxy_fail_count < battle_config.icewall_walk_block && map->getcell(bl->m,x,y,CELL_CHKICEWALL) && (dx > 0 || dy > 0)) { + if(md && md->walktoxy_fail_count < icewall_walk_block && map->getcell(bl->m,x,y,CELL_CHKICEWALL) && (dx > 0 || dy > 0)) { //Needs to be done here so that rudeattack skills are invoked md->walktoxy_fail_count++; clif->fixpos(bl); + //Monsters in this situation first use a chase skill, then unlock target and then use an idle skill + if (!(++ud->walk_count%WALK_SKILL_INTERVAL)) + mob->skill_use(md, tick, -1); mob->unlocktarget(md, tick); - //Use idle skill at this point if (!(++ud->walk_count%WALK_SKILL_INTERVAL)) mob->skill_use(md, tick, -1); return 0; @@ -1060,6 +1071,17 @@ int unit_can_move(struct block_list *bl) { return 0; } + + // Icewall walk block special trapped monster mode + if(bl->type == BL_MOB) { + struct mob_data *md = BL_CAST(BL_MOB, bl); + if(md && ((md->status.mode&MD_BOSS && battle_config.boss_icewall_walk_block == 1 && map->getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)) + || (!(md->status.mode&MD_BOSS) && battle_config.mob_icewall_walk_block == 1 && map->getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)))) { + md->walktoxy_fail_count = 1; //Make sure rudeattacked skills are invoked + return 0; + } + } + return 1; } |