diff options
author | Michieru <Michieru@users.noreply.github.com> | 2014-10-25 18:14:59 +0200 |
---|---|---|
committer | Michieru <Michieru@users.noreply.github.com> | 2014-10-25 18:14:59 +0200 |
commit | a5c0636f74a2177839aec9153b542afd8c36850a (patch) | |
tree | bf4f9b1e09113b4a3bcd6b02b705b3b2e9980ae2 /src | |
parent | 3e1fe0d3842aab1c85f4dfd8e3533ca6631fc4e5 (diff) | |
download | hercules-a5c0636f74a2177839aec9153b542afd8c36850a.tar.gz hercules-a5c0636f74a2177839aec9153b542afd8c36850a.tar.bz2 hercules-a5c0636f74a2177839aec9153b542afd8c36850a.tar.xz hercules-a5c0636f74a2177839aec9153b542afd8c36850a.zip |
Sight Blaster and other skill fixes, magic reflect, crash, trap display and monster behavior fixes
- Fixed cast time of Sightrasher in pre-renewal (700ms -> 500ms)
- Official Sight Blaster behavior (bugreport:6945, partially bugreport:144)
* Sight Blaster's AoE is now 3x3 even in pre-renewal (it was originally larger so it hits traps before they trigger)
* Sight Blaster will now prevent traps from triggering as long as they are knocked back
* Fixed a bug that caused Sight Blaster to not work on traps and ice walls at all
* Sight Blaster will no longer expire when the attack was reflected
* Sight Blaster will now expire when hitting an ice wall
* Sight Blaster will now properly protect you from being attacked from its AoE range
- Sight, Ruwach and Sight Blaster will now check for a target every 20ms (previously every 250ms)
- Step action will now be canceled when being knocked back (skills won't be executed anymore when knocked out of range)
- When knock back magic is reflected it will no longer lead to the caster being knocked back (related to bugreport:6945)
- Activated traps can no longer be hit
- Fixed a problem that left "trap ghosts" forever on the screen when a trap was knocked out of the screen
- Monster behavior fixes
* Monsters will no longer be able to do normal attacks when hiding
* If out of any reason a monster on "attack" state can't move and can't do normal attacks, it will now use "attack" state skills
* The order of monster thought processing is now equal to official servers
- Fixed some potential map server crashes
Mega thanks to Playtester (rathena b88e95381d6a7)
Diffstat (limited to 'src')
-rw-r--r-- | src/map/battle.c | 8 | ||||
-rw-r--r-- | src/map/clif.c | 4 | ||||
-rw-r--r-- | src/map/mob.c | 26 | ||||
-rw-r--r-- | src/map/skill.c | 4 | ||||
-rw-r--r-- | src/map/status.c | 34 | ||||
-rw-r--r-- | src/map/unit.c | 1 |
6 files changed, 52 insertions, 25 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index 3db887c42..5b041d9c3 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -6144,7 +6144,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f TBL_SKILL *su = (TBL_SKILL*)target; if( !su->group ) return 0; - if( skill->get_inf2(su->group->skill_id)&INF2_TRAP ) { //Only a few skills can target traps... + if( 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->get_current_skill(src) ) { case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps case RK_DRAGONBREATH_WATER: @@ -6243,6 +6243,7 @@ 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->group) return 0; @@ -6253,6 +6254,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_WZ_SIGHTBLASTER] && sc->data[SC_WZ_SIGHTBLASTER]->val2 > 0 && sc->data[SC_WZ_SIGHTBLASTER]->val4%2 == 0)
+ return -1;
+ } } break; case BL_MER: diff --git a/src/map/clif.c b/src/map/clif.c index ae885465b..c9ad1245c 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4785,7 +4785,9 @@ int clif_outsight(struct block_list *bl,va_list ap) } if (sd && sd->fd) { //sd is watching tbl go out of view. nullpo_ret(tbl); - if (((vd=status->get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && + 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)->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 d0a65315a..eea1ff18e 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1603,8 +1603,8 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 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) @@ -1624,6 +1624,19 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 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
+ mob->skill_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. @@ -1635,15 +1648,6 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 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 - mob->skill_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 5ea5cc424..2c52f24ac 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2120,6 +2120,7 @@ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) * packet shouldn't display a skill animation) * flag&0x2000 is used to signal that the skill_lv should be passed as -1 to the * client (causes player characters to not scream skill name) + * flag&0x4000 - Return 0 if damage was reflected *-------------------------------------------------------------------------*/ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { struct Damage dmg; @@ -2791,6 +2792,9 @@ int skill_attack(int attack_type, struct block_list* src, struct block_list *dsr map->freeblock_unlock(); + if ((flag&0x4000) && rmdamage == 1)
+ return 0; //Should return 0 when damage was reflected + return (int)cap_value(damage,INT_MIN,INT_MAX); } diff --git a/src/map/status.c b/src/map/status.c index d452d81d1..315a5e4a5 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -6015,7 +6015,9 @@ int status_get_party_id(struct block_list *bl) { return ((TBL_MER*)bl)->master->status.party_id; break; case BL_SKILL: - return ((TBL_SKILL*)bl)->group->party_id; + if (((TBL_SKILL*)bl)->group) + return ((TBL_SKILL*)bl)->group->party_id; + break; case BL_ELEM: if (((TBL_ELEM*)bl)->master) return ((TBL_ELEM*)bl)->master->status.party_id; @@ -6058,7 +6060,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; @@ -7883,8 +7887,8 @@ int status_change_start(struct block_list *src, struct block_list *bl, enum sc_t case SC_RUWACH: case SC_WZ_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; //Permanent effects. @@ -10522,14 +10526,17 @@ int status_change_timer(int tid, int64 tick, int id, intptr_t data) { case SC_SIGHT: case SC_RUWACH: case SC_WZ_SIGHTBLASTER: - if(type == SC_WZ_SIGHTBLASTER) + if(type == SC_WZ_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; @@ -11324,10 +11331,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,1,tick,0) - ){ - sce->val2 = 0; //This signals it to end. + struct skill_unit *su = (struct skill_unit *)bl;
+ if (sce && skill->attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,sce->val1,tick,0x4000)
+ && (!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 e99b9f2a1..b4653df00 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -795,6 +795,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) } if( sd ) { + unit->stop_stepaction(bl); //Stop stepaction when knocked back sd->ud.to_x = nx; sd->ud.to_y = ny; } |