Fixed looters getting stuck (#6958)

- Fixes #6939
- Looters will now use complex pathing to find a way to an item they can see
- Monsters no longer stop when using NPC_EMOTION or NPC_EMOTION_ON
- Added a security check to prevent endless loops when easy pathing is used (no longer used by default)

Special thanks to @secretdataz.
This commit is contained in:
Playtester 2022-05-18 23:25:37 +02:00 committed by GitHub
parent 20d9fa6cc7
commit f5e75d28ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 14 additions and 25 deletions

View File

@ -978,29 +978,14 @@ bool mob_is_chasing(int state)
} }
/*========================================== /*==========================================
* Reachability to a Specification ID existence place * Checks if a monster can reach a target by walking
* state indicates type of 'seek' mob should do: * Range: Maximum number of cells to be walked
* - MSS_LOOT: Looking for item, path must be easy.
* - MSS_RUSH: Chasing attacking player, path is complex
* - MSS_FOLLOW: Initiative/support seek, path is complex
*------------------------------------------*/ *------------------------------------------*/
int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state) int mob_can_reach(struct mob_data *md,struct block_list *bl,int range)
{ {
int easy = 0;
nullpo_ret(md); nullpo_ret(md);
nullpo_ret(bl); nullpo_ret(bl);
switch (state) { return unit_can_reach_bl(&md->bl, bl, range, 0, NULL, NULL);
case MSS_RUSH:
case MSS_FOLLOW:
easy = 0; //(battle_config.mob_ai&0x1?0:1);
break;
case MSS_LOOT:
default:
easy = 1;
break;
}
return unit_can_reach_bl(&md->bl, bl, range, easy, NULL, NULL);
} }
/*========================================== /*==========================================
@ -1023,7 +1008,7 @@ int mob_linksearch(struct block_list *bl,va_list ap)
&& !md->target_id) && !md->target_id)
{ {
md->last_linktime = tick; md->last_linktime = tick;
if( mob_can_reach(md,target,md->db->range2, MSS_FOLLOW) ){ // Reachability judging if( mob_can_reach(md,target,md->db->range2) ){ // Reachability judging
md->target_id = target->id; md->target_id = target->id;
md->min_chase=md->db->range3; md->min_chase=md->db->range3;
return 1; return 1;
@ -1382,7 +1367,7 @@ static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
target = va_arg(ap,struct block_list**); target = va_arg(ap,struct block_list**);
dist = distance_bl(&md->bl, bl); dist = distance_bl(&md->bl, bl);
if (mob_can_reach(md,bl,dist+1, MSS_LOOT) && ( if (mob_can_reach(md, bl, md->db->range3) && (
(*target) == nullptr || (*target) == nullptr ||
(battle_config.monster_loot_search_type && md->target_id > bl->id) || (battle_config.monster_loot_search_type && md->target_id > bl->id) ||
(!battle_config.monster_loot_search_type && !check_distance_bl(&md->bl, *target, dist)) // New target closer than previous one. (!battle_config.monster_loot_search_type && !check_distance_bl(&md->bl, *target, dist)) // New target closer than previous one.
@ -1755,7 +1740,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
|| md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target. || md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target.
|| md->walktoxy_fail_count > 0) || md->walktoxy_fail_count > 0)
) )
|| !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) || !mob_can_reach(md, tbl, md->min_chase)
) )
&& md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
&& !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack && !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack
@ -1780,7 +1765,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
|| md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target. || md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target.
|| md->walktoxy_fail_count > 0) || md->walktoxy_fail_count > 0)
) )
|| !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH) || !mob_can_reach(md, abl, dist+md->db->range3)
) )
) ) ) )
{ // Rude attacked { // Rude attacked
@ -1880,7 +1865,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
if (!can_move) //Stuck. Wait before walking. if (!can_move) //Stuck. Wait before walking.
return true; return true;
md->state.skillstate = MSS_LOOT; md->state.skillstate = MSS_LOOT;
if (!unit_walktobl(&md->bl, tbl, 0, 1)) if (!unit_walktobl(&md->bl, tbl, 0, 0))
mob_unlocktarget(md, tick); //Can't loot... mob_unlocktarget(md, tick); //Can't loot...
return true; return true;
} }
@ -1978,7 +1963,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
//Follow up if possible. //Follow up if possible.
//Hint: Chase skills are handled in the walktobl routine //Hint: Chase skills are handled in the walktobl routine
if(!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) || if(!mob_can_reach(md, tbl, md->min_chase) ||
!unit_walktobl(&md->bl, tbl, md->status.rhw.range, 2)) !unit_walktobl(&md->bl, tbl, md->status.rhw.range, 2))
mob_unlocktarget(md,tick); mob_unlocktarget(md,tick);

View File

@ -531,6 +531,7 @@ static TIMER_FUNC(unit_walktoxy_timer)
map[bl->m].users > 0 && map[bl->m].users > 0 &&
mobskill_use(md, tick, -1)) { mobskill_use(md, tick, -1)) {
if (!(ud->skill_id == NPC_SELFDESTRUCTION && ud->skilltimer != INVALID_TIMER) if (!(ud->skill_id == NPC_SELFDESTRUCTION && ud->skilltimer != INVALID_TIMER)
&& ud->skill_id != NPC_EMOTION && ud->skill_id != NPC_EMOTION_ON //NPC_EMOTION doesn't make the monster stop
&& md->state.skillstate != MSS_WALK) //Walk skills are supposed to be used while walking && md->state.skillstate != MSS_WALK) //Walk skills are supposed to be used while walking
{ // Skill used, abort walking { // Skill used, abort walking
clif_fixpos(bl); // Fix position as walk has been cancelled. clif_fixpos(bl); // Fix position as walk has been cancelled.
@ -855,6 +856,9 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, unsi
//Should walk on the same cell as target (for looters) //Should walk on the same cell as target (for looters)
ud->to_x = tbl->x; ud->to_x = tbl->x;
ud->to_y = tbl->y; ud->to_y = tbl->y;
//Because of the change of target position the easy walkpath could fail
//Note: Easy walking is no longer used by default, but we keep this to prevent endless loops [Playtester]
flag &= ~1;
} }
ud->state.walk_easy = flag&1; ud->state.walk_easy = flag&1;