Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharp Shooting range bug #658

Closed
landergate opened this issue Sep 30, 2015 · 10 comments
Closed

Sharp Shooting range bug #658

landergate opened this issue Sep 30, 2015 · 10 comments

Comments

@landergate
Copy link

@landergate landergate commented Sep 30, 2015

Bump: https://rathena.org/board/tracker/issue-7360-sharp-shooting-kamaitachi-damage-path-area/

For some reason, Sharp Shooting has abnormal damage range.
Like Mikado mentioned - around 18-21 cells.
This is highly abusable on WoE, as you can't see enemy char spamming with it out of the screen area.

Must be not more than 12, no matter how close/far the target is.

Reproduce video: https://youtu.be/fvhAVFCuPUE
Watch around 03:23

@anacondaq
Copy link

@anacondaq anacondaq commented Sep 30, 2015

Is this bug still exist? I though it's already fixed.
Which revision? How reproduce?

@Playtester
Copy link
Member

@Playtester Playtester commented Sep 30, 2015

Range should be 13 tiles (well 1-2 more because of AoE around each cell). Seems to be fine in skill_db.txt too. Maxcount is 13 and splash is 2.

@anacondaq
Copy link

@anacondaq anacondaq commented Oct 26, 2015

Btw, @Playtester is it at server-side coded or at client?
I know some cheat-software, which bypass range checks in game client, and with this cheat-tool cheater can use spells on enemies out the range (20+ range) for example for sharp shooting.

So, my question in next:
Is it server-side calculated range? Or at client-serverside?
Is current range at server-side protected against client-based cheat tools?

@Playtester
Copy link
Member

@Playtester Playtester commented Oct 26, 2015

Well, the client knows the ranges because it needs to know where to walk before using the skill. But if you hack the client to say a higher range, the server should still deny the skill request the client sends.

Could be that it does not for properly for sharp shooting as the only information it takes from the target is the direction between you and the target. The spell's AoE should still be 13 cells.

If it goes up to the target then the problem is that instead of 13 cells AoE effect it creates a "from me to target" AoE effect.

@MrAntares
Copy link

@MrAntares MrAntares commented Oct 29, 2015

Same with Cannon Spear

@Playtester
Copy link
Member

@Playtester Playtester commented Jan 31, 2016

I tested this thoroughly now and it turns out that Aegis doesn't even use a path algorithm for it. Instead, they determine an AoE effect based on the direction between you and the target. So it basically works like Brandish Spear.

These are the cells that can be hit (yellow = targetting east, red = targetting south-east, orange = both):

path-sharpshooting

It's interesting, because the monster you target might actually be on a cell that you can't even hit. Aegis however has a fallback: If the area skill doesn't hit any target, then the monster originally targetted by the skill will be hit instead.

@Playtester
Copy link
Member

@Playtester Playtester commented Jan 31, 2016

Tested full AoE for First Wind Level 1 and Level 5 now too. It uses exactly the same algorithm:

path-firstwind

Note: Target range of First Wind is also 5:6:7:8:9 and not 9 on all levels.

@Playtester
Copy link
Member

@Playtester Playtester commented Jan 31, 2016

Official path function (not optimized but it works):

/*========================================== [Playtester]
* Calls the given function for every object of a type that is on a path.
* The path goes into one of the eight directions and the direction is determined by the given coordinates.
* The path has a length, a width and an offset.
* The cost for diagonal movement is the same as for linear movement.
* @param m: ID of map
* @param x0: Start X
* @param y0: Start Y
* @param x1: X to calculate direction against
* @param y1: Y to calculate direction against
* @param range: Determines width of the path (width = range*2+1 cells)
* @param length: Length of the path
* @param offset: Move the whole path into the direction
* @param type: Type of bl to search for
*------------------------------------------*/
int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,int16 y0,int16 x1,int16 y1,int16 range,int length,int offset,int type,...)
{
    int returnCount = 0;  //Total sum of returned values of func()

    int i, blockcount = bl_list_count;
    struct block_list *bl;
    int seed, linelength, linepos, sx, sy, x, y, bx, by, srcx = x0, srcy = y0;
    uint8 dir = map_calc_dir_xy(x0, y0, x1, y1, 6);
    short dx = dirx[dir];
    short dy = diry[dir];
    va_list ap;

    if (m < 0)
        return 0;

    if (length < 1)
        return 0;

    //Move start point by offset
    x0 = x0 + dx*offset;
    y0 = y0 + dy*offset;
    //Calculate target coordinate
    x1 = x0 + dx*length;
    y1 = y0 + dy*length;

    if (type&~BL_MOB) {
        //Find each seed cell for moving along the line, diagonal directions have 2*range more seeds
        for (seed = 0; seed <= (1 + (dir % 2)) * 2 * range; seed++) {
            int limit = (2 * range) + 1;
            sx = x0 + (dirx[(dir + 2) % 8] * ((seed%limit) - range));
            sy = y0 + (diry[(dir + 2) % 8] * ((seed%limit) - range));
            //Diagonal seeds
            if (seed >= limit) {
                sx = sx + dirx[(dir + 1) % 8];
                sy = sy + diry[(dir + 1) % 8];
                linelength = length - 1;
            }
            else {
                linelength = length;
            }
            //Move along the line from seed
            for (linepos = 0; linepos < linelength; linepos++) {
                x = sx + dx*linepos;
                y = sy + dy*linepos;            
                //Doesn't hit the source cell
                if (x == srcx && y == srcy)
                    continue;
                //If no line of sight from src then no need to compute further
                if (!path_search_long(NULL, m, srcx, srcy, x, y, CELL_CHKWALL))
                    continue;
                bx = x / BLOCK_SIZE;
                by = y / BLOCK_SIZE;
                for (bl = map[m].block[bx + by * map[m].bxs]; bl != NULL; bl = bl->next) {
                    if (bl->prev && bl->type&type && bl_list_count < BL_LIST_MAX && bl->x == x && bl->y == y)
                        bl_list[bl_list_count++] = bl;
                }
            }
        }
    }
    if (type&BL_MOB) {
        //Find each seed cell for moving along the line, diagonal directions have 2*range more seeds
        for (seed = 0; seed <= (1 + (dir % 2)) * 2 * range; seed++) {
            int limit = (2 * range) + 1;
            sx = x0 + (dirx[(dir + 2) % 8] * ((seed%limit) - range));
            sy = y0 + (diry[(dir + 2) % 8] * ((seed%limit) - range));
            //Diagonal seeds
            if (seed >= limit) {
                sx = sx + dirx[(dir + 1) % 8];
                sy = sy + diry[(dir + 1) % 8];
                linelength = length - 1;
            }
            else {
                linelength = length;
            }
            //Move along the line from seed
            for (linepos = 0; linepos < linelength; linepos++) {
                x = sx + dx*linepos;
                y = sy + dy*linepos;
                //Doesn't hit the source cell
                if (x == srcx && y == srcy)
                    continue;
                //If no line of sight from src then no need to compute further
                if (!path_search_long(NULL, m, srcx, srcy, x, y, CELL_CHKWALL))
                    continue;
                bx = x / BLOCK_SIZE;
                by = y / BLOCK_SIZE;
                for (bl = map[m].block_mob[bx + by * map[m].bxs]; bl != NULL; bl = bl->next) {
                    if (bl->prev && bl_list_count < BL_LIST_MAX && bl->x == x && bl->y == y)
                        bl_list[bl_list_count++] = bl;
                }
            }
        }
    }

    if( bl_list_count >= BL_LIST_MAX )
        ShowWarning("map_foreachinpath: block count too many!\n");

    map_freeblock_lock();

    for( i = blockcount; i < bl_list_count; i++ )
        if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasn't queued for deletion.
            va_start(ap, type);
            returnCount += func(bl_list[ i ], ap);
            va_end(ap);
        }

    map_freeblock_unlock();

    bl_list_count = blockcount;
    return returnCount;
}

@Playtester
Copy link
Member

@Playtester Playtester commented Feb 1, 2016

I tested Brandish thoroughly now. Turns out it uses the same algorithm!
Brandish deals different damage depending on area.
Violet = Highest damage
Red = High damage
Orange = Medium damage
Yellow = Low damage

path-brandish

@Playtester
Copy link
Member

@Playtester Playtester commented Feb 2, 2016

Tested Flame Launcher and Cannon Spear. AoE is the same on all levels.

Left - Flame Lauchner, Right - Cannon Spear

path-3rdjob

Important to note: These two skills don't actually hit the target if it isn't in the AoE, unlike all the other line of damage skills.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants