Monster Losing Target Display (#8479)

- When a monster loses its target, it will now properly display movement to the next cell rather than snapping back to the previous cell
- Looters will no longer spam movement packets to the client when they go for loot
- Added some base implementation for sub-cell coordinates
- Fixes #8232

Co-authored-by: Lemongrass3110
This commit is contained in:
Playtester
2024-07-06 12:51:58 +02:00
committed by GitHub
parent 0a977c1fd7
commit 78a2babe4d
4 changed files with 90 additions and 5 deletions

View File

@@ -180,7 +180,7 @@ static inline void WBUFPOS(uint8* p, unsigned short pos, short x, short y, unsig
// client-side: x0+=sx0*0.0625-0.5 and y0+=sy0*0.0625-0.5
static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) {
static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, short x1, short y1, uint8 sx0, uint8 sy0) {
p += pos;
p[0] = (uint8)(x0>>2);
p[1] = (uint8)((x0<<6) | ((y0>>4)&0x3f));
@@ -1436,7 +1436,7 @@ static void clif_set_unit_walking( struct block_list& bl, map_session_data* tsd,
p.virtue = (sc) ? sc->opt3 : 0;
p.isPKModeON = (sd && sd->status.karma) ? 1 : 0;
p.sex = vd->sex;
WBUFPOS2( &p.MoveData[0], 0, bl.x, bl.y, ud.to_x, ud.to_y, 8, 8 );
WBUFPOS2(&p.MoveData[0], 0, bl.x, bl.y, ud.to_x, ud.to_y, ud.sx, ud.sy);
p.xSize = p.ySize = (sd) ? 5 : 0;
p.clevel = clif_setlevel( &bl );
#if PACKETVER >= 20080102

View File

@@ -1566,7 +1566,7 @@ int mob_unlocktarget(struct mob_data *md, t_tick tick)
break;
default:
mob_stop_attack(md);
mob_stop_walking(md,1); //Stop chasing.
unit_stop_walking_soon(md->bl); //Stop chasing.
if (status_has_mode(&md->status,MD_ANGRY) && !md->state.aggressive)
md->state.aggressive = 1; //Restore angry state when switching to idle
md->state.skillstate = MSS_IDLE;
@@ -1908,6 +1908,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
md->state.skillstate = MSS_LOOT;
if (!unit_walktobl(&md->bl, tbl, 0, 0))
mob_unlocktarget(md, tick); //Can't loot...
else
unit_set_target(&md->ud, tbl->id); //Remember current loot target
return true;
}
//Within looting range.

View File

@@ -397,6 +397,9 @@ static TIMER_FUNC(unit_walktoxy_timer)
}
ud->walktimer = INVALID_TIMER;
// As movement to next cell finished, set sub-cell position to center
ud->sx = 8;
ud->sy = 8;
if (bl->prev == nullptr)
return 0; // Stop moved because it is missing from the block_list
@@ -1404,6 +1407,78 @@ int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type)
return 0;
}
/**
* Updates the walkpath of a unit to end after 0.5-1.5 cells moved
* Sends required packet for proper display on the client using subcoordinates
* @param bl: Object to stop walking
*/
void unit_stop_walking_soon(struct block_list& bl)
{
struct unit_data* ud = unit_bl2ud(&bl);
if (ud == nullptr)
return;
if (ud->walktimer == INVALID_TIMER)
return;
if (ud->walkpath.path_pos + 1 >= ud->walkpath.path_len)
return;
const struct TimerData* td = get_timer(ud->walktimer);
if (td == nullptr)
return;
// Get how much percent we traversed on the timer
double cell_percent = 1.0 - ((double)DIFF_TICK(td->tick, gettick()) / (double)td->data);
short ox = bl.x, oy = bl.y; // Remember original x and y coordinates
short path_remain = 1; // Remaining path to walk
if (cell_percent > 0.0 && cell_percent < 1.0) {
// Set subcell coordinates according to timer
// This gives a value between 8 and 39
ud->sx = static_cast<decltype(ud->sx)>(24.0 + dirx[ud->walkpath.path[ud->walkpath.path_pos]] * 16.0 * cell_percent);
ud->sy = static_cast<decltype(ud->sy)>(24.0 + diry[ud->walkpath.path[ud->walkpath.path_pos]] * 16.0 * cell_percent);
// 16-31 reflect sub position 0-15 on the current cell
// 8-15 reflect sub position 8-15 at -1 main coordinate
// 32-39 reflect sub position 0-7 at +1 main coordinate
if (ud->sx < 16 || ud->sy < 16 || ud->sx > 31 || ud->sy > 31) {
path_remain = 2;
if (ud->sx < 16) bl.x--;
if (ud->sy < 16) bl.y--;
if (ud->sx > 31) bl.x++;
if (ud->sy > 31) bl.y++;
}
ud->sx %= 16;
ud->sy %= 16;
}
else if (cell_percent >= 1.0) {
// Assume exactly one cell moved
bl.x += dirx[ud->walkpath.path[ud->walkpath.path_pos]];
bl.y += diry[ud->walkpath.path[ud->walkpath.path_pos]];
path_remain = 2;
}
// Shorten walkpath
if (ud->walkpath.path_pos + path_remain < ud->walkpath.path_len) {
ud->walkpath.path_len = ud->walkpath.path_pos + path_remain;
ud->to_x = ox;
ud->to_y = oy;
for (int i = 0; i < path_remain; i++) {
ud->to_x += dirx[ud->walkpath.path[ud->walkpath.path_pos + i]];
ud->to_y += diry[ud->walkpath.path[ud->walkpath.path_pos + i]];
}
// Send movement packet with calculated coordinates and subcoordinates
clif_move(*ud);
}
// Reset coordinates
bl.x = ox;
bl.y = oy;
ud->sx = 8;
ud->sy = 8;
}
/**
* Stops a unit from walking
* @param bl: Object to stop walking
@@ -1446,8 +1521,12 @@ int unit_stop_walking(struct block_list *bl,int type)
unit_walktoxy_timer(INVALID_TIMER, tick, bl->id, ud->walkpath.path_pos);
}
if(type&USW_FIXPOS)
clif_fixpos( *bl );
if (type&USW_FIXPOS) {
// Stop on cell center
ud->sx = 8;
ud->sy = 8;
clif_fixpos(*bl);
}
ud->walkpath.path_len = 0;
ud->walkpath.path_pos = 0;
@@ -3014,6 +3093,8 @@ void unit_dataset(struct block_list *bl)
ud->attackabletime =
ud->canact_tick =
ud->canmove_tick = gettick();
ud->sx = 8;
ud->sy = 8;
}
/**

View File

@@ -27,6 +27,7 @@ struct unit_data {
struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
short attacktarget_lv;
short to_x, to_y;
uint8 sx, sy; // Subtile position (0-15, with 8 being center of cell)
short skillx, skilly;
uint16 skill_id, skill_lv;
int skilltarget;
@@ -114,6 +115,7 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir);
TIMER_FUNC(unit_delay_walktoxy_timer);
TIMER_FUNC(unit_delay_walktobl_timer);
void unit_stop_walking_soon(struct block_list& bl);
// Causes the target object to stop moving.
int unit_stop_walking(struct block_list *bl,int type);
bool unit_can_move(struct block_list *bl);