Index: /java/net/sf/l2j/gameserver/ai/AbstractAI.java =================================================================== --- /java/net/sf/l2j/gameserver/ai/AbstractAI.java (revision 656) +++ /java/net/sf/l2j/gameserver/ai/AbstractAI.java (working copy) @@ -328,6 +328,9 @@ case EVT_CONFUSED: onEvtConfused((L2Character)arg0); break; + case EVT_MUTED: + onEvtMuted((L2Character)arg0); + break; case EVT_READY_TO_ACT: onEvtReadyToAct(); break; @@ -376,6 +379,7 @@ protected abstract void onEvtSleeping(L2Character attacker); protected abstract void onEvtRooted(L2Character attacker); protected abstract void onEvtConfused(L2Character attacker); + protected abstract void onEvtMuted(L2Character attacker); protected abstract void onEvtReadyToAct(); protected abstract void onEvtUserCmd(Object arg0, Object arg1); protected abstract void onEvtArrived(); Index: /java/net/sf/l2j/gameserver/ai/L2CharacterAI.java =================================================================== --- /java/net/sf/l2j/gameserver/ai/L2CharacterAI.java (revision 659) +++ /java/net/sf/l2j/gameserver/ai/L2CharacterAI.java (working copy) @@ -547,7 +547,27 @@ } + /** + * Launch actions corresponding to the Event Muted.

+ * + * Actions :

+ *
  • Break an attack and send Server->Client ActionFailed packet and a System Message to the L2Character
  • + *
  • Launch actions corresponding to the Event onAttacked


  • + * + */ + protected void onEvtMuted(L2Character attacker) + { + // Break an attack and send Server->Client ActionFailed packet and a System Message to the L2Character + _actor.breakCast(); + + // Launch actions corresponding to the Event onAttacked + onEvtAttacked(attacker); + + } + + + /** * Launch actions corresponding to the Event ReadyToAct.

    * * Actions :

    Index: /java/net/sf/l2j/gameserver/ai/L2AttackableAI.java =================================================================== --- /java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (revision 659) +++ /java/net/sf/l2j/gameserver/ai/L2AttackableAI.java (working copy) @@ -33,6 +33,7 @@ import net.sf.l2j.gameserver.model.L2Attackable; import net.sf.l2j.gameserver.model.L2Character; import net.sf.l2j.gameserver.model.L2DoorInstance; +import net.sf.l2j.gameserver.model.L2Effect; import net.sf.l2j.gameserver.model.L2FolkInstance; import net.sf.l2j.gameserver.model.L2FriendlyMobInstance; import net.sf.l2j.gameserver.model.L2GuardInstance; @@ -509,7 +510,6 @@ L2Skill[] skills = null; double dist = 0; int range = 0; - int max_range = 0; try { @@ -517,52 +517,47 @@ skills = _actor.getAllSkills(); dist = _actor.getDistance(_attack_target.getX(), _attack_target.getY()); range = _actor.getPhysicalAttackRange(); - max_range = range; } catch (NullPointerException e) { _log.warning("AttackableAI: Attack traget is NULL."); //e.printStackTrace(); } - + // If this is NOT muted and still far from target + if (!_actor.isMuted() && dist > range+20) + { + // check for long ranged skills and heal/buff skills + if ( !Config.ALT_GAME_MOB_ATTACK_AI && _rnd.nextInt(100) <= 5) + for (L2Skill sk : skills) { + if ((((sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) && (dist >= sk.getCastRange())) || dist >= sk.getCastRange()/3) && + !_actor.isSkillDisabled(sk.getId()) && _actor.getCurrentMp() >= sk.getMpConsume() && !sk.isPassive()) + { + L2Object OldTarget = _actor.getTarget(); + if (sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) + { + boolean useSkill = true; + if (sk.getSkillType() == L2Skill.SkillType.HEAL && _actor.getCurrentHp() > (int)(_actor.getMaxHp()/1.5)) useSkill = false; + if (sk.getSkillType() == L2Skill.SkillType.BUFF) { + L2Effect[] effects = _actor.getAllEffects(); + for(int i = 0; effects != null && i < effects.length; i++) + { + L2Effect effect = effects[i]; + if (effect.getSkill() == sk) { + useSkill = false; + break; + } + } + } + if (useSkill) + _actor.setTarget(_actor); + } + + clientStopMoving(null); + _accessor.doCast(sk); + _actor.setTarget(OldTarget); + return; + } - // Check if the actor isn't muted and if it can't use physical attack - if (!_actor.isMuted() && dist > range+20) - { - // check distant skills - if ( !Config.ALT_GAME_MOB_ATTACK_AI || - (!(_actor instanceof L2MonsterInstance) || - (_actor instanceof L2MonsterInstance && _rnd.nextInt(40) == 1))) - for (L2Skill sk : skills) - { - // Check if the skill isn't disabled, if the target is inside the skill range and if actor has enough MP - if (sk.getCastRange() >= dist && !_actor.isSkillDisabled(sk.getId()) && - _actor.getCurrentMp() > sk.getMpConsume()) - { - - // If the skill is a BUFF or a HEAL change target - L2Object OldTarget = _actor.getTarget(); - if (sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) - { - _actor.setTarget(_actor); - } - - // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast) - clientStopMoving(null); - - // Manage the casting task (casting and interrupt time, re-use delay...) and display the casting bar and animation on client - _accessor.doCast(sk); - - // Restore initial target - _actor.setTarget(OldTarget); - - return; - } - - max_range = Math.max(max_range, sk.getCastRange()); - } - - // Check if the actor is a L2SiegeGuardInstance if (_actor instanceof L2SiegeGuardInstance) { @@ -595,7 +590,6 @@ moveToPawn(_attack_target, range); } } - } else { @@ -607,67 +601,77 @@ } - - // Chose a target from its aggroList - L2Character hated; - if (_actor.isConfused()) - hated = _attack_target; // Force mobs to attak anybody if confused - else - hated =((L2Attackable)_actor).getMostHated(); - - - // Order to the L2Attackable to attack the target - if (hated == null) + // Else, if this IS muted and still far, just move + else if (_actor.isMuted() && dist > range+20) { // Set the AI Intention to AI_INTENTION_ACTIVE - setIntention(AI_INTENTION_ACTIVE); + moveToPawn(_attack_target, range); return; } - if (hated != _attack_target) - _attack_target = hated; - - // Calculate the attack timeout - _attack_timeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks(); - - // Check if the actor isn't muted and if it has skills - if (!_actor.isMuted() && skills.length > 0 && _rnd.nextInt(5) == 3) + // Else, if this is close enough to attack + else if (dist <= range+20) + { + // Force mobs to attak anybody if confused + L2Character hated; + if (_actor.isConfused()) + hated = _attack_target; + else + hated =((L2Attackable)_actor).getMostHated(); + + if (hated == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (hated != _attack_target) + _attack_target = hated; + + _attack_timeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks(); + + // check for close combat skills && heal/buff skills + if (!_actor.isMuted() && _rnd.nextInt(100) <= 5) + { + for (L2Skill sk : skills) + { + if (sk.getCastRange() >= (int)dist && sk.getCastRange() <= 70 && !sk.isPassive() && + _actor.getCurrentMp() >= sk.getMpConsume() && !_actor.isSkillDisabled(sk.getId())) { - // Go through the actor skills - for (L2Skill sk : skills) - { - // Check if the skill isn't disabled, if the target is inside the skill range and if actor has enough MP - if (sk.getCastRange() >= dist && !_actor.isSkillDisabled(sk.getId()) && - _actor.getCurrentMp() < sk.getMpConsume()) - { - // If the skill is a BUFF or a HEAL change target - L2Object OldTarget = _actor.getTarget(); - if (sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) - { - _actor.setTarget(_actor); - } - - // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast) - // clientStopMoving(null); - - // Manage the casting task (casting and interrupt time, re-use delay...) and display the casting bar and animation on client - _accessor.doCast(sk); - - // Restore initial target - _actor.setTarget(OldTarget); - - return; - } - } + L2Object OldTarget = _actor.getTarget(); + if (sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL) + { + boolean useSkill = true; + if (sk.getSkillType() == L2Skill.SkillType.HEAL && _actor.getCurrentHp() > (int)(_actor.getMaxHp()/1.5)) useSkill = false; + if (sk.getSkillType() == L2Skill.SkillType.BUFF) { + L2Effect[] effects = _actor.getAllEffects(); + for(int i = 0; effects != null && i < effects.length; i++) + { + L2Effect effect = effects[i]; + if (effect.getSkill() == sk) + { + useSkill = false; + break; + } + } + } + if (useSkill) + _actor.setTarget(_actor); + } + + clientStopMoving(null); + _accessor.doCast(sk); + _actor.setTarget(OldTarget); + return; + } + } } - // Launch a physical attack against a target (Simple, Bow, Pole or Dual) _accessor.doAttack(_attack_target); - - } - } + } + } + } + } - /** * Manage AI thinking actions of a L2Attackable.

    */