diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf index 0e033bbb10..71998453f3 100644 --- a/conf/battle/skill.conf +++ b/conf/battle/skill.conf @@ -337,3 +337,12 @@ stormgust_knockback: yes // as Fixed Casting Time, and the rest (80%) as Variable Casting Time. // Put it 0 to disable default Fixed Casting Time (just like -1 is the skill_cast_db.txt). default_fixed_castrate: 20 + +// On official servers, skills that hit all targets on a path (e.g. Focused Arrow Strike and First Wind) first +// calculate one of the eight directions and then apply an AoE based on that direction. This means there can be +// areas that such skills can't hit. If you target a monster in such an area, only this monster will be hit. +// The 3rd job skills Flame Launcher and Cannon Spear can completely miss. +// Set this to "no" to calculate a path from the caster to the target instead and hit everything near that path. +// You can adjust splash and maxcount in the skill_db to adjust the width and length of these skills. +// Note: Brandish Spear will always use this algorithm due to its special damage behavior. +skill_eightpath_algorithm: yes diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt index 232ad0a011..03de005427 100644 --- a/db/pre-re/skill_db.txt +++ b/db/pre-re/skill_db.txt @@ -148,7 +148,7 @@ // Knight 55,0,0,0,0,0,0,10,0,no,0,0,0,weapon,0,0x0, KN_SPEARMASTERY,Spear Mastery 56,-2,8,1,-1,0,0,10,3,no,0,0,0,weapon,0,0x0, KN_PIERCE,Pierce -57,-2,6,1,-1,0x1,0,10,1,no,0,0,0,weapon,3,0x20000, KN_BRANDISHSPEAR,Brandish Spear +57,-2,6,1,-1,0x1,2,10,1,no,0,0,5,weapon,2,0x20000, KN_BRANDISHSPEAR,Brandish Spear 58,-4,6,1,-1,0x2,0,10,1,no,0,0,0,weapon,6,0x0, KN_SPEARSTAB,Spear Stab 59,3:5:7:9:11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, KN_SPEARBOOMERANG,Spear Boomerang 60,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, KN_TWOHANDQUICKEN,Twohand Quicken @@ -550,7 +550,7 @@ // Sniper 380,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, SN_SIGHT,Falcon Eyes 381,5,8,1,-3,0x40,0,5,1,yes,0,0,0,misc,0,0x80, SN_FALCONASSAULT,Falcon Assault -382,9,8,1,-1,0,2,5,1,yes,0,0,13,weapon,0,0x0, SN_SHARPSHOOTING,Focused Arrow Strike +382,9,8,1,-1,0,1,5,1,yes,0,0,14,weapon,0,0x0, SN_SHARPSHOOTING,Focused Arrow Strike 383,0,6,4,0,0x3,-1,10,1,yes,0,0,0,weapon,0,0x0, SN_WINDWALK,Wind Walker //**** @@ -767,7 +767,7 @@ 539,0,6,4,1,0x2,3,5,1,yes,0,0,0,magic,0,0x0, NJ_HYOUSYOURAKU,Ice Meteor 540,9,8,1,4,0,0,10,1:2:2:3:3:4:4:5:5:6,yes,0,0,0,magic,0,0x0, NJ_HUUJIN,Wind Blade 541,9,6,4,4,0x2,2:2:3:3:4,5,1,yes,0,0,0,magic,0,0x0, NJ_RAIGEKISAI,Lightning Strike of Destruction -542,9,8,1,4,0,3,5,1,yes,0,0,5:6:7:8:9,magic,0,0x0, NJ_KAMAITACHI,Kamaitachi +542,5:6:7:8:9,8,1,4,0,1,5,1,yes,0,0,5:6:7:8:9,magic,0,0x0, NJ_KAMAITACHI,Kamaitachi 543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul 544,-5,6,1,0,0x40,0,10,1,no,0,0,0,weapon,0,0x0, NJ_ISSEN,Final Strike @@ -779,11 +779,11 @@ //**** // Additional NPC Skills (Episode 11.3) 653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake -654,9,6,1,3,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_FIREBREATH,Fire Breath -655,9,6,1,1,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ICEBREATH,Ice Breath -656,9,6,1,4,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_THUNDERBREATH,Thunder Breath -657,9,6,1,5,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ACIDBREATH,Acid Breath -658,9,6,1,7,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_DARKNESSBREATH,Darkness Breath +654,6,6,1,3,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_FIREBREATH,Fire Breath +655,6,6,1,1,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ICEBREATH,Ice Breath +656,6,6,1,4,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_THUNDERBREATH,Thunder Breath +657,6,6,1,5,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ACIDBREATH,Acid Breath +658,6,6,1,7,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_DARKNESSBREATH,Darkness Breath 659,0,6,4,0,0x3,2:5:8:11:14,5,1,no,0,0x2,0,none,0,0x0, NPC_DRAGONFEAR,Dragon Fear 660,-9,6,1,-1,0,0,5,1,no,0,0x2,0,weapon,0,0x0, NPC_BLEEDING,Bleeding 661,0,6,4,0,0x2,7,5,1,no,0,0x2,0,weapon,7,0x0, NPC_PULSESTRIKE,Pulse Strike @@ -1023,7 +1023,7 @@ 2256,11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, NC_BOOSTKNUCKLE,Boost Knuckle 2257,3,6,1,-1,0,0,3,1,no,0,0,0,weapon,0,0x0, NC_PILEBUNKER,Pile Bunker 2258,13,6,1,-1,0x2,1,3,1,no,0,0,0,weapon,0,0x0, NC_VULCANARM,Vulcan Arm -2259,7,6,1,3,0,2,3,1,no,0,0,5,weapon,0,0x0, NC_FLAMELAUNCHER,Flame Launcher +2259,5,6,1,3,0,1,3,1,no,0,0,5,weapon,0,0x0, NC_FLAMELAUNCHER,Flame Launcher 2260,7,6,2,1,0x2,2:3:4,3,1,no,0,0x40000,0,weapon,0,0x0, NC_COLDSLOWER,Cold Slower 2261,9:11:13,6,1,-1,0x42,3:2:1,3,1,no,0,0,0,weapon,0,0x0, NC_ARMSCANNON,Arm Cannon 2262,0,6,4,0,0x1,0,3,1,no,0,0,0,none,0,0x0, NC_ACCELERATION,Acceleration @@ -1075,7 +1075,7 @@ //**** // LG Royal Guard -2307,11,8,1,-1,0,2,5,1,no,0,0,10,weapon,0,0x0, LG_CANNONSPEAR,Cannon Spear +2307,11,8,1,-1,0,1,5,1,no,0,0,11,weapon,0,0x0, LG_CANNONSPEAR,Cannon Spear 2308,7,6,1,-1,0,0,10,1,no,0,0,0,weapon,0,0x0, LG_BANISHINGPOINT,Banishing Point 2309,0,6,4,0,0x3,2,3,1,no,0,0,0,none,0,0x0, LG_TRAMPLE,Trample 2310,1,6,1,0,0,0,5,1,no,0,0,0,weapon,0,0x0, LG_SHIELDPRESS,Shield Press diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index a3c7c80d04..4eafedfb52 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -148,7 +148,7 @@ // Knight 55,0,0,0,0,0,0,10,0,no,0,0,0,weapon,0,0x0, KN_SPEARMASTERY,Spear Mastery 56,-2,8,1,-1,0,0,10,3,no,0,0,0,weapon,0,0x0, KN_PIERCE,Pierce -57,-2,6,1,-1,0x1,0,10,1,no,0,0,0,weapon,3,0x20000, KN_BRANDISHSPEAR,Brandish Spear +57,-2,6,1,-1,0x1,2,10,1,no,0,0,5,weapon,2,0x20000, KN_BRANDISHSPEAR,Brandish Spear 58,-4,6,1,-1,0x2,0,10,1,no,0,0x40000,0,weapon,6,0x0, KN_SPEARSTAB,Spear Stab 59,3:5:7:9:11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, KN_SPEARBOOMERANG,Spear Boomerang 60,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, KN_TWOHANDQUICKEN,Twohand Quicken @@ -550,7 +550,7 @@ // Sniper 380,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, SN_SIGHT,Falcon Eyes 381,5,8,1,-3,0x40,0,5,1,yes,0,0,0,misc,0,0x80, SN_FALCONASSAULT,Falcon Assault -382,9,8,1,-1,0,2,5,1,yes,0,0,13,weapon,0,0x0, SN_SHARPSHOOTING,Focused Arrow Strike +382,9,8,1,-1,0,1,5,1,yes,0,0,14,weapon,0,0x0, SN_SHARPSHOOTING,Focused Arrow Strike 383,0,6,4,0,0x3,-1,10,1,yes,0,0,0,weapon,0,0x0, SN_WINDWALK,Wind Walker //**** @@ -767,7 +767,7 @@ 539,0,6,4,1,0x2,3,5,1,yes,0,0,0,magic,0,0x0, NJ_HYOUSYOURAKU,Ice Meteor 540,9,8,1,4,0,0,10,1:2:2:3:3:4:4:5:5:6,yes,0,0,0,magic,0,0x0, NJ_HUUJIN,Wind Blade 541,9,6,2,4,0x2,2:2:3:3:4,5,1,yes,0,0,0,magic,0,0x0, NJ_RAIGEKISAI,Lightning Strike of Destruction -542,9,8,1,4,0,3,5,1,yes,0,0,5:6:7:8:9,magic,0,0x0, NJ_KAMAITACHI,Kamaitachi +542,5:6:7:8:9,8,1,4,0,1,5,1,yes,0,0,5:6:7:8:9,magic,0,0x0, NJ_KAMAITACHI,Kamaitachi 543,0,6,4,0,0x1,0,5,1,yes,0,0,0,none,0,0x0, NJ_NEN,Soul 544,-5,8,1,0,0x40,0,10,1,no,0,0,0,misc,0,0x0, NJ_ISSEN,Final Strike @@ -779,11 +779,11 @@ //**** // Additional NPC Skills (Episode 11.3) 653,0,8,4,0,0x6,5:7:9:11:13:5:7:9:11:13,10,1,no,0,0x2,0,magic,0,0x0, NPC_EARTHQUAKE,Earthquake -654,9,6,1,3,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_FIREBREATH,Fire Breath -655,9,6,1,1,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ICEBREATH,Ice Breath -656,9,6,1,4,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_THUNDERBREATH,Thunder Breath -657,9,6,1,5,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ACIDBREATH,Acid Breath -658,9,6,1,7,0,5,10,1,no,0,0x2,14,weapon,0,0x0, NPC_DARKNESSBREATH,Darkness Breath +654,6,6,1,3,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_FIREBREATH,Fire Breath +655,6,6,1,1,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ICEBREATH,Ice Breath +656,6,6,1,4,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_THUNDERBREATH,Thunder Breath +657,6,6,1,5,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_ACIDBREATH,Acid Breath +658,6,6,1,7,0,3,10,1,no,0,0x2,14,weapon,0,0x0, NPC_DARKNESSBREATH,Darkness Breath 659,0,6,4,0,0x3,2:5:8:11:14,5,1,no,0,0x2,0,none,0,0x0, NPC_DRAGONFEAR,Dragon Fear 660,-9,6,1,-1,0,0,5,1,no,0,0x2,0,weapon,0,0x0, NPC_BLEEDING,Bleeding 661,0,6,4,0,0x2,7,5,1,no,0,0x2,0,weapon,7,0x0, NPC_PULSESTRIKE,Pulse Strike @@ -1023,7 +1023,7 @@ 2256,11,6,1,-1,0,0,5,1,no,0,0,0,weapon,0,0x0, NC_BOOSTKNUCKLE,Boost Knuckle 2257,3,6,1,-1,0,0,3,1,no,0,0,0,weapon,0,0x0, NC_PILEBUNKER,Pile Bunker 2258,13,6,1,-1,0x2,1,3,1,no,0,0,0,weapon,0,0x0, NC_VULCANARM,Vulcan Arm -2259,7,6,1,3,0,2,3,1,no,0,0,5,weapon,0,0x0, NC_FLAMELAUNCHER,Flame Launcher +2259,5,6,1,3,0,1,3,1,no,0,0,5,weapon,0,0x0, NC_FLAMELAUNCHER,Flame Launcher 2260,7,6,2,1,0x2,2:3:4,3,1,no,0,0x40000,0,weapon,0,0x0, NC_COLDSLOWER,Cold Slower 2261,9:11:13,6,1,-1,0x42,3:2:1,3,1,no,0,0,0,weapon,0,0x0, NC_ARMSCANNON,Arm Cannon 2262,0,6,4,0,0x1,0,3,1,no,0,0,0,none,0,0x0, NC_ACCELERATION,Acceleration @@ -1075,7 +1075,7 @@ //**** // LG Royal Guard -2307,11,8,1,-1,0,2,5,1,no,0,0,10,weapon,0,0x0, LG_CANNONSPEAR,Cannon Spear +2307,11,8,1,-1,0,1,5,1,no,0,0,11,weapon,0,0x0, LG_CANNONSPEAR,Cannon Spear 2308,7,6,1,-1,0,0,10,1,no,0,0,0,weapon,0,0x0, LG_BANISHINGPOINT,Banishing Point 2309,0,6,4,0,0x3,2,3,1,no,0,0,0,none,0,0x0, LG_TRAMPLE,Trample 2310,1,6,1,0,0,0,5,1,no,0,0,0,weapon,0,0x20000, LG_SHIELDPRESS,Shield Press diff --git a/src/map/battle.c b/src/map/battle.c index e853ff8563..077e4534a8 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3410,17 +3410,17 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s int ratio = 100 + 20 * skill_lv; skillratio += -100 + ratio; - if(skill_lv > 3 && wd.miscflag == 1) + if(skill_lv > 3 && wd.miscflag == 0) skillratio += ratio / 2; - if(skill_lv > 6 && wd.miscflag == 1) + if(skill_lv > 6 && wd.miscflag == 0) skillratio += ratio / 4; - if(skill_lv > 9 && wd.miscflag == 1) + if(skill_lv > 9 && wd.miscflag == 0) skillratio += ratio / 8; - if(skill_lv > 6 && wd.miscflag == 2) + if(skill_lv > 6 && wd.miscflag == 1) skillratio += ratio / 2; - if(skill_lv > 9 && wd.miscflag == 2) + if(skill_lv > 9 && wd.miscflag == 1) skillratio += ratio / 4; - if(skill_lv > 9 && wd.miscflag == 3) + if(skill_lv > 9 && wd.miscflag == 2) skillratio += ratio / 2; break; } @@ -8197,6 +8197,7 @@ static const struct _battle_data { { "save_body_style", &battle_config.save_body_style, 0, 0, 1, }, { "monster_eye_range_bonus", &battle_config.mob_eye_range_bonus, 0, 0, 10, }, { "monster_stuck_warning", &battle_config.mob_stuck_warning, 0, 0, 1, }, + { "skill_eightpath_algorithm", &battle_config.skill_eightpath_algorithm, 1, 0, 1, }, }; #ifndef STATS_OPT_OUT diff --git a/src/map/battle.h b/src/map/battle.h index 97ee42a363..7b65020b26 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -600,6 +600,7 @@ extern struct Battle_Config int save_body_style; int mob_eye_range_bonus; //Vulture's Eye and Snake's Eye range bonus int mob_stuck_warning; //Show warning if a monster is stuck too long + int skill_eightpath_algorithm; //Official path algorithm } battle_config; void do_init_battle(void); diff --git a/src/map/map.c b/src/map/map.c index 223ca65649..c28cb1f027 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1210,6 +1210,167 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i } +/*========================================== [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 horizontal/vertical 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: Moves the whole path, half-length for diagonal paths +* @param type: Type of bl to search for +*------------------------------------------*/ +int map_foreachindir(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 bx, by; + int mx0, mx1, my0, my1, rx, ry; + int8 half = 0; + 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 (range < 0) + return 0; + if (length < 1) + return 0; + if (offset < 0) + return 0; + + //Special offset handling for diagonal paths + if (offset && (dir % 2)) { + //So that diagonal paths can attach to each other, we have to work with half-tile offsets + offset = (2 * offset) - 1; + //To get the half-tiles we need to increase length by one + length++; + } + + //Get area that needs to be checked + mx0 = x0 + dx*(offset / ((dir % 2) + 1)); + my0 = y0 + dy*(offset / ((dir % 2) + 1)); + mx1 = x0 + dx*(offset / ((dir % 2) + 1) + length - 1); + my1 = y0 + dy*(offset / ((dir % 2) + 1) + length - 1); + + //The following assumes mx0 < mx1 && my0 < my1 + if (mx0 > mx1) + swap(mx0, mx1); + if (my0 > my1) + swap(my0, my1); + + //Apply width to the path by turning 90 degrees + mx0 -= abs(range*dirx[(dir + 2) % 8]); + my0 -= abs(range*diry[(dir + 2) % 8]); + mx1 += abs(range*dirx[(dir + 2) % 8]); + my1 += abs(range*diry[(dir + 2) % 8]); + + mx0 = max(mx0, 0); + my0 = max(my0, 0); + mx1 = min(mx1, map[m].xs - 1); + my1 = min(my1, map[m].ys - 1); + + if (type&~BL_MOB) { + for (by = my0 / BLOCK_SIZE; by <= my1 / BLOCK_SIZE; by++) { + for (bx = mx0 / BLOCK_SIZE; bx <= mx1 / BLOCK_SIZE; bx++) { + 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) { + //Check if inside search area + if (bl->x < mx0 || bl->x > mx1 || bl->y < my0 || bl->y > my1) + continue; + //What matters now is the relative x and y from the start point + rx = (bl->x - x0); + ry = (bl->y - y0); + //Do not hit source cell + if (rx == 0 && ry == 0) + continue; + //This turns it so that the area that is hit is always with positive rx and ry + rx *= dx; + ry *= dy; + //These checks only need to be done for diagonal paths + if (dir % 2) { + //Check for length + if ((rx + ry < offset) || (rx + ry > 2 * (length + (offset/2) - 1))) + continue; + //Check for width + if (abs(rx - ry) > 2 * range) + continue; + } + //Everything else ok, check for line of sight from source + if (!path_search_long(NULL, m, x0, y0, bl->x, bl->y, CELL_CHKWALL)) + continue; + //All checks passed, add to list + bl_list[bl_list_count++] = bl; + } + } + } + } + } + if (type&BL_MOB) { + for (by = my0 / BLOCK_SIZE; by <= my1 / BLOCK_SIZE; by++) { + for (bx = mx0 / BLOCK_SIZE; bx <= mx1 / BLOCK_SIZE; bx++) { + 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) { + //Check if inside search area + if (bl->x < mx0 || bl->x > mx1 || bl->y < my0 || bl->y > my1) + continue; + //What matters now is the relative x and y from the start point + rx = (bl->x - x0); + ry = (bl->y - y0); + //Do not hit source cell + if (rx == 0 && ry == 0) + continue; + //This turns it so that the area that is hit is always with positive rx and ry + rx *= dx; + ry *= dy; + //These checks only need to be done for diagonal paths + if (dir % 2) { + //Check for length + if ((rx + ry < offset) || (rx + ry > 2 * (length + (offset / 2) - 1))) + continue; + //Check for width + if (abs(rx - ry) > 2 * range) + continue; + } + //Everything else ok, check for line of sight from source + if (!path_search_long(NULL, m, x0, y0, bl->x, bl->y, CELL_CHKWALL)) + continue; + //All checks passed, add to list + 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; +} + // Copy of map_foreachincell, but applied to the whole map. [Skotlex] int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type,...) { diff --git a/src/map/map.h b/src/map/map.h index 88ff96a9f6..5a43f222a3 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -828,6 +828,7 @@ int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...); int map_foreachincell(int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, ...); 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 type, ...); +int map_foreachindir(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 map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type, ...); //blocklist nb in one cell int map_count_oncell(int16 m,int16 x,int16 y,int type,int flag); diff --git a/src/map/skill.c b/src/map/skill.c index e78167c728..b654dd2f26 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -4445,27 +4445,42 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NC_FLAMELAUNCHER: if (sd) pc_overheat(sd,1); + case LG_CANNONSPEAR: + skill_area_temp[1] = bl->id; + if (battle_config.skill_eightpath_algorithm) { + //Use official AoE algorithm + map_foreachindir(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), 0, splash_target(src), + skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); + } else { + map_foreachinpath(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), splash_target(src), + skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); + } + break; + case SN_SHARPSHOOTING: case MA_SHARPSHOOTING: case NJ_KAMAITACHI: - case LG_CANNONSPEAR: - //It won't shoot through walls since on castend there has to be a direct - //line of sight between caster and target. - skill_area_temp[1] = bl->id; - map_foreachinpath (skill_attack_area,src->m,src->x,src->y,bl->x,bl->y, - skill_get_splash(skill_id, skill_lv),skill_get_maxcount(skill_id,skill_lv), splash_target(src), - skill_get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); - break; - case NPC_ACIDBREATH: case NPC_DARKNESSBREATH: case NPC_FIREBREATH: case NPC_ICEBREATH: case NPC_THUNDERBREATH: skill_area_temp[1] = bl->id; - map_foreachinpath(skill_attack_area,src->m,src->x,src->y,bl->x,bl->y, - skill_get_splash(skill_id, skill_lv),skill_get_maxcount(skill_id,skill_lv), splash_target(src), - skill_get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); + if (battle_config.skill_eightpath_algorithm) { + //Use official AoE algorithm + if (!(map_foreachindir(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), 0, splash_target(src), + skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY))) { + //These skills hit at least the target if the AoE doesn't hit + skill_attack(skill_get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + } + } else { + map_foreachinpath(skill_attack_area, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv), splash_target(src), + skill_get_type(skill_id), src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); + } break; case MO_INVESTIGATE: @@ -6742,7 +6757,29 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KN_BRANDISHSPEAR: case ML_BRANDISH: - skill_brandishspear(src, bl, skill_id, skill_lv, tick, flag); + { + skill_area_temp[1] = bl->id; + + if(skill_lv >= 10) + map_foreachindir(skill_area_sub, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), 1, skill_get_maxcount(skill_id, skill_lv)-1, splash_target(src), + src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 3, + skill_castend_damage_id); + if(skill_lv >= 7) + map_foreachindir(skill_area_sub, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), 1, skill_get_maxcount(skill_id, skill_lv)-2, splash_target(src), + src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 2, + skill_castend_damage_id); + if(skill_lv >= 4) + map_foreachindir(skill_area_sub, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), 1, skill_get_maxcount(skill_id, skill_lv)-3, splash_target(src), + src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, + skill_castend_damage_id); + map_foreachindir(skill_area_sub, src->m, src->x, src->y, bl->x, bl->y, + skill_get_splash(skill_id, skill_lv), skill_get_maxcount(skill_id, skill_lv)-3, 0, splash_target(src), + src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 0, + skill_castend_damage_id); + } break; case WZ_SIGHTRASHER: @@ -16199,182 +16236,6 @@ int skill_delayfix(struct block_list *bl, uint16 skill_id, uint16 skill_lv) return time; } -/*========================================= - * - *-----------------------------------------*/ -struct square { - int val1[5]; - int val2[5]; -}; - -static void skill_brandishspear_first (struct square *tc, uint8 dir, int16 x, int16 y) -{ - nullpo_retv(tc); - - if(dir == 0){ - tc->val1[0]=x-2; - tc->val1[1]=x-1; - tc->val1[2]=x; - tc->val1[3]=x+1; - tc->val1[4]=x+2; - tc->val2[0]= - tc->val2[1]= - tc->val2[2]= - tc->val2[3]= - tc->val2[4]=y-1; - } - else if(dir==2){ - tc->val1[0]= - tc->val1[1]= - tc->val1[2]= - tc->val1[3]= - tc->val1[4]=x+1; - tc->val2[0]=y+2; - tc->val2[1]=y+1; - tc->val2[2]=y; - tc->val2[3]=y-1; - tc->val2[4]=y-2; - } - else if(dir==4){ - tc->val1[0]=x-2; - tc->val1[1]=x-1; - tc->val1[2]=x; - tc->val1[3]=x+1; - tc->val1[4]=x+2; - tc->val2[0]= - tc->val2[1]= - tc->val2[2]= - tc->val2[3]= - tc->val2[4]=y+1; - } - else if(dir==6){ - tc->val1[0]= - tc->val1[1]= - tc->val1[2]= - tc->val1[3]= - tc->val1[4]=x-1; - tc->val2[0]=y+2; - tc->val2[1]=y+1; - tc->val2[2]=y; - tc->val2[3]=y-1; - tc->val2[4]=y-2; - } - else if(dir==1){ - tc->val1[0]=x-1; - tc->val1[1]=x; - tc->val1[2]=x+1; - tc->val1[3]=x+2; - tc->val1[4]=x+3; - tc->val2[0]=y-4; - tc->val2[1]=y-3; - tc->val2[2]=y-1; - tc->val2[3]=y; - tc->val2[4]=y+1; - } - else if(dir==3){ - tc->val1[0]=x+3; - tc->val1[1]=x+2; - tc->val1[2]=x+1; - tc->val1[3]=x; - tc->val1[4]=x-1; - tc->val2[0]=y-1; - tc->val2[1]=y; - tc->val2[2]=y+1; - tc->val2[3]=y+2; - tc->val2[4]=y+3; - } - else if(dir==5){ - tc->val1[0]=x+1; - tc->val1[1]=x; - tc->val1[2]=x-1; - tc->val1[3]=x-2; - tc->val1[4]=x-3; - tc->val2[0]=y+3; - tc->val2[1]=y+2; - tc->val2[2]=y+1; - tc->val2[3]=y; - tc->val2[4]=y-1; - } - else if(dir==7){ - tc->val1[0]=x-3; - tc->val1[1]=x-2; - tc->val1[2]=x-1; - tc->val1[3]=x; - tc->val1[4]=x+1; - tc->val2[1]=y; - tc->val2[0]=y+1; - tc->val2[2]=y-1; - tc->val2[3]=y-2; - tc->val2[4]=y-3; - } - -} - -static void skill_brandishspear_dir (struct square* tc, uint8 dir, int are) -{ - int c; - nullpo_retv(tc); - - for( c = 0; c < 5; c++ ) { - switch( dir ) { - case 0: tc->val2[c]+=are; break; - case 1: tc->val1[c]-=are; tc->val2[c]+=are; break; - case 2: tc->val1[c]-=are; break; - case 3: tc->val1[c]-=are; tc->val2[c]-=are; break; - case 4: tc->val2[c]-=are; break; - case 5: tc->val1[c]+=are; tc->val2[c]-=are; break; - case 6: tc->val1[c]+=are; break; - case 7: tc->val1[c]+=are; tc->val2[c]+=are; break; - } - } -} - -void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ - int c,n=4; - uint8 dir = map_calc_dir(src,bl->x,bl->y); - struct square tc; - int x=bl->x,y=bl->y; - skill_brandishspear_first(&tc,dir,x,y); - skill_brandishspear_dir(&tc,dir,4); - skill_area_temp[1] = bl->id; - - if(skill_lv > 9){ - for(c=1;c<4;c++){ - map_foreachincell(skill_area_sub, - bl->m,tc.val1[c],tc.val2[c],BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, - skill_castend_damage_id); - } - } - if(skill_lv > 6){ - skill_brandishspear_dir(&tc,dir,-1); - n--; - }else{ - skill_brandishspear_dir(&tc,dir,-2); - n-=2; - } - - if(skill_lv > 3){ - for(c=0;c<5;c++){ - map_foreachincell(skill_area_sub, - bl->m,tc.val1[c],tc.val2[c],BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, - skill_castend_damage_id); - if(skill_lv > 6 && n==3 && c==4){ - skill_brandishspear_dir(&tc,dir,-1); - n--;c=-1; - } - } - } - for(c=0;c<10;c++){ - if(c==0||c==5) skill_brandishspear_dir(&tc,dir,-1); - map_foreachincell(skill_area_sub, - bl->m,tc.val1[c%5],tc.val2[c%5],BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, - skill_castend_damage_id); - } -} /*========================================== * Weapon Repair [Celest/DracoRPG] diff --git a/src/map/skill.h b/src/map/skill.h index 8b9aa178ba..48f8bc7b26 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -471,7 +471,6 @@ struct skill_unit_group *skill_check_dancing( struct block_list *src ); int skill_castcancel(struct block_list *bl,int type); int skill_sit (struct map_session_data *sd, int type); -void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag); void skill_overbrand(struct block_list* src, uint16 skill_id, uint16 skill_lv, uint16 x, uint16 y, unsigned int tick, int flag); void skill_repairweapon(struct map_session_data *sd, int idx); void skill_identify(struct map_session_data *sd,int idx);