Fixes script commands unitwalkto/unitwalk (#7007)

* Fixes #5340.
* Resolves an issue where monsters may tend to lose their target if they are too slow and the destination is too far when using script commands unitwalkto/unitwalk.
* Allow script command unitstopwalk to remove the state tracking for script commands unitwalk/unitwalkto.
* Print a warning to the console if a unit is forced to walk again and hasn't yet reached its initial destination.
Thanks to @NeutralDev and @Lemongrass3110!
This commit is contained in:
Aleos 2022-06-07 15:07:51 -04:00 committed by GitHub
parent 2bb79d0200
commit aad3a70bbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 7 deletions

View File

@ -8270,6 +8270,8 @@ values (can be combined using the pipe operator):
USW_MOVE_FULL_CELL = Enable moving to the next cell when unit was already half-way there (may cause on-touch/place side-effects, such as a scripted map change).
USW_FORCE_STOP = Force stop moving.
This command will also remove the state tracking used for 'unitwalk' and 'unitwalkto'.
---------------------------------------
*unittalk <GID>,"<text>"{,flag};

View File

@ -1687,6 +1687,10 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
if(md->bl.prev == nullptr || md->status.hp == 0)
return false;
// Monsters force-walked by script commands should not be searching for targets.
if (md->ud.state.force_walk)
return false;
if (DIFF_TICK(tick, md->last_thinktime) < MIN_MOBTHINKTIME)
return false;
@ -2005,6 +2009,10 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
if(md->bl.prev == NULL)
return 0;
// Monsters force-walked by script commands should not be searching for targets.
if (md->ud.state.force_walk)
return false;
t_tick tick = va_arg(args,t_tick);
if (battle_config.mob_ai&0x20 && map_getmapdata(md->bl.m)->users>0)

View File

@ -19310,6 +19310,13 @@ BUILDIN_FUNC(unitwalk)
ud = unit_bl2ud(bl);
// Unit was already forced to walk.
if (ud != nullptr && ud->state.force_walk) {
script_pushint(st, 0);
ShowWarning("buildin_%s: Unit has already been forced to walk and not reached it's destination yet.\n", cmd);
return SCRIPT_CMD_FAILURE;
}
if (bl->type == BL_NPC) {
if (!((TBL_NPC*)bl)->status.hp)
status_calc_npc(((TBL_NPC*)bl), SCO_FIRST);
@ -19321,8 +19328,11 @@ BUILDIN_FUNC(unitwalk)
int x = script_getnum(st,3);
int y = script_getnum(st,4);
if (script_pushint(st, unit_can_reach_pos(bl,x,y,0)))
if (script_pushint(st, unit_can_reach_pos(bl,x,y,0))) {
if (ud != nullptr)
ud->state.force_walk = true;
add_timer(gettick()+50, unit_delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); // Need timer to avoid mismatches
}
} else {
struct block_list* tbl = map_id2bl(script_getnum(st,3));
@ -19330,8 +19340,11 @@ BUILDIN_FUNC(unitwalk)
ShowError("buildin_unitwalk: Bad target destination.\n");
script_pushint(st, 0);
return SCRIPT_CMD_FAILURE;
} else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL)))
} else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL))) {
if (ud != nullptr)
ud->state.force_walk = true;
add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches
}
off = 4;
}
@ -19477,10 +19490,21 @@ BUILDIN_FUNC(unitstopwalk)
if (script_hasdata(st, 3))
flag = script_getnum(st, 3);
if(script_rid2bl(2,bl))
unit_stop_walking(bl, flag);
if(script_rid2bl(2,bl)) {
unit_data *ud = unit_bl2ud(bl);
return SCRIPT_CMD_SUCCESS;
if (ud != nullptr)
ud->state.force_walk = false;
if (unit_stop_walking(bl, flag) == 0 && flag != USW_FORCE_STOP) {
ShowWarning("buildin_unitstopwalk: Unable to find unit or unit is not walking.\n");
return SCRIPT_CMD_FAILURE;
}
return SCRIPT_CMD_SUCCESS;
} else {
return SCRIPT_CMD_FAILURE;
}
}
/**

View File

@ -435,7 +435,7 @@ static TIMER_FUNC(unit_walktoxy_timer)
//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 < icewall_walk_block && map_getcell(bl->m,x,y,CELL_CHKICEWALL) && (dx > 0 || dy > 0)) {
if(md && !ud->state.force_walk && 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);
@ -472,6 +472,8 @@ static TIMER_FUNC(unit_walktoxy_timer)
}
#endif
ud->state.force_walk = false;
if (ud->walk_done_event[0]){
char walk_done_event[EVENT_NAME_LENGTH];
@ -526,7 +528,7 @@ static TIMER_FUNC(unit_walktoxy_timer)
md->min_chase--;
// Walk skills are triggered regardless of target due to the idle-walk mob state.
// But avoid triggering on stop-walk calls.
if(tid != INVALID_TIMER &&
if(!ud->state.force_walk && tid != INVALID_TIMER &&
!(ud->walk_count%WALK_SKILL_INTERVAL) &&
map[bl->m].users > 0 &&
mobskill_use(md, tick, -1)) {

View File

@ -58,6 +58,7 @@ struct unit_data {
unsigned blockedmove : 1;
unsigned blockedskill : 1;
unsigned ignore_cell_stack_limit : 1;
bool force_walk; ///< Used with script commands unitwalk/unitwalkto. Disables monster idle and random walk.
} state;
char walk_done_event[EVENT_NAME_LENGTH];
char title[NAME_LENGTH];