diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 4fad10c048..86a5475ac2 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -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 diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 9e1a384a2b..1a34aea3e2 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -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. diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 449f8fb1bc..8f5d4820d0 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -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_castsx)>(24.0 + dirx[ud->walkpath.path[ud->walkpath.path_pos]] * 16.0 * cell_percent); + ud->sy = static_castsy)>(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; } /** diff --git a/src/map/unit.hpp b/src/map/unit.hpp index 1a2c6178b9..eaa4e990b7 100644 --- a/src/map/unit.hpp +++ b/src/map/unit.hpp @@ -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);