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.
*/