Line of Sight System updated (fixes #937, fixes #994)

* You can now target walls with ground skills
* Updated path check to not check the last cell
* Unit skills will now place units depending on line of sight to the caster rather than the cast center
* Implemented a new algorithm that retrieves all units in an area that are in line of sight with the area center
* Arrow Shower, Dragon Breath, Cold Slower, Wind Cutter and Arms Cannon now use the new algorithm (Arrow Shower is no longer a unit skill)
* Nodamage skills will no longer fail when the target walked around a corner
* The following damage skills will no longer damage through walls: Raging Thrust, Tornado Kick, Splash Attack, Venom Splasher, Fireball, Meteor Assault, Desperado, Spread Attack, Pulse Strike, Hell's Judgment, Vampire Gift, Magnum Break, Sightrasher, Frost Nova, Explosion, Self Destruction, Firing Trap, Icebound Trap, Cluster Bomb, Claymore, Fire Pillar
This commit is contained in:
Playtester 2016-03-05 18:02:22 +01:00
parent fb4cf3e5e3
commit 7906f0a3ff
9 changed files with 125 additions and 45 deletions

View File

@ -48,7 +48,7 @@
// 14 attack type (none, weapon, magic, misc) // 14 attack type (none, weapon, magic, misc)
// 15 Blowcount (amount of tiles skill knockbacks) // 15 Blowcount (amount of tiles skill knockbacks)
// 16 inf3 (skill information 3): // 16 inf3 (skill information 3):
// 0x00001 - skill ignores land protector (e.g. arrow shower) // 0x00001 - skill ignores land protector
// 0x00002 - skill that doesn't end camouflage // 0x00002 - skill that doesn't end camouflage
// 0x00004 - usable skills while hiding // 0x00004 - usable skills while hiding
// 0x00008 - skill that can be use while in dancing state // 0x00008 - skill that can be use while in dancing state

View File

@ -36,7 +36,6 @@
21,0x86, , 0, 2:2:2:2:2:2:2:2:2:2:3,1000,enemy, 0x010 //MG_THUNDERSTORM 21,0x86, , 0, 2:2:2:2:2:2:2:2:2:2:3,1000,enemy, 0x010 //MG_THUNDERSTORM
25,0x85, , 1, 0, -1,all, 0x6003 //AL_PNEUMA 25,0x85, , 1, 0, -1,all, 0x6003 //AL_PNEUMA
27,0x81,0x80, 0, 0, -1,all, 0x00E //AL_WARP 27,0x81,0x80, 0, 0, -1,all, 0x00E //AL_WARP
47,0x86, , 0, 2,1000,enemy, 0x080 //AC_SHOWER
70,0x83, , -1, 1,1000,all, 0x018 //PR_SANCTUARY 70,0x83, , -1, 1,1000,all, 0x018 //PR_SANCTUARY
79,0x84, , -1, 1,3000,enemy, 0x8018 //PR_MAGNUS 79,0x84, , -1, 1,3000,enemy, 0x8018 //PR_MAGNUS
80,0x87,0x88, 0, 1,2000,enemy, 0x4006 //WZ_FIREPILLAR 80,0x87,0x88, 0, 1,2000,enemy, 0x4006 //WZ_FIREPILLAR
@ -84,7 +83,7 @@
329,0xae, , 3, 0, -1,all, 0x140 //DC_FORTUNEKISS 329,0xae, , 3, 0, -1,all, 0x140 //DC_FORTUNEKISS
330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU 330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER 336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS 339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_GRANDDARKNESS
362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA 362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA
369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL 369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT 395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
@ -95,7 +94,7 @@
428,0x86, , 0, 1, 100,enemy, 0x000 //SG_SUN_WARM 428,0x86, , 0, 1, 100,enemy, 0x000 //SG_SUN_WARM
429,0x86, , 0, 1, 100,enemy, 0x000 //SG_MOON_WARM 429,0x86, , 0, 1, 100,enemy, 0x000 //SG_MOON_WARM
430,0x86, , 0, 1, 100,enemy, 0x000 //SG_STAR_WARM 430,0x86, , 0, 1, 100,enemy, 0x000 //SG_STAR_WARM
484,0xb8, , 2, 0,1000,enemy, 0x8808 //HW_GRAVITATION 484,0xb8, , 2, 0,1000,enemy, 0x8818 //HW_GRAVITATION
488,0xb9, , 3, 0, -1,all, 0x200 //CG_HERMODE 488,0xb9, , 3, 0, -1,all, 0x200 //CG_HERMODE
516,0x86, , 3, 0, 100,enemy, 0x000 //GS_DESPERADO 516,0x86, , 3, 0, 100,enemy, 0x000 //GS_DESPERADO
521,0xbe, , 0, 1,1000,enemy, 0x000 //GS_GROUNDDRIFT 521,0xbe, , 0, 1,1000,enemy, 0x000 //GS_GROUNDDRIFT
@ -182,7 +181,6 @@
8041,0xf6, , 1:1:2:2:3, 0,2000,enemy, 0x01A //MH_LAVA_SLIDE 8041,0xf6, , 1:1:2:2:3, 0,2000,enemy, 0x01A //MH_LAVA_SLIDE
8043,0xf7, , 1, 0,-1,all, 0x2018 //MH_VOLCANIC_ASH 8043,0xf7, , 1, 0,-1,all, 0x2018 //MH_VOLCANIC_ASH
8208,0x86, , 0, 2,1000,enemy, 0x080 //MA_SHOWER
8209,0x90, , 0, 1,1000,enemy, 0x006 //MA_SKIDTRAP 8209,0x90, , 0, 1,1000,enemy, 0x006 //MA_SKIDTRAP
8210,0x93, , 0, 0,1000,enemy, 0x006 //MA_LANDMINE 8210,0x93, , 0, 0,1000,enemy, 0x006 //MA_LANDMINE
8211,0x95, , 0, 1,1000,enemy, 0x006 //MA_SANDMAN 8211,0x95, , 0, 1,1000,enemy, 0x006 //MA_SANDMAN

View File

@ -48,7 +48,7 @@
// 14 attack type (none, weapon, magic, misc) // 14 attack type (none, weapon, magic, misc)
// 15 Blowcount (amount of tiles skill knockbacks) // 15 Blowcount (amount of tiles skill knockbacks)
// 16 inf3 (skill information 3): // 16 inf3 (skill information 3):
// 0x00001 - skill ignores land protector (e.g. arrow shower) // 0x00001 - skill ignores land protector
// 0x00002 - skill that doesn't end camouflage // 0x00002 - skill that doesn't end camouflage
// 0x00004 - usable skills while hiding // 0x00004 - usable skills while hiding
// 0x00008 - skill that can be use while in dancing state // 0x00008 - skill that can be use while in dancing state
@ -131,7 +131,7 @@
44,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0, AC_VULTURE,Vulture's Eye 44,0,0,0,0,0,0,10,0,no,0,0,0,none,0,0x0, AC_VULTURE,Vulture's Eye
45,0,6,4,0,0x3,3,10,1,no,0,0,0,weapon,0,0x0, AC_CONCENTRATION,Improve Concentration 45,0,6,4,0,0x3,3,10,1,no,0,0,0,weapon,0,0x0, AC_CONCENTRATION,Improve Concentration
46,-9,8,1,-1,0,0,10,2,no,0,0,0,weapon,0,0x80, AC_DOUBLE,Double Strafe 46,-9,8,1,-1,0,0,10,2,no,0,0,0,weapon,0,0x80, AC_DOUBLE,Double Strafe
47,-9,6,2,-1,0x2,2,10,1,no,0,0x40000,0,weapon,2,0x81, AC_SHOWER,Arrow Shower 47,-9,6,2,-1,0x2,1:1:1:1:1:2:2:2:2:2,10,1,no,0,0x40000,0,weapon,2,0x81, AC_SHOWER,Arrow Shower
//**** //****
// Thief // Thief
@ -1382,7 +1382,7 @@
8205,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, MS_REFLECTSHIELD,Shield_Reflect 8205,0,6,4,0,0x1,0,10,1,no,0,0,0,weapon,0,0x0, MS_REFLECTSHIELD,Shield_Reflect
8206,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, MS_BERSERK,Frenzy 8206,0,6,4,0,0x1,0,1,1,no,0,0,0,weapon,0,0x0, MS_BERSERK,Frenzy
8207,-9,8,1,-1,0,0,10,2,no,0,0,0,weapon,0,0x80, MA_DOUBLE,Double_Strafe 8207,-9,8,1,-1,0,0,10,2,no,0,0,0,weapon,0,0x80, MA_DOUBLE,Double_Strafe
8208,-9,6,2,-1,0x2,2,10,1,no,0,0x40000,0,weapon,2,0x81, MA_SHOWER,Arrow_Shower 8208,-9,6,2,-1,0x2,1:1:1:1:1:2:2:2:2:2,10,1,no,0,0x40000,0,weapon,2,0x81, MA_SHOWER,Arrow_Shower
8209,3,6,2,0,0x1,0,5,1,no,0,0x80,0,misc,6:7:8:9:10,0x3000, MA_SKIDTRAP,Skid_Trap 8209,3,6,2,0,0x1,0,5,1,no,0,0x80,0,misc,6:7:8:9:10,0x3000, MA_SKIDTRAP,Skid_Trap
8210,3,6,2,2,0xC0,0,5,1,no,0,0x80,0,misc,0,0x3800, MA_LANDMINE,Land_Mine 8210,3,6,2,2,0xC0,0,5,1,no,0,0x80,0,misc,0,0x3800, MA_LANDMINE,Land_Mine
8211,3,6,2,0,0x3,2,5,1,no,0,0x80,0,misc,0,0x3000, MA_SANDMAN,Sandman 8211,3,6,2,0,0x3,2,5,1,no,0,0x80,0,misc,0,0x3000, MA_SANDMAN,Sandman

View File

@ -36,7 +36,6 @@
21,0x86, , 0, 2:2:2:2:2:2:2:2:2:2:3,1000,enemy, 0x010 //MG_THUNDERSTORM 21,0x86, , 0, 2:2:2:2:2:2:2:2:2:2:3,1000,enemy, 0x010 //MG_THUNDERSTORM
25,0x85, , 1, 0, -1,all, 0x6003 //AL_PNEUMA 25,0x85, , 1, 0, -1,all, 0x6003 //AL_PNEUMA
27,0x81,0x80, 0, 0, -1,all, 0x00E //AL_WARP 27,0x81,0x80, 0, 0, -1,all, 0x00E //AL_WARP
47,0x86, , 0, 1:1:1:1:1:2:2:2:2:2,1000,enemy, 0x080 //AC_SHOWER
70,0x83, , -1, 1,1000,all, 0x018 //PR_SANCTUARY 70,0x83, , -1, 1,1000,all, 0x018 //PR_SANCTUARY
79,0x84, , -1, 1,3000,enemy, 0x8018 //PR_MAGNUS 79,0x84, , -1, 1,3000,enemy, 0x8018 //PR_MAGNUS
80,0x87,0x88, 0, 1,2000,enemy, 0x4006 //WZ_FIREPILLAR 80,0x87,0x88, 0, 1,2000,enemy, 0x4006 //WZ_FIREPILLAR
@ -84,7 +83,7 @@
329,0xae, , 3, 0, -1,all, 0x140 //DC_FORTUNEKISS 329,0xae, , 3, 0, -1,all, 0x140 //DC_FORTUNEKISS
330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU 330,0xaf, , 3, 0, -1,all, 0x140 //DC_SERVICEFORYOU
336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER 336,0xb2, , 0,-1, -1,noone, 0x000 //WE_CALLPARTNER
339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_DARKGRANDCROSS 339,0x86, , -1, 0, 300,enemy, 0x000 //NPC_GRANDDARKNESS
362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA 362,0xb4, , 2, 0, 300,all, 0x2000 //HP_BASILICA
369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL 369,0xb3, , -1, 0,10000,all, 0x008 //PA_GOSPEL
395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT 395,0xb5, , 4, 0, -1,all, 0x200 //CG_MOONLIT
@ -95,7 +94,7 @@
428,0x86, , 0, 1, 100,enemy, 0x000 //SG_SUN_WARM 428,0x86, , 0, 1, 100,enemy, 0x000 //SG_SUN_WARM
429,0x86, , 0, 1, 100,enemy, 0x000 //SG_MOON_WARM 429,0x86, , 0, 1, 100,enemy, 0x000 //SG_MOON_WARM
430,0x86, , 0, 1, 100,enemy, 0x000 //SG_STAR_WARM 430,0x86, , 0, 1, 100,enemy, 0x000 //SG_STAR_WARM
484,0xb8, , 2, 0, 500,enemy, 0x8808 //HW_GRAVITATION 484,0xb8, , 2, 0, 500,enemy, 0x8818 //HW_GRAVITATION
488,0xb9, , 3, 0, -1,all, 0x200 //CG_HERMODE 488,0xb9, , 3, 0, -1,all, 0x200 //CG_HERMODE
516,0x86, , 3, 0, 100,enemy, 0x000 //GS_DESPERADO 516,0x86, , 3, 0, 100,enemy, 0x000 //GS_DESPERADO
521,0xbe, , 0, 1,1000,enemy, 0x000 //GS_GROUNDDRIFT 521,0xbe, , 0, 1,1000,enemy, 0x000 //GS_GROUNDDRIFT
@ -183,7 +182,6 @@
8041,0xf6, , 1:1:2:2:3, 0,2000,enemy, 0x01A //MH_LAVA_SLIDE 8041,0xf6, , 1:1:2:2:3, 0,2000,enemy, 0x01A //MH_LAVA_SLIDE
8043,0xf7, , 1, 0,-1,all, 0x2018 //MH_VOLCANIC_ASH 8043,0xf7, , 1, 0,-1,all, 0x2018 //MH_VOLCANIC_ASH
8208,0x86, , 0, 2,1000,enemy, 0x080 //MA_SHOWER
8209,0x90, , 0, 1,1000,enemy, 0x8006 //MA_SKIDTRAP 8209,0x90, , 0, 1,1000,enemy, 0x8006 //MA_SKIDTRAP
8210,0x93, , 0, 0,1000,enemy, 0x8006 //MA_LANDMINE 8210,0x93, , 0, 0,1000,enemy, 0x8006 //MA_LANDMINE
8211,0x95, , 0, 1,1000,enemy, 0x8006 //MA_SANDMAN 8211,0x95, , 0, 1,1000,enemy, 0x8006 //MA_SANDMAN

View File

@ -742,6 +742,76 @@ int map_foreachinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0
bl_list_count = blockcount; bl_list_count = blockcount;
return returnCount; //[Skotlex] return returnCount; //[Skotlex]
} }
/*========================================== [Playtester]
* Same as foreachinarea, but there must be a shoot-able range between area center and target.
* @param m: ID of map
* @param x0: West end of area
* @param y0: South end of area
* @param x1: East end of area
* @param y1: North end of area
* @param type: Type of bl to search for
*------------------------------------------*/
int map_foreachinshootarea(int(*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...)
{
int bx, by, cx, cy;
int returnCount = 0; //total sum of returned values of func()
struct block_list *bl;
int blockcount = bl_list_count, i;
va_list ap;
if (m < 0 || m >= map_num)
return 0;
if (x1 < x0)
swap(x0, x1);
if (y1 < y0)
swap(y0, y1);
x0 = i16max(x0, 0);
y0 = i16max(y0, 0);
x1 = i16min(x1, map[m].xs - 1);
y1 = i16min(y1, map[m].ys - 1);
cx = x0 + (x1 - x0) / 2;
cy = y0 + (y1 - y0) / 2;
if (type&~BL_MOB)
for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
for (bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
for (bl = map[m].block[bx + by * map[m].bxs]; bl != NULL; bl = bl->next)
if (bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1
&& path_search_long(NULL, m, cx, cy, bl->x, bl->y, CELL_CHKWALL)
&& bl_list_count < BL_LIST_MAX)
bl_list[bl_list_count++] = bl;
if (type&BL_MOB)
for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
for (bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
for (bl = map[m].block_mob[bx + by * map[m].bxs]; bl != NULL; bl = bl->next)
if (bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1
&& path_search_long(NULL, m, cx, cy, bl->x, bl->y, CELL_CHKWALL)
&& bl_list_count < BL_LIST_MAX)
bl_list[bl_list_count++] = bl;
if (bl_list_count >= BL_LIST_MAX)
ShowWarning("map_foreachinarea: 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;
}
/*========================================== /*==========================================
* Adapted from forcountinarea for an easier invocation. [pakpil] * Adapted from forcountinarea for an easier invocation. [pakpil]
*------------------------------------------*/ *------------------------------------------*/

View File

@ -822,7 +822,8 @@ int map_delblock(struct block_list* bl);
int map_moveblock(struct block_list *, int, int, unsigned int); int map_moveblock(struct block_list *, int, int, unsigned int);
int map_foreachinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); int map_foreachinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...);
int map_foreachinshootrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); int map_foreachinshootrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...);
int map_foreachinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...); int map_foreachinarea(int(*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...);
int map_foreachinshootarea(int(*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...);
int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, ...); int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, ...);
int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...); int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...);
int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...); int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...);

View File

@ -172,7 +172,7 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16
spd->y[spd->len] = y0; spd->y[spd->len] = y0;
spd->len++; spd->len++;
} }
if (map_getcellp(md,x0,y0,cell)) if ((x0 != x1 || y0 != y1) && map_getcellp(md,x0,y0,cell))
return false; return false;
} }

View File

@ -2887,16 +2887,16 @@ void skill_attack_blow(struct block_list *src, struct block_list *dsrc, struct b
if(!battle_config.stormgust_knockback) if(!battle_config.stormgust_knockback)
dir = rnd()%8; dir = rnd()%8;
break; break;
case WL_CRIMSONROCK:
dir = map_calc_dir(target,skill_area_temp[4],skill_area_temp[5]);
break;
case MC_CARTREVOLUTION: case MC_CARTREVOLUTION:
if (battle_config.cart_revo_knockback) if (battle_config.cart_revo_knockback)
dir = 6; // Official servers push target to the West dir = 6; // Official servers push target to the West
break; break;
case AC_SHOWER: case AC_SHOWER:
if (!battle_config.arrow_shower_knockback) case WL_CRIMSONROCK:
if (!battle_config.arrow_shower_knockback && skill_id == AC_SHOWER)
dir = map_calc_dir(target, src->x, src->y); dir = map_calc_dir(target, src->x, src->y);
else
dir = map_calc_dir(target, skill_area_temp[4], skill_area_temp[5]);
break; break;
} }
@ -4427,7 +4427,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case MO_COMBOFINISH: case MO_COMBOFINISH:
if (!(flag&1) && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_MONK) if (!(flag&1) && sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_MONK)
{ //Becomes a splash attack when Soul Linked. { //Becomes a splash attack when Soul Linked.
map_foreachinrange(skill_area_sub, bl, map_foreachinshootrange(skill_area_sub, bl,
skill_get_splash(skill_id, skill_lv),splash_target(src), skill_get_splash(skill_id, skill_lv),splash_target(src),
src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1,
skill_castend_damage_id); skill_castend_damage_id);
@ -4438,7 +4438,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
case TK_STORMKICK: // Taekwon kicks [Dralnu] case TK_STORMKICK: // Taekwon kicks [Dralnu]
clif_skill_nodamage(src,bl,skill_id,skill_lv,1); clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
skill_area_temp[1] = 0; skill_area_temp[1] = 0;
map_foreachinrange(skill_attack_area, src, map_foreachinshootrange(skill_attack_area, src,
skill_get_splash(skill_id, skill_lv), splash_target(src), skill_get_splash(skill_id, skill_lv), splash_target(src),
BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
break; break;
@ -4708,7 +4708,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint
skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, (skill_id == AS_SPLASHER)?1:skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count); skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, (skill_id == AS_SPLASHER)?1:skill_get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, BCT_ENEMY, skill_area_sub_count);
// recursive invocation of skill_castend_damage_id() with flag|1 // recursive invocation of skill_castend_damage_id() with flag|1
if (battle_config.skill_wall_check && skill_id == RA_ARROWSTORM) if (battle_config.skill_wall_check && skill_id != NPC_EARTHQUAKE)
map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); map_foreachinshootrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
else else
map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); map_foreachinrange(skill_area_sub, bl, skill_get_splash(skill_id, skill_lv), starget, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
@ -6293,7 +6293,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SM_MAGNUM: case SM_MAGNUM:
case MS_MAGNUM: case MS_MAGNUM:
skill_area_temp[1] = 0; skill_area_temp[1] = 0;
map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR, map_foreachinshootrange(skill_area_sub, src, skill_get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR,
src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill_castend_damage_id); src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill_castend_damage_id);
clif_skill_nodamage (src,src,skill_id,skill_lv,1); clif_skill_nodamage (src,src,skill_id,skill_lv,1);
// Initiate 20% of your damage becomes fire element. // Initiate 20% of your damage becomes fire element.
@ -6804,7 +6804,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
//Passive side of the attack. //Passive side of the attack.
status_change_end(src, SC_SIGHT, INVALID_TIMER); status_change_end(src, SC_SIGHT, INVALID_TIMER);
clif_skill_nodamage(src,bl,skill_id,skill_lv,1); clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
map_foreachinrange(skill_area_sub,src, map_foreachinshootrange(skill_area_sub,src,
skill_get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL, skill_get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL,
src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_ANIMATION|1, src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_ANIMATION|1,
skill_castend_damage_id); skill_castend_damage_id);
@ -6813,7 +6813,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case WZ_FROSTNOVA: case WZ_FROSTNOVA:
clif_skill_nodamage(src,bl,skill_id,skill_lv,1); clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
skill_area_temp[1] = 0; skill_area_temp[1] = 0;
map_foreachinrange(skill_attack_area, src, map_foreachinshootrange(skill_attack_area, src,
skill_get_splash(skill_id, skill_lv), splash_target(src), skill_get_splash(skill_id, skill_lv), splash_target(src),
BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY);
break; break;
@ -6826,7 +6826,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
BCT_ENEMY:BCT_ALL; BCT_ENEMY:BCT_ALL;
clif_skill_nodamage(src, src, skill_id, -1, 1); clif_skill_nodamage(src, src, skill_id, -1, 1);
map_delblock(src); //Required to prevent chain-self-destructions hitting back. map_delblock(src); //Required to prevent chain-self-destructions hitting back.
map_foreachinrange(skill_area_sub, bl, map_foreachinshootrange(skill_area_sub, bl,
skill_get_splash(skill_id, skill_lv), splash_target(src), skill_get_splash(skill_id, skill_lv), splash_target(src),
src, skill_id, skill_lv, tick, flag|i, src, skill_id, skill_lv, tick, flag|i,
skill_castend_damage_id); skill_castend_damage_id);
@ -10984,7 +10984,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
break; break;
} }
#ifdef OFFICIAL_WALKPATH #ifdef OFFICIAL_WALKPATH
if( !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) ) if(skill_get_casttype(ud->skill_id) != CAST_NODAMAGE && !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL))
{ {
if (sd) { if (sd) {
clif_skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); clif_skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0);
@ -11358,7 +11358,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case BS_HAMMERFALL: case BS_HAMMERFALL:
i = skill_get_splash(skill_id, skill_lv); i = skill_get_splash(skill_id, skill_lv);
map_foreachinarea (skill_area_sub, map_foreachinarea(skill_area_sub,
src->m, x-i, y-i, x+i, y+i, BL_CHAR, src->m, x-i, y-i, x+i, y+i, BL_CHAR,
src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2,
skill_castend_nodamage_id); skill_castend_nodamage_id);
@ -11434,8 +11434,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case WE_CALLPARTNER: case WE_CALLPARTNER:
case WE_CALLPARENT: case WE_CALLPARENT:
case WE_CALLBABY: case WE_CALLBABY:
case AC_SHOWER: //Ground-placed skill implementation.
case MA_SHOWER:
case SA_LANDPROTECTOR: case SA_LANDPROTECTOR:
case BD_LULLABY: case BD_LULLABY:
case BD_RICHMANKIM: case BD_RICHMANKIM:
@ -11768,13 +11766,18 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
case RK_WINDCUTTER: case RK_WINDCUTTER:
clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
case AC_SHOWER:
case MA_SHOWER:
case NC_COLDSLOWER: case NC_COLDSLOWER:
case NC_ARMSCANNON: case NC_ARMSCANNON:
case RK_DRAGONBREATH: case RK_DRAGONBREATH:
case RK_DRAGONBREATH_WATER: case RK_DRAGONBREATH_WATER:
// Cast center might be relevant later (e.g. for knockback direction)
skill_area_temp[4] = x;
skill_area_temp[5] = y;
i = skill_get_splash(skill_id,skill_lv); i = skill_get_splash(skill_id,skill_lv);
if (battle_config.skill_wall_check) if (battle_config.skill_wall_check)
map_foreachinshootrange(skill_area_sub,src,skill_get_splash(skill_id, skill_lv),splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); map_foreachinshootarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
else else
map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id); map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
break; break;
@ -12744,8 +12747,8 @@ struct skill_unit_group *skill_unitsetting(struct block_list *src, uint16 skill_
if( !group->state.song_dance && !map_getcell(src->m,ux,uy,CELL_CHKREACH) ) if( !group->state.song_dance && !map_getcell(src->m,ux,uy,CELL_CHKREACH) )
continue; // don't place skill units on walls (except for songs/dances/encores) continue; // don't place skill units on walls (except for songs/dances/encores)
if( battle_config.skill_wall_check && unit_flag&UF_PATHCHECK && !path_search_long(NULL,src->m,ux,uy,x,y,CELL_CHKWALL) ) if( battle_config.skill_wall_check && unit_flag&UF_PATHCHECK && !path_search_long(NULL,src->m,ux,uy,src->x,src->y,CELL_CHKWALL) )
continue; // no path between cell and center of casting. continue; // no path between cell and caster
switch( skill_id ) { switch( skill_id ) {
// HP for Skill unit that can be damaged, see also skill_unit_ondamaged // HP for Skill unit that can be damaged, see also skill_unit_ondamaged
@ -13445,18 +13448,23 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, uns
case UNT_FREEZINGTRAP: case UNT_FREEZINGTRAP:
case UNT_FIREPILLAR_ACTIVE: case UNT_FIREPILLAR_ACTIVE:
case UNT_CLAYMORETRAP: case UNT_CLAYMORETRAP:
{
int bl_flag = sg->bl_flag;
if (tsc && tsc->data[SC__MANHOLE]) if (tsc && tsc->data[SC__MANHOLE])
break; break;
if (sg->unit_id == UNT_FIRINGTRAP || sg->unit_id == UNT_ICEBOUNDTRAP || sg->unit_id == UNT_CLAYMORETRAP) if (sg->unit_id == UNT_FIRINGTRAP || sg->unit_id == UNT_ICEBOUNDTRAP || sg->unit_id == UNT_CLAYMORETRAP)
map_foreachinrange(skill_trap_splash, &unit->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &unit->bl, tick); bl_flag = bl_flag|BL_SKILL|~BCT_SELF;
if(battle_config.skill_wall_check && !(skill_get_nk(skill_id)&NK_NO_DAMAGE))
map_foreachinshootrange(skill_trap_splash, &unit->bl, skill_get_splash(sg->skill_id, sg->skill_lv), bl_flag, &unit->bl, tick);
else else
map_foreachinrange(skill_trap_splash, &unit->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &unit->bl, tick); map_foreachinrange(skill_trap_splash, &unit->bl, skill_get_splash(sg->skill_id, sg->skill_lv), bl_flag, &unit->bl, tick);
if (sg->unit_id != UNT_FIREPILLAR_ACTIVE) if (sg->unit_id != UNT_FIREPILLAR_ACTIVE)
clif_changetraplook(&unit->bl,(sg->unit_id == UNT_LANDMINE ? UNT_FIREPILLAR_ACTIVE : UNT_USED_TRAPS)); clif_changetraplook(&unit->bl,(sg->unit_id == UNT_LANDMINE ? UNT_FIREPILLAR_ACTIVE : UNT_USED_TRAPS));
sg->limit = DIFF_TICK(tick, sg->tick) + sg->limit = DIFF_TICK(tick, sg->tick) +
(sg->unit_id == UNT_CLUSTERBOMB || sg->unit_id == UNT_ICEBOUNDTRAP ? 1000 : 0) + // Cluster Bomb/Icebound has 1s to disappear once activated. (sg->unit_id == UNT_CLUSTERBOMB || sg->unit_id == UNT_ICEBOUNDTRAP ? 1000 : 0) + // Cluster Bomb/Icebound has 1s to disappear once activated.
(sg->unit_id == UNT_FIRINGTRAP ? 0 : 1500); // Firing Trap gets removed immediately once activated. (sg->unit_id == UNT_FIRINGTRAP ? 0 : 1500); // Firing Trap gets removed immediately once activated.
sg->unit_id = UNT_USED_TRAPS; // Change ID so it does not invoke a for each in area again. sg->unit_id = UNT_USED_TRAPS; // Change ID so it does not invoke a for each in area again.
}
break; break;
case UNT_TALKIEBOX: case UNT_TALKIEBOX:
@ -16796,9 +16804,15 @@ int skill_detonator(struct block_list *bl, va_list ap)
case UNT_CLAYMORETRAP: case UNT_CLAYMORETRAP:
case UNT_FIRINGTRAP: case UNT_FIRINGTRAP:
case UNT_ICEBOUNDTRAP: case UNT_ICEBOUNDTRAP:
if (battle_config.skill_wall_check)
map_foreachinshootrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag|BL_SKILL|~BCT_SELF,bl,unit->group->tick);
else
map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag|BL_SKILL|~BCT_SELF,bl,unit->group->tick); map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag|BL_SKILL|~BCT_SELF,bl,unit->group->tick);
break; break;
default: default:
if(battle_config.skill_wall_check && !(skill_get_nk(unit->group->skill_id)&NK_NO_DAMAGE))
map_foreachinshootrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);
else
map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick); map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);
break; break;
} }
@ -19337,6 +19351,9 @@ static int skill_destroy_trap(struct block_list *bl, va_list ap)
case UNT_CLAYMORETRAP: case UNT_CLAYMORETRAP:
case UNT_FIRINGTRAP: case UNT_FIRINGTRAP:
case UNT_ICEBOUNDTRAP: case UNT_ICEBOUNDTRAP:
if(battle_config.skill_wall_check)
map_foreachinshootrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &su->bl,tick);
else
map_foreachinrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &su->bl,tick); map_foreachinrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &su->bl,tick);
break; break;
case UNT_LANDMINE: case UNT_LANDMINE:
@ -19346,6 +19363,9 @@ static int skill_destroy_trap(struct block_list *bl, va_list ap)
case UNT_FLASHER: case UNT_FLASHER:
case UNT_FREEZINGTRAP: case UNT_FREEZINGTRAP:
case UNT_CLUSTERBOMB: case UNT_CLUSTERBOMB:
if (battle_config.skill_wall_check && !(skill_get_nk(sg->skill_id)&NK_NO_DAMAGE))
map_foreachinshootrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &su->bl,tick);
else
map_foreachinrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &su->bl,tick); map_foreachinrange(skill_trap_splash,&su->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &su->bl,tick);
break; break;
} }

View File

@ -1986,13 +1986,6 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
return 0; return 0;
} }
if( map_getcell(src->m, skill_x, skill_y, CELL_CHKWALL) ) { // Can't cast ground targeted spells on wall cells
if (sd)
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
return 0;
}
// Check range and obstacle // Check range and obstacle
bl.type = BL_NUL; bl.type = BL_NUL;
bl.m = src->m; bl.m = src->m;