Official line of damage path algorithm (fixes #658)

* Implemented the official line of damage algorithm that official servers use; it will calculate the direction between caster and target and apply one of eight possible AoEs
* Added a config setting with which you can switch back to the custom emulator path algorithm
* Updated Brandish Spear(5x5), Focused Arrow Strike(13x3), First Wind(5-9x3), NPC Breath attacks(14x7), Flame Launcher(5x3) and Cannon Spear(11x3) to use this algorithm and corrected range, splash and maxcount values for all these skills
* Fixed Brandish Spear's AoE being completely wrong and having holes in its AoE when attacking diagonally; also fixed the knock back being 3 instead of 2 and not working at all for the longest reach; Brandish Spear's AoE width and length can now be defined in skill_db.txt
* Focused Arrow Strike, First Wind and NPC breath attacks will at least hit one target, if no enemy is on the AoE, the target will be hit instead; Brandish Spear, Flame Launcher and Cannon Spear can completely miss
This commit is contained in:
Playtester 2016-02-02 23:41:05 +01:00
parent 79229c83c5
commit 6ad062f6e3
9 changed files with 249 additions and 216 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,...)
{

View File

@ -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);

View File

@ -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]

View File

@ -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);