Issue information

Issue ID
#3078
Status
Fixed
Severity
Medium
Started
Hercules Elf Bot
May 15, 2009 10:56
Last Post
Hercules Elf Bot
May 15, 2009 10:56
Confirmation
N/A

Hercules Elf Bot - May 15, 2009 10:56

Originally posted by [b]theultramage[/b]
http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=3078

There is an unexpected code execution path when calculating knockback, which can lead to a state where a player is left standing in the "unwalkable darkness" of a map.

The scenario is:
1. camp near a warp
2. get a knockbacking mob to rush you (ex: Ferus)
3. try to run away through the warp
4. get knockbacked just as you are about to reach the warp

The outcome:
You appear on the destination map, but with the x/y coords of the originating map. Thus landing in the 'darkness' and unless you have a way to flywing/bwing/tele out of there, you're not getting out. This position is not walkable yet it saves, and you can log in and out on the same spot.

See function skill_blown:
CODE
int skill_blown(struct block_list* src, struct block_list* target, int count, int direction, int flag)
{
    ret=path_blownpos(target->m,target->x,target->y,dx,dy,count);
    nx = ret>>16;
    ny = ret&0xffff;
<< here, the new x/y coords are stored in temp variables >>

...

    if (!su)
        unit_stop_walking(target,0);
<< here unit_stop_walking does some internal processing, explained below >>

...

        map_moveblock(target, nx, ny, gettick());
<< here the x/y coordinates are modified >>
}

Now see unit_stop_walking:
CODE
int unit_stop_walking(struct block_list *bl,int type)
{
...
    if ((type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell.
        || (td && DIFF_TICK(td->tick, tick) <= td->data/2)) //Enough time has passed to cover half-cell
    {    
        ud->walkpath.path_len = ud->walkpath.path_pos+1;
        unit_walktoxy_timer(-1, tick, bl->id, ud->walkpath.path_pos);
    }
...
}

And unit_walktoxy_timer:
CODE
static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr data)
{
...
        if(map_getcell(bl->m,x,y,CELL_CHKNPC)) {
            npc_touch_areanpc(sd,bl->m,x,y);
...
}

So basically,
skill_blown remembers the x/y values,
then unit_stop_walking itself unexepectedly alters the x/y/m coordinates inside (by activating the warp),
and then skill_blown blindly rewrites the already changed values.

Finally, here's a screenshot that demonstrates how it looks like. The char used @refresh, his partymates see his dot on the map, and he could see nearby mobs - proving that the position he's standing on is really where he is server-side.
Attached Image


This post has been edited by theultramage: May 15 2009, 03:59 AM