// Calculate a new attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
}
}
final L2Character originalAttackTarget = getAttackTarget();
// Check if target is dead or if timeout is expired to stop this attack
if (originalAttackTarget == null || originalAttackTarget.isAlikeDead() || (originalAttackTarget instanceof L2PcInstance && (((L2PcInstance)originalAttackTarget).isOffline() || ((L2PcInstance)originalAttackTarget).isOnline()==0 )) || _attackTimeout < GameTimeController.getGameTicks())
{
// Stop hating this target after the attack timeout or if target is dead
if (originalAttackTarget != null)
((L2Attackable) _actor).stopHating(originalAttackTarget);
// Set the AI Intention to AI_INTENTION_ACTIVE
setIntention(AI_INTENTION_ACTIVE);
_actor.setWalking();
return;
}
/*
// Handle all L2Object of its Faction inside the Faction Range
if (_actor instanceof L2NpcInstance && ((L2NpcInstance) _actor).getFactionId() != null)
{
String faction_id = ((L2NpcInstance) _actor).getFactionId();
// Go through all L2Object that belong to its faction
Collection<L2Object> objs = _actor.getKnownList().getKnownObjects().values();
//synchronized (_actor.getKnownList().getKnownObjects())
try
{
for (L2Object obj : objs)
{
if (obj instanceof L2NpcInstance)
{
L2NpcInstance npc = (L2NpcInstance) obj;
//Handle SevenSigns mob Factions
String npcfaction = npc.getFactionId();
boolean sevenSignFaction = false;
// TODO: Unhardcode this by AI scripts (DrHouse)
//Catacomb mobs should assist lilim and nephilim other than dungeon
if ("c_dungeon_clan".equals(faction_id) && ("c_dungeon_lilim".equals(npcfaction) || "c_dungeon_nephi".equals(npcfaction)))
sevenSignFaction = true;
//Lilim mobs should assist other Lilim and catacomb mobs
else if ("c_dungeon_lilim".equals(faction_id) && "c_dungeon_clan".equals(npcfaction))
sevenSignFaction = true;
//Nephilim mobs should assist other Nephilim and catacomb mobs
else if ("c_dungeon_nephi".equals(faction_id) && "c_dungeon_clan".equals(npcfaction))
sevenSignFaction = true;
if (!faction_id.equals(npc.getFactionId()) && !sevenSignFaction)
continue;
// Check if the L2Object is inside the Faction Range of
// the actor
if (_actor.isInsideRadius(npc, npc.getFactionRange() + npc.getTemplate().collisionRadius, true, false) && npc.getAI() != null)
{
if (Math.abs(originalAttackTarget.getZ() - npc.getZ()) < 600 && _actor.getAttackByList().contains(originalAttackTarget) && (npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE || npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE) && GeoData.getInstance().canSeeTarget(_actor, npc))
{
if ((originalAttackTarget instanceof L2PcInstance) || (originalAttackTarget instanceof L2Summon))
{
if (npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_FACTION_CALL) != null)
{
L2PcInstance player = (originalAttackTarget instanceof L2PcInstance) ? (L2PcInstance) originalAttackTarget : ((L2Summon) originalAttackTarget).getOwner();
for (Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_FACTION_CALL))
quest.notifyFactionCall(npc, (L2NpcInstance) _actor, player, (originalAttackTarget instanceof L2Summon));
}
}
else if (npc instanceof L2Attackable && getAttackTarget() != null && npc.getAI()._intention != CtrlIntention.AI_INTENTION_ATTACK)
{
((L2Attackable) npc).addDamageHate(getAttackTarget(), 0, ((L2Attackable) _actor).getHating(getAttackTarget()));
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, getAttackTarget());
}
}
}
}
}
}
catch (NullPointerException e)
{
_log.log(Level.WARNING, "L2AttackableAI: thinkAttack() faction call failed: " + e.getMessage(), e);
}
}
*/
// Call all L2Object of its Faction inside the Faction Range
if(((L2NpcInstance) _actor).getFactionId() != null)
{
// Go through all L2Object that belong to its faction
for(L2Object obj : _actor.getKnownList().getKnownObjects().values())
{
if(obj instanceof L2NpcInstance)
{
L2NpcInstance npc = (L2NpcInstance) obj;
String faction_id = ((L2NpcInstance) _actor).getFactionId();
if(!faction_id.equalsIgnoreCase(npc.getFactionId()) || npc.getFactionRange() == 0)
{
faction_id = null;
continue;
}
// Check if the L2Object is inside the Faction Range of the actor
if(_actor.getAttackByList()!=null && _actor.isInsideRadius(npc, npc.getFactionRange(), true, false) && npc.getAI() != null &&
_actor.getAttackByList().contains(originalAttackTarget))
{
if(npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE || npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE){
if(GeoData.getInstance().canSeeTarget(_actor, npc) && Math.abs(originalAttackTarget.getZ() - npc.getZ()) < 600){
if(originalAttackTarget instanceof L2PcInstance && originalAttackTarget.isInParty() && originalAttackTarget.getParty().isInDimensionalRift())
{
byte riftType = originalAttackTarget.getParty().getDimensionalRift().getType();
byte riftRoom = originalAttackTarget.getParty().getDimensionalRift().getCurrentRoom();
if(_actor instanceof L2RiftInvaderInstance && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(npc.getX(), npc.getY(), npc.getZ()))
{
continue;
}
}
// Notify the L2Object AI with EVT_AGGRESSION
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, originalAttackTarget, 1);
}
}
if(GeoData.getInstance().canSeeTarget(_actor, npc) && Math.abs(originalAttackTarget.getZ() - npc.getZ()) < 500){
if(originalAttackTarget instanceof L2PcInstance || originalAttackTarget instanceof L2Summon)
{
L2PcInstance player = originalAttackTarget instanceof L2PcInstance ? (L2PcInstance) originalAttackTarget : ((L2Summon) originalAttackTarget).getOwner();
for(Quest quest : npc.getTemplate().getEventQuests(Quest.QuestEventType.ON_FACTION_CALL))
{
quest.notifyFactionCall(npc, (L2NpcInstance) _actor, player, (originalAttackTarget instanceof L2Summon));
}
}
}
}
npc = null;
}
}
}
if(_actor.isAttackingDisabled())
return;
// Get all information needed to chose between physical or magical attack
L2Skill[] skills = null;
double dist2 = 0;
int range = 0;
try
{
_actor.setTarget(originalAttackTarget);
skills = _actor.getAllSkills();
dist2 = _actor.getPlanDistanceSq(originalAttackTarget.getX(), originalAttackTarget.getY());
range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + originalAttackTarget.getTemplate().collisionRadius;
}
catch(NullPointerException e)
{
//_log.warning("AttackableAI: Attack target is NULL.");
if(Config.ENABLE_ALL_EXCEPTIONS)
e.printStackTrace();
setIntention(AI_INTENTION_ACTIVE);
return;
}
L2Weapon weapon = _actor.getActiveWeaponItem();
final int collision = _actor.getTemplate().collisionRadius;
final int combinedCollision = collision + originalAttackTarget.getTemplate().collisionRadius;
//------------------------------------------------------
// In case many mobs are trying to hit from same place, move a bit,
// circling around the target
// Note from Gnacik:
// On l2js because of that sometimes mobs don't attack player only running
// around player without any sense, so decrease chance for now
if (!_actor.isMovementDisabled() && Rnd.nextInt(100) <= 3)
{
for (L2Object nearby : _actor.getKnownList().getKnownObjects().values())
{
if (nearby instanceof L2Attackable
&& _actor.isInsideRadius(nearby, collision, false, false)
&& nearby != originalAttackTarget)
{
int newX = combinedCollision + Rnd.get(40);
if (Rnd.nextBoolean())
newX = originalAttackTarget.getX() + newX;
else
newX = originalAttackTarget.getX() - newX;
int newY = combinedCollision + Rnd.get(40);
if (Rnd.nextBoolean())
newY = originalAttackTarget.getY() + newY;
else
newY = originalAttackTarget.getY() - newY;
if (!_actor.isInsideRadius(newX, newY, collision, false))
{
int newZ = _actor.getZ() + 30;
if (Config.GEODATA == 0 || GeoData.getInstance().canMoveFromToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), newX, newY, newZ))
moveTo(newX, newY, newZ);
}
return;
}
}
}
if(weapon != null && weapon.getItemType() == L2WeaponType.BOW)
{
// Micht: kepping this one otherwise we should do 2 sqrt
double distance2 = _actor.getPlanDistanceSq(originalAttackTarget.getX(), originalAttackTarget.getY());
if (Math.sqrt(distance2) <= 60 + combinedCollision)
{
//double distance2 = _actor.getPlanDistanceSq(originalAttackTarget.getX(), originalAttackTarget.getY());
//if(distance2 <= 10000)
//{
int chance = 5;
if(chance >= Rnd.get(100))
{
int posX = _actor.getX();
int posY = _actor.getY();
int posZ = _actor.getZ();
double distance = Math.sqrt(distance2); // This way, we only do the sqrt if we need it
int signx = -1;
int signy = -1;
if(_actor.getX() > originalAttackTarget.getX())
{
signx = 1;
}
if(_actor.getY() > originalAttackTarget.getY())
{
signy = 1;
}
posX += Math.round((float) (signx * (range / 2 + Rnd.get(range)) - distance));
posY += Math.round((float) (signy * (range / 2 + Rnd.get(range)) - distance));
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(posX, posY, posZ, 0));
return;
}
}
}
weapon = null;
// Force mobs to attack anybody if confused
L2Character hated;
if(_actor.isConfused())
{
hated = originalAttackTarget;
}
else
{
hated = ((L2Attackable) _actor).getMostHated();
}
if(hated == null)
{
setIntention(AI_INTENTION_ACTIVE);
return;
}
if(hated != originalAttackTarget)
{
setAttackTarget(hated);
}
// We should calculate new distance cuz mob can have changed the target
dist2 = _actor.getPlanDistanceSq(hated.getX(), hated.getY());
if(hated.isMoving())
{
range += 50;
}
// Check if the actor isn't far from target
if(dist2 > range * range)
{
// check for long ranged skills and heal/buff skills
if(!_actor.isMuted() && (!Config.ALT_GAME_MOB_ATTACK_AI || _actor instanceof L2MonsterInstance && Rnd.nextInt(100) <= 5))
{
for(L2Skill sk : skills)
{
int castRange = sk.getCastRange();
boolean _inRange = false;
if(dist2 >= castRange * castRange / 9.0 && dist2 <= castRange * castRange && castRange > 70){
_inRange = true;
}
if((sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL || _inRange) && !_actor.isSkillDisabled(sk.getId()) && _actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk) && !sk.isPassive() && Rnd.nextInt(100) <= 5)
{
if(sk.getSkillType() == L2Skill.SkillType.BUFF || sk.getSkillType() == L2Skill.SkillType.HEAL)
{
boolean useSkillSelf = true;
if(sk.getSkillType() == L2Skill.SkillType.HEAL && _actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5))
{
useSkillSelf = false;
break;
}
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)
{
useSkillSelf = false;
break;
}
}
effects = null;
}
if(useSkillSelf)
{
_actor.setTarget(_actor);
}
}
L2Object OldTarget = _actor.getTarget();
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
OldTarget = null;
return;
}
}
}
// Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
if(hated.isMoving())
{
range -= 100;
}
if(range < 5)
{