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:
parent
79229c83c5
commit
6ad062f6e3
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
161
src/map/map.c
161
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,...)
|
||||
{
|
||||
|
@ -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);
|
||||
|
239
src/map/skill.c
239
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]
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user