diff --git a/db/pre-re/skill_cast_db.txt b/db/pre-re/skill_cast_db.txt index 80d4fd071c..20d9994c7f 100644 --- a/db/pre-re/skill_cast_db.txt +++ b/db/pre-re/skill_cast_db.txt @@ -157,7 +157,7 @@ //-- WZ_FIREPILLAR 80,3000:2700:2400:2100:1800:1500:1200:900:600:300,1000,0,30000,600:800:1000:1200:1400:1600:1800:2000:2200:2400,0 //-- WZ_SIGHTRASHER -81,700,2000,0,500,0,0 +81,500,2000,0,500,0,0 //-- WZ_METEOR 83,15000,2000:3000:3000:4000:4000:5000:5000:6000:6000:7000,0,500,5000,0 //-- WZ_JUPITEL diff --git a/db/pre-re/skill_db.txt b/db/pre-re/skill_db.txt index 4bdcc6e23e..cb7ee7b83c 100644 --- a/db/pre-re/skill_db.txt +++ b/db/pre-re/skill_db.txt @@ -864,7 +864,7 @@ 1003,0,0,0,0,0,0,1,0,no,0,0x1,0,weapon,0,0x0, AS_SONICACCEL,Sonic Acceleration 1004,9,8,1,0,0x8,0,1,1,no,0,0x1,0,weapon,0,0x0, AS_VENOMKNIFE,Throw Venom Knife 1005,1,6,1,0,0x1,0,1,1,no,0,0x1,0,weapon,0,0x0, RG_CLOSECONFINE,Close Confine -1006,0,6,4,3,0,2,1,1,yes,0,0x1,0,magic,3,0x20, WZ_SIGHTBLASTER,Sight Blaster +1006,0,6,4,3,0,1,1,1,yes,0,0x1,0,magic,3,0x20, WZ_SIGHTBLASTER,Sight Blaster 1007,0,6,4,0,0x1,0,1,0,no,0,0x1,0,none,0,0x0, SA_CREATECON,Create Elemental Converter 1008,9,6,1,1,0x1,0,1,1,yes,0,0x1,0,magic,0,0x0, SA_ELEMENTWATER,Elemental Change Water 1009,-9,6,1,0,0,0,1,1,no,0,0x1,0,weapon,3,0x0, HT_PHANTASMIC,Phantasmic Arrow diff --git a/src/map/battle.c b/src/map/battle.c index 58d97dfa55..3e689b65b1 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7147,7 +7147,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f { TBL_SKILL *su = (TBL_SKILL*)target; - if( su && su->group && skill_get_inf2(su->group->skill_id)&INF2_TRAP ) { //Only a few skills can target traps... + if( su && su->group && skill_get_inf2(su->group->skill_id)&INF2_TRAP && su->group->unit_id != UNT_USED_TRAPS) { //Only a few skills can target traps... switch( battle_getcurrentskill(src) ) { case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps case RK_DRAGONBREATH_WATER: @@ -7251,10 +7251,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f break; case BL_SKILL: { struct skill_unit *su = (struct skill_unit *)src; - + struct status_change* sc = status_get_sc(target); if (!su || !su->group) return 0; - if (su->group->src_id == target->id) { int inf2 = skill_get_inf2(su->group->skill_id); if (inf2&INF2_NO_TARGET_SELF) @@ -7262,6 +7261,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if (inf2&INF2_TARGET_SELF) return 1; } + //Status changes that prevent traps from triggering + if (sc && sc->count && skill_get_inf2(su->group->skill_id)&INF2_TRAP) { + if( sc->data[SC_SIGHTBLASTER] && sc->data[SC_SIGHTBLASTER]->val2 > 0 && sc->data[SC_SIGHTBLASTER]->val4%2 == 0) + return -1; + } } break; case BL_MER: diff --git a/src/map/clif.c b/src/map/clif.c index e9bf626770..447602a669 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4708,9 +4708,10 @@ int clif_outsight(struct block_list *bl,va_list ap) tsd = BL_CAST(BL_PC, tbl); if (tsd && tsd->fd) { //tsd has lost sight of the bl object. + nullpo_ret(bl); switch(bl->type){ case BL_PC: - if (sd->vd.class_ != INVISIBLE_CLASS) + if(sd->vd.class_ != INVISIBLE_CLASS) clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); if(sd->chatID){ struct chat_data *cd; @@ -4718,9 +4719,9 @@ int clif_outsight(struct block_list *bl,va_list ap) if(cd->usersd[0]==sd) clif_dispchat(cd,tsd->fd); } - if( sd->state.vending ) + if(sd->state.vending) clif_closevendingboard(bl,tsd->fd); - if( sd->state.buyingstore ) + if(sd->state.buyingstore) clif_buyingstore_disappear_entry_single(tsd, sd); break; case BL_ITEM: @@ -4730,17 +4731,20 @@ int clif_outsight(struct block_list *bl,va_list ap) clif_clearchar_skillunit((struct skill_unit *)bl,tsd->fd); break; case BL_NPC: - if( !(((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE) ) + if(!(((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE)) clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); break; default: - if ((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS) + if((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS) clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); break; } } if (sd && sd->fd) { //sd is watching tbl go out of view. - if (((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && + nullpo_ret(tbl); + if(tbl->type == BL_SKILL) //Trap knocked out of sight + clif_clearchar_skillunit((struct skill_unit *)tbl,sd->fd); + else if(((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && !(tbl->type == BL_NPC && (((TBL_NPC*)tbl)->sc.option&OPTION_INVISIBLE))) clif_clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd); } diff --git a/src/map/mob.c b/src/map/mob.c index 7e889582c4..c99e499bb9 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1625,8 +1625,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) //Attempt to attack. //At this point we know the target is attackable, we just gotta check if the range matches. - if (battle_check_range (&md->bl, tbl, md->status.rhw.range)) - { //Target within range, engage + if (battle_check_range(&md->bl, tbl, md->status.rhw.range) && !(md->sc.option&OPTION_HIDE)) + { //Target within range and able to use normal attack, engage if (md->ud.target != tbl->id || md->ud.attacktimer == INVALID_TIMER) { //Only attack if no more attack delay left if(tbl->type == BL_PC) @@ -1646,6 +1646,19 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return true; } + //Monsters in berserk state, unable to use normal attacks, will always attempt a skill + if(md->ud.walktimer == INVALID_TIMER && (md->state.skillstate == MSS_BERSERK || md->state.skillstate == MSS_ANGRY)) + { + if (DIFF_TICK(md->ud.canmove_tick, tick) <= MIN_MOBTHINKTIME && DIFF_TICK(md->ud.canact_tick, tick) < -MIN_MOBTHINKTIME*IDLE_SKILL_INTERVAL) + { //Only use skill if able to walk on next tick and not used a skill the last second + mobskill_use(md, tick, -1); + } + } + + //Target still in attack range, no need to chase the target + if(battle_check_range(&md->bl, tbl, md->status.rhw.range)) + return true; + //Out of range... if (!(mode&MD_CANMOVE) || (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0)) { //Can't chase. Immobile and trapped mobs should unlock target and use an idle skill. @@ -1657,15 +1670,6 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return true; } - //Before a monster starts to chase a target, it will check if it has a ranged "attack" skill to use on it. - if(md->ud.walktimer == INVALID_TIMER && (md->state.skillstate == MSS_BERSERK || md->state.skillstate == MSS_ANGRY)) - { - if (DIFF_TICK(md->ud.canmove_tick, tick) <= MIN_MOBTHINKTIME && DIFF_TICK(md->ud.canact_tick, tick) < -MIN_MOBTHINKTIME*IDLE_SKILL_INTERVAL) - { //Only use skill if able to walk on next tick and not used a skill the last second - mobskill_use(md, tick, -1); - } - } - if (md->ud.walktimer != INVALID_TIMER && md->ud.target == tbl->id && ( !(battle_config.mob_ai&0x1) || diff --git a/src/map/skill.c b/src/map/skill.c index 09e63442b4..8abd4bbe51 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2831,6 +2831,8 @@ void skill_attack_blow(struct block_list *src, struct block_list *dsrc, struct b * flag&0xFFF is passed to the underlying battle_calc_attack for processing * (usually holds number of targets, or just 1 for simple splash attacks) * + * flag&0x1000 - Return 0 if damage was reflected + * * Values from enum e_skill_display * Values from enum e_battle_check_target *-------------------------------------------------------------------------*/ @@ -2909,7 +2911,8 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * tsc = NULL; //Don't need it. /* bugreport:2564 flag&2 disables double casting trigger */ flag |= 2; - + //Reflected magic damage will not cause the caster to be knocked back [Playtester] + flag |= 4; //Spirit of Wizard blocks Kaite's reflection if( type == 2 && tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_WIZARD ) { //Consume one Fragment per hit of the casted skill? [Skotlex] @@ -3285,6 +3288,9 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list * map_freeblock_unlock(); + if ((flag&0x1000) && rmdamage == 1) + return 0; //Should return 0 when damage was reflected + return damage; } diff --git a/src/map/status.c b/src/map/status.c index cc5fbb6acf..b24582b179 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -6750,7 +6750,9 @@ int status_get_guild_id(struct block_list *bl) return ((TBL_NPC*)bl)->u.scr.guild_id; break; case BL_SKILL: - return ((TBL_SKILL*)bl)->group->guild_id; + if (((TBL_SKILL*)bl)->group) + return ((TBL_SKILL*)bl)->group->guild_id; + break; case BL_ELEM: if (((TBL_ELEM*)bl)->master) return ((TBL_ELEM*)bl)->master->status.guild_id; @@ -8701,8 +8703,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_RUWACH: case SC_SIGHTBLASTER: val3 = skill_get_splash(val2, val1); // Val2 should bring the skill-id. - val2 = tick/250; - tick_time = 10; // [GodLesZ] tick time + val2 = tick/20; + tick_time = 20; // [GodLesZ] tick time break; case SC_AUTOGUARD: @@ -11370,14 +11372,17 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) case SC_SIGHT: case SC_RUWACH: case SC_SIGHTBLASTER: - if(type == SC_SIGHTBLASTER) + if(type == SC_SIGHTBLASTER) { + //Restore trap immunity + if(sce->val4%2) + sce->val4--; map_foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); - else + } else map_foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); if( --(sce->val2)>0 ) { - sce->val4 += 250; // Use for Shadow Form 2 seconds checking. - sc_timer_next(250+tick, status_change_timer, bl->id, data); + sce->val4 += 20; // Use for Shadow Form 2 seconds checking. + sc_timer_next(20+tick, status_change_timer, bl->id, data); return 0; } break; @@ -12203,9 +12208,13 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) if (battle_check_target( src, bl, BCT_ENEMY ) > 0 && status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2)) { - if (sce && !(bl->type&BL_SKILL) // The hit is not counted if it's against a trap - && skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0)) { + struct skill_unit *su = (struct skill_unit *)bl; + if (sce && skill_attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0x1000) + && (!su || !su->group || !(skill_get_inf2(su->group->skill_id)&INF2_TRAP))) { // The hit is not counted if it's against a trap sce->val2 = 0; // This signals it to end. + } else if((bl->type&BL_SKILL) && sce->val4%2 == 0) { + //Remove trap immunity temporarily so it triggers if you still stand on it + sce->val4++; } } break; diff --git a/src/map/unit.c b/src/map/unit.c index 35a5e79ac2..bc9c558c57 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1009,6 +1009,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) unit_stop_walking(bl, 0); if( sd ) { + unit_stop_stepaction(bl); //Stop stepaction when knocked back sd->ud.to_x = nx; sd->ud.to_y = ny; }