Merged with released L2J-Unity files.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,103 +1,90 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* Interface of AI and client state.<br>
|
||||
* To correctly send messages to client we need it's state.<br>
|
||||
* For example, if we've sent 'StartAutoAttack' message, we need to send 'StopAutoAttack' message before any other action.<br>
|
||||
* Or if we've sent 'MoveToPawn', we need to send 'StopMove' when the movement of a character is canceled (by Root spell or any other reason).<br>
|
||||
* Thus, we need to know the state of client, i.e. which messages we've sent and how the client will show the scene.<br>
|
||||
* Close to this task is the task of AI.<br>
|
||||
* If a player's character is attacking a mob, his ATTACK may be interrupted by an event, that temporary disable attacking.<br>
|
||||
* But when the possibility to ATTACK will be enabled, the character must continue the ATTACK.<br>
|
||||
* For mobs it may be more complex, since we want them to decide when to use magic, or when to follow the player for physical combat, or when to escape, to help another mob, etc.<br>
|
||||
* This interface is hiding complexity of server<->client interaction and multiple states of a character.<br>
|
||||
* It allows to set a desired, simple "wish" of a character, and the implementation of this interface will take care about the rest.<br>
|
||||
* The goal of a character may be like "ATTACK", "random walk" and so on.<br>
|
||||
* To reach the goal implementation will split it into several small actions, several steps (possibly repeatable).<br>
|
||||
* Like "run to target" then "hit it", then if target is not dead - repeat.<br>
|
||||
* This flow of simpler steps may be interrupted by incoming events.<br>
|
||||
* Like a character's movement was disabled (by Root spell, for instance).<br>
|
||||
* Depending on character's ability AI may choose to wait, or to use magic ATTACK and so on.<br>
|
||||
* Additionally incoming events are compared with client's state of the character,<br>
|
||||
* and required network messages are sent to client's, i.e. if we have incoming event that character's movement was disabled, it causes changing if its behavior,<br>
|
||||
* and if client's state for the character is "moving" we send messages to clients to stop the avatar/mob.
|
||||
*/
|
||||
public interface Ctrl
|
||||
{
|
||||
/**
|
||||
* Gets the actor.
|
||||
* @return the actor
|
||||
*/
|
||||
L2Character getActor();
|
||||
|
||||
/**
|
||||
* Gets the intention.
|
||||
* @return the intention
|
||||
*/
|
||||
CtrlIntention getIntention();
|
||||
|
||||
/**
|
||||
* Gets the attack target.
|
||||
* @return the attack target
|
||||
*/
|
||||
L2Character getAttackTarget();
|
||||
|
||||
/**
|
||||
* Set general state/intention for AI, with optional data.
|
||||
* @param intention the new intention
|
||||
*/
|
||||
void setIntention(CtrlIntention intention);
|
||||
|
||||
/**
|
||||
* Sets the intention.
|
||||
* @param intention the intention
|
||||
* @param arg0 the arg0
|
||||
*/
|
||||
void setIntention(CtrlIntention intention, Object arg0);
|
||||
|
||||
/**
|
||||
* Sets the intention.
|
||||
* @param intention the intention
|
||||
* @param arg0 the arg0
|
||||
* @param arg1 the arg1
|
||||
*/
|
||||
void setIntention(CtrlIntention intention, Object arg0, Object arg1);
|
||||
|
||||
/**
|
||||
* Event, that notifies about previous step result, or user command, that does not change current general intention.
|
||||
* @param evt the event
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt);
|
||||
|
||||
/**
|
||||
* Notify an event.
|
||||
* @param evt the event
|
||||
* @param arg0 the arg0
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt, Object arg0);
|
||||
|
||||
/**
|
||||
* Notify an event.
|
||||
* @param evt the event
|
||||
* @param args the args
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt, Object... args);
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* Interface of AI and client state.<br>
|
||||
* To correctly send messages to client we need it's state.<br>
|
||||
* For example, if we've sent 'StartAutoAttack' message, we need to send 'StopAutoAttack' message before any other action.<br>
|
||||
* Or if we've sent 'MoveToPawn', we need to send 'StopMove' when the movement of a character is canceled (by Root spell or any other reason).<br>
|
||||
* Thus, we need to know the state of client, i.e. which messages we've sent and how the client will show the scene.<br>
|
||||
* Close to this task is the task of AI.<br>
|
||||
* If a player's character is attacking a mob, his ATTACK may be interrupted by an event, that temporary disable attacking.<br>
|
||||
* But when the possibility to ATTACK will be enabled, the character must continue the ATTACK.<br>
|
||||
* For mobs it may be more complex, since we want them to decide when to use magic, or when to follow the player for physical combat, or when to escape, to help another mob, etc.<br>
|
||||
* This interface is hiding complexity of server<->client interaction and multiple states of a character.<br>
|
||||
* It allows to set a desired, simple "wish" of a character, and the implementation of this interface will take care about the rest.<br>
|
||||
* The goal of a character may be like "ATTACK", "random walk" and so on.<br>
|
||||
* To reach the goal implementation will split it into several small actions, several steps (possibly repeatable).<br>
|
||||
* Like "run to target" then "hit it", then if target is not dead - repeat.<br>
|
||||
* This flow of simpler steps may be interrupted by incoming events.<br>
|
||||
* Like a character's movement was disabled (by Root spell, for instance).<br>
|
||||
* Depending on character's ability AI may choose to wait, or to use magic ATTACK and so on.<br>
|
||||
* Additionally incoming events are compared with client's state of the character,<br>
|
||||
* and required network messages are sent to client's, i.e. if we have incoming event that character's movement was disabled, it causes changing if its behavior,<br>
|
||||
* and if client's state for the character is "moving" we send messages to clients to stop the avatar/mob.
|
||||
*/
|
||||
public interface Ctrl
|
||||
{
|
||||
/**
|
||||
* Gets the actor.
|
||||
* @return the actor
|
||||
*/
|
||||
L2Character getActor();
|
||||
|
||||
/**
|
||||
* Gets the intention.
|
||||
* @return the intention
|
||||
*/
|
||||
CtrlIntention getIntention();
|
||||
|
||||
/**
|
||||
* Set general state/intention for AI, with optional data.
|
||||
* @param intention the new intention
|
||||
*/
|
||||
void setIntention(CtrlIntention intention);
|
||||
|
||||
/**
|
||||
* Sets the intention.
|
||||
* @param intention the intention
|
||||
* @param args
|
||||
*/
|
||||
void setIntention(CtrlIntention intention, Object... args);
|
||||
|
||||
/**
|
||||
* Event, that notifies about previous step result, or user command, that does not change current general intention.
|
||||
* @param evt the event
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt);
|
||||
|
||||
/**
|
||||
* Notify an event.
|
||||
* @param evt the event
|
||||
* @param arg0 the arg0
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt, Object arg0);
|
||||
|
||||
/**
|
||||
* Notify an event.
|
||||
* @param evt the event
|
||||
* @param arg0 the arg0
|
||||
* @param arg1 the arg1
|
||||
*/
|
||||
void notifyEvent(CtrlEvent evt, Object arg0, Object arg1);
|
||||
}
|
||||
|
@ -1,88 +1,80 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
/**
|
||||
* This class contains an enum of each possibles events that can happen on an AI character.
|
||||
*/
|
||||
public enum CtrlEvent
|
||||
{
|
||||
/**
|
||||
* Something has changed, usually a previous step has being completed or maybe was completed, the AI must thing on next action.
|
||||
*/
|
||||
EVT_THINK,
|
||||
/**
|
||||
* The actor was attacked. This event comes each time a physical or magical<br>
|
||||
* attack was done on the actor. NPC may start attack in response, or ignore<br>
|
||||
* this event if they already attack someone, or change target and so on.
|
||||
*/
|
||||
EVT_ATTACKED,
|
||||
/** Increase/decrease aggression towards a target, or reduce global aggression if target is null */
|
||||
EVT_AGGRESSION,
|
||||
/** Actor is in stun state */
|
||||
EVT_STUNNED,
|
||||
/** Actor is paralyzed or petrified */
|
||||
EVT_PARALYZED,
|
||||
/** Actor starts/stops sleeping */
|
||||
EVT_SLEEPING,
|
||||
/** Actor is in rooted state (cannot move) */
|
||||
EVT_ROOTED,
|
||||
/** Actor evaded hit **/
|
||||
EVT_EVADED,
|
||||
/**
|
||||
* An event that previous action was completed. The action may be an attempt to physically/magically hit an enemy, or an action that discarded attack attempt has finished.
|
||||
*/
|
||||
EVT_READY_TO_ACT,
|
||||
/**
|
||||
* User's command, like using a combat magic or changing weapon, etc. The command is not intended to change final goal
|
||||
*/
|
||||
EVT_USER_CMD,
|
||||
/**
|
||||
* The actor arrived to assigned location, or it's a time to modify movement destination (follow, interact, random move and others intentions).
|
||||
*/
|
||||
EVT_ARRIVED,
|
||||
/**
|
||||
* The actor arrived to an intermediate point, and needs to revalidate destination. This is sent when follow/move to pawn if destination is far away.
|
||||
*/
|
||||
EVT_ARRIVED_REVALIDATE,
|
||||
/** The actor cannot move anymore. */
|
||||
EVT_ARRIVED_BLOCKED,
|
||||
/** Forgets an object (if it's used as attack target, follow target and so on */
|
||||
EVT_FORGET_OBJECT,
|
||||
/**
|
||||
* Attempt to cancel current step execution, but not change the intention.<br>
|
||||
* For example, the actor was put into a stun, so it's current attack<br>
|
||||
* or movement has to be canceled. But after the stun state expired,<br>
|
||||
* the actor may try to attack again. Another usage for CANCEL is a user's<br>
|
||||
* attempt to cancel a cast/bow attack and so on.
|
||||
*/
|
||||
EVT_CANCEL,
|
||||
/** The character is dead */
|
||||
EVT_DEAD,
|
||||
/** The character looks like dead */
|
||||
EVT_FAKE_DEATH,
|
||||
/** The character attack anyone randomly **/
|
||||
EVT_CONFUSED,
|
||||
/** The character cannot cast spells anymore **/
|
||||
EVT_MUTED,
|
||||
/** The character flee in random directions **/
|
||||
EVT_AFRAID,
|
||||
/** The character finish casting **/
|
||||
EVT_FINISH_CASTING,
|
||||
/** The character betrayed its master */
|
||||
EVT_BETRAYED
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
/**
|
||||
* This class contains an enum of each possibles events that can happen on an AI character.
|
||||
*/
|
||||
public enum CtrlEvent
|
||||
{
|
||||
/**
|
||||
* Something has changed, usually a previous step has being completed or maybe was completed, the AI must thing on next action.
|
||||
*/
|
||||
EVT_THINK,
|
||||
/**
|
||||
* The actor was attacked. This event comes each time a physical or magical<br>
|
||||
* attack was done on the actor. NPC may start attack in response, or ignore<br>
|
||||
* this event if they already attack someone, or change target and so on.
|
||||
*/
|
||||
EVT_ATTACKED,
|
||||
/** Increase/decrease aggression towards a target, or reduce global aggression if target is null */
|
||||
EVT_AGGRESSION,
|
||||
/** Actor is in stun state */
|
||||
EVT_ACTION_BLOCKED,
|
||||
/** Actor is in rooted state (cannot move) */
|
||||
EVT_ROOTED,
|
||||
/** Actor evaded hit **/
|
||||
EVT_EVADED,
|
||||
/**
|
||||
* An event that previous action was completed. The action may be an attempt to physically/magically hit an enemy, or an action that discarded attack attempt has finished.
|
||||
*/
|
||||
EVT_READY_TO_ACT,
|
||||
/**
|
||||
* The actor arrived to assigned location, or it's a time to modify movement destination (follow, interact, random move and others intentions).
|
||||
*/
|
||||
EVT_ARRIVED,
|
||||
/**
|
||||
* The actor arrived to an intermediate point, and needs to revalidate destination. This is sent when follow/move to pawn if destination is far away.
|
||||
*/
|
||||
EVT_ARRIVED_REVALIDATE,
|
||||
/** The actor cannot move anymore. */
|
||||
EVT_ARRIVED_BLOCKED,
|
||||
/** Forgets an object (if it's used as attack target, follow target and so on */
|
||||
EVT_FORGET_OBJECT,
|
||||
/**
|
||||
* Attempt to cancel current step execution, but not change the intention.<br>
|
||||
* For example, the actor was put into a stun, so it's current attack<br>
|
||||
* or movement has to be canceled. But after the stun state expired,<br>
|
||||
* the actor may try to attack again. Another usage for CANCEL is a user's<br>
|
||||
* attempt to cancel a cast/bow attack and so on.
|
||||
*/
|
||||
EVT_CANCEL,
|
||||
/** The character is dead */
|
||||
EVT_DEAD,
|
||||
/** The character looks like dead */
|
||||
EVT_FAKE_DEATH,
|
||||
/** The character attack anyone randomly **/
|
||||
EVT_CONFUSED,
|
||||
/** The character cannot cast spells anymore **/
|
||||
EVT_MUTED,
|
||||
/** The character flee in random directions **/
|
||||
EVT_AFRAID,
|
||||
/** The character finish casting **/
|
||||
EVT_FINISH_CASTING,
|
||||
/** The character betrayed its master */
|
||||
EVT_BETRAYED
|
||||
}
|
||||
|
273
trunk/java/com/l2jmobius/gameserver/ai/DoppelgangerAI.java
Normal file
273
trunk/java/com/l2jmobius/gameserver/ai/DoppelgangerAI.java
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
import com.l2jmobius.gameserver.GameTimeController;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.DoppelgangerInstance;
|
||||
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.skills.SkillCaster;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
|
||||
|
||||
public class DoppelgangerAI extends L2CharacterAI
|
||||
{
|
||||
private volatile boolean _thinking; // to prevent recursive thinking
|
||||
private volatile boolean _startFollow;
|
||||
private L2Character _lastAttack = null;
|
||||
|
||||
public DoppelgangerAI(DoppelgangerInstance clone)
|
||||
{
|
||||
super(clone);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionIdle()
|
||||
{
|
||||
stopFollow();
|
||||
_startFollow = false;
|
||||
onIntentionActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
if (_startFollow)
|
||||
{
|
||||
setIntention(AI_INTENTION_FOLLOW, getActor().getSummoner());
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onIntentionActive();
|
||||
}
|
||||
}
|
||||
|
||||
private void thinkAttack()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
final L2Character attackTarget = (target != null) && target.isCharacter() ? (L2Character) target : null;
|
||||
|
||||
if (checkTargetLostOrDead(attackTarget))
|
||||
{
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
{
|
||||
if (_actor.isCastingNow(SkillCaster::isAnyNormalType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final L2Object target = _skill.getTarget(_actor, _forceUse, _dontMove, false);
|
||||
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
final boolean val = _startFollow;
|
||||
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
getActor().followSummoner(false);
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
_startFollow = val;
|
||||
_actor.doCast(_skill, _item, _forceUse, _dontMove);
|
||||
}
|
||||
|
||||
private void thinkInteract()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_thinking = true;
|
||||
try
|
||||
{
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ATTACK:
|
||||
thinkAttack();
|
||||
break;
|
||||
case AI_INTENTION_CAST:
|
||||
thinkCast();
|
||||
break;
|
||||
case AI_INTENTION_INTERACT:
|
||||
thinkInteract();
|
||||
break;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
if (_lastAttack == null)
|
||||
{
|
||||
getActor().followSummoner(_startFollow);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
|
||||
_lastAttack = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyFollowStatusChange()
|
||||
{
|
||||
_startFollow = !_startFollow;
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ACTIVE:
|
||||
case AI_INTENTION_FOLLOW:
|
||||
case AI_INTENTION_IDLE:
|
||||
case AI_INTENTION_MOVE_TO:
|
||||
case AI_INTENTION_PICK_UP:
|
||||
getActor().followSummoner(_startFollow);
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartFollowController(boolean val)
|
||||
{
|
||||
_startFollow = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_ATTACK)
|
||||
{
|
||||
_lastAttack = (getTarget() != null) && getTarget().isCharacter() ? (L2Character) getTarget() : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastAttack = null;
|
||||
}
|
||||
super.onIntentionCast(skill, target, item, forceUse, dontMove);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveToPawn(L2Object pawn, int offset)
|
||||
{
|
||||
// Check if actor can move
|
||||
if (!_actor.isMovementDisabled() && (_actor.getMoveSpeed() > 0))
|
||||
{
|
||||
if (offset < 10)
|
||||
{
|
||||
offset = 10;
|
||||
}
|
||||
|
||||
// prevent possible extra calls to this function (there is none?),
|
||||
// also don't send movetopawn packets too often
|
||||
boolean sendPacket = true;
|
||||
if (_clientMoving && (getTarget() == pawn))
|
||||
{
|
||||
if (_clientMovingToPawnOffset == offset)
|
||||
{
|
||||
if (GameTimeController.getInstance().getGameTicks() < _moveToPawnTimeout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sendPacket = false;
|
||||
}
|
||||
else if (_actor.isOnGeodataPath())
|
||||
{
|
||||
// minimum time to calculate new route is 2 seconds
|
||||
if (GameTimeController.getInstance().getGameTicks() < (_moveToPawnTimeout + 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set AI movement data
|
||||
_clientMoving = true;
|
||||
_clientMovingToPawnOffset = offset;
|
||||
setTarget(pawn);
|
||||
_moveToPawnTimeout = GameTimeController.getInstance().getGameTicks();
|
||||
_moveToPawnTimeout += 1000 / GameTimeController.MILLIS_IN_TICK;
|
||||
|
||||
if (pawn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
|
||||
// _actor.moveToLocation(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
|
||||
final Location loc = new Location(pawn.getX() + Rnd.get(-offset, offset), pawn.getY() + Rnd.get(-offset, offset), pawn.getZ());
|
||||
_actor.moveToLocation(loc.getX(), loc.getY(), loc.getZ(), 0);
|
||||
|
||||
if (!_actor.isMoving())
|
||||
{
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Doppelgangers always send MoveToLocation packet.
|
||||
if (sendPacket)
|
||||
{
|
||||
_actor.broadcastPacket(new MoveToLocation(_actor));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clientActionFailed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoppelgangerInstance getActor()
|
||||
{
|
||||
return (DoppelgangerInstance) super.getActor();
|
||||
}
|
||||
}
|
245
trunk/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java
Normal file
245
trunk/java/com/l2jmobius/gameserver/ai/FriendlyNpcAI.java
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
import com.l2jmobius.gameserver.GeoData;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.L2World;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Attackable;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* @author Sdw
|
||||
*/
|
||||
public class FriendlyNpcAI extends L2AttackableAI
|
||||
{
|
||||
public FriendlyNpcAI(L2Attackable attackable)
|
||||
{
|
||||
super(attackable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void thinkActive()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAggression(L2Character target, int aggro)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getIntention() == AI_INTENTION_REST)
|
||||
{
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isControlBlocked())
|
||||
{
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the Intention of this AbstractAI to AI_INTENTION_ATTACK
|
||||
changeIntention(AI_INTENTION_ATTACK, target);
|
||||
|
||||
// Set the AI attack target
|
||||
setTarget(target);
|
||||
|
||||
stopFollow();
|
||||
|
||||
// Launch the Think Event
|
||||
notifyEvent(CtrlEvent.EVT_THINK, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void thinkAttack()
|
||||
{
|
||||
final L2Attackable npc = getActiveChar();
|
||||
if (npc.isCastingNow() || npc.isCoreAIDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final L2Object target = getTarget();
|
||||
final L2Character originalAttackTarget = (target != null) && target.isCharacter() ? (L2Character) target : null;
|
||||
// Check if target is dead or if timeout is expired to stop this attack
|
||||
if ((originalAttackTarget == null) || originalAttackTarget.isAlikeDead())
|
||||
{
|
||||
// Stop hating this target after the attack timeout or if target is dead
|
||||
if (originalAttackTarget != null)
|
||||
{
|
||||
npc.stopHating(originalAttackTarget);
|
||||
}
|
||||
|
||||
// Set the AI Intention to AI_INTENTION_ACTIVE
|
||||
setIntention(AI_INTENTION_ACTIVE);
|
||||
|
||||
npc.setWalking();
|
||||
return;
|
||||
}
|
||||
|
||||
final int collision = npc.getTemplate().getCollisionRadius();
|
||||
|
||||
setTarget(originalAttackTarget);
|
||||
|
||||
final int combinedCollision = collision + originalAttackTarget.getTemplate().getCollisionRadius();
|
||||
|
||||
if (!npc.isMovementDisabled() && (Rnd.nextInt(100) <= 3))
|
||||
{
|
||||
for (L2Attackable nearby : L2World.getInstance().getVisibleObjects(npc, L2Attackable.class))
|
||||
{
|
||||
if (npc.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 (!npc.isInsideRadius(newX, newY, 0, collision, false, false))
|
||||
{
|
||||
final int newZ = npc.getZ() + 30;
|
||||
if (GeoData.getInstance().canMove(npc.getX(), npc.getY(), npc.getZ(), newX, newY, newZ, npc.getInstanceWorld()))
|
||||
{
|
||||
moveTo(newX, newY, newZ);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dodge if its needed
|
||||
if (!npc.isMovementDisabled() && (npc.getTemplate().getDodge() > 0))
|
||||
{
|
||||
if (Rnd.get(100) <= npc.getTemplate().getDodge())
|
||||
{
|
||||
final double distance2 = npc.calculateDistance(originalAttackTarget, false, true);
|
||||
if (Math.sqrt(distance2) <= (60 + combinedCollision))
|
||||
{
|
||||
int posX = npc.getX();
|
||||
int posY = npc.getY();
|
||||
final int posZ = npc.getZ() + 30;
|
||||
|
||||
if (originalAttackTarget.getX() < posX)
|
||||
{
|
||||
posX = posX + 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
posX = posX - 300;
|
||||
}
|
||||
|
||||
if (originalAttackTarget.getY() < posY)
|
||||
{
|
||||
posY = posY + 300;
|
||||
}
|
||||
else
|
||||
{
|
||||
posY = posY - 300;
|
||||
}
|
||||
|
||||
if (GeoData.getInstance().canMove(npc.getX(), npc.getY(), npc.getZ(), posX, posY, posZ, npc.getInstanceWorld()))
|
||||
{
|
||||
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(posX, posY, posZ, 0));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final double dist = npc.calculateDistance(originalAttackTarget, false, false);
|
||||
final int dist2 = (int) dist - collision;
|
||||
int range = npc.getPhysicalAttackRange() + combinedCollision;
|
||||
if (originalAttackTarget.isMoving())
|
||||
{
|
||||
range = range + 50;
|
||||
if (npc.isMoving())
|
||||
{
|
||||
range = range + 50;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dist2 > range) || !GeoData.getInstance().canSeeTarget(npc, originalAttackTarget))
|
||||
{
|
||||
if (originalAttackTarget.isMoving())
|
||||
{
|
||||
range -= 100;
|
||||
}
|
||||
if (range < 5)
|
||||
{
|
||||
range = 5;
|
||||
}
|
||||
moveToPawn(originalAttackTarget, range);
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack(originalAttackTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void thinkCast()
|
||||
{
|
||||
final L2Object target = _skill.getTarget(_actor, _forceUse, _dontMove, false);
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_actor.doCast(_skill, _item, _forceUse, _dontMove);
|
||||
}
|
||||
}
|
@ -1,75 +1,75 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2AirShipInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.ExMoveToLocationAirShip;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.ExStopMoveAirShip;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public class L2AirShipAI extends L2VehicleAI
|
||||
{
|
||||
public L2AirShipAI(L2AirShipInstance creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (!_actor.isMovementDisabled())
|
||||
{
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new ExMoveToLocationAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientStopMoving(Location loc)
|
||||
{
|
||||
if (_actor.isMoving())
|
||||
{
|
||||
_actor.stopMove(loc);
|
||||
}
|
||||
|
||||
if (_clientMoving || (loc != null))
|
||||
{
|
||||
_clientMoving = false;
|
||||
_actor.broadcastPacket(new ExStopMoveAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeStateToPlayer(L2PcInstance player)
|
||||
{
|
||||
if (_clientMoving)
|
||||
{
|
||||
player.sendPacket(new ExMoveToLocationAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2AirShipInstance getActor()
|
||||
{
|
||||
return (L2AirShipInstance) _actor;
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2AirShipInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.ExMoveToLocationAirShip;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.ExStopMoveAirShip;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public class L2AirShipAI extends L2VehicleAI
|
||||
{
|
||||
public L2AirShipAI(L2AirShipInstance airShip)
|
||||
{
|
||||
super(airShip);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (!_actor.isMovementDisabled())
|
||||
{
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new ExMoveToLocationAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientStopMoving(Location loc)
|
||||
{
|
||||
if (_actor.isMoving())
|
||||
{
|
||||
_actor.stopMove(loc);
|
||||
}
|
||||
|
||||
if (_clientMoving || (loc != null))
|
||||
{
|
||||
_clientMoving = false;
|
||||
_actor.broadcastPacket(new ExStopMoveAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeStateToPlayer(L2PcInstance player)
|
||||
{
|
||||
if (_clientMoving)
|
||||
{
|
||||
player.sendPacket(new ExMoveToLocationAirShip(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2AirShipInstance getActor()
|
||||
{
|
||||
return (L2AirShipInstance) _actor;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,84 +1,82 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2BoatInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleDeparture;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleInfo;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleStarted;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public class L2BoatAI extends L2VehicleAI
|
||||
{
|
||||
public L2BoatAI(L2BoatInstance creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (_actor.isMovementDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_clientMoving)
|
||||
{
|
||||
_actor.broadcastPacket(new VehicleStarted(getActor(), 1));
|
||||
}
|
||||
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new VehicleDeparture(getActor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientStopMoving(Location loc)
|
||||
{
|
||||
if (_actor.isMoving())
|
||||
{
|
||||
_actor.stopMove(loc);
|
||||
}
|
||||
|
||||
if (_clientMoving || (loc != null))
|
||||
{
|
||||
_clientMoving = false;
|
||||
_actor.broadcastPacket(new VehicleStarted(getActor(), 0));
|
||||
_actor.broadcastPacket(new VehicleInfo(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeStateToPlayer(L2PcInstance player)
|
||||
{
|
||||
if (_clientMoving)
|
||||
{
|
||||
player.sendPacket(new VehicleDeparture(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2BoatInstance getActor()
|
||||
{
|
||||
return (L2BoatInstance) _actor;
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2BoatInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleDeparture;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleInfo;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.VehicleStarted;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public class L2BoatAI extends L2VehicleAI
|
||||
{
|
||||
public L2BoatAI(L2BoatInstance boat)
|
||||
{
|
||||
super(boat);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (!_actor.isMovementDisabled())
|
||||
{
|
||||
if (!_clientMoving)
|
||||
{
|
||||
_actor.broadcastPacket(new VehicleStarted(getActor(), 1));
|
||||
}
|
||||
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new VehicleDeparture(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clientStopMoving(Location loc)
|
||||
{
|
||||
if (_actor.isMoving())
|
||||
{
|
||||
_actor.stopMove(loc);
|
||||
}
|
||||
|
||||
if (_clientMoving || (loc != null))
|
||||
{
|
||||
_clientMoving = false;
|
||||
_actor.broadcastPacket(new VehicleStarted(getActor(), 0));
|
||||
_actor.broadcastPacket(new VehicleInfo(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeStateToPlayer(L2PcInstance player)
|
||||
{
|
||||
if (_clientMoving)
|
||||
{
|
||||
player.sendPacket(new VehicleDeparture(getActor()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2BoatInstance getActor()
|
||||
{
|
||||
return (L2BoatInstance) _actor;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,176 +1,168 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2DefenderInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* @author mkizub
|
||||
*/
|
||||
public class L2DoorAI extends L2CharacterAI
|
||||
{
|
||||
public L2DoorAI(L2DoorInstance creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionIdle()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionRest()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionMoveTo(Location destination)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionFollow(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionPickUp(L2Object item)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionInteract(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
ThreadPoolManager.getInstance().executeGeneral(new onEventAttackedDoorTask((L2DoorInstance) _actor, attacker));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAggression(L2Character target, int aggro)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtStunned(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtSleeping(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtRooted(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtReadyToAct()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtUserCmd(Object arg0, Object arg1)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrived()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrivedRevalidate()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrivedBlocked(Location blocked_at_loc)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtForgetObject(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtDead()
|
||||
{
|
||||
}
|
||||
|
||||
private class onEventAttackedDoorTask implements Runnable
|
||||
{
|
||||
private final L2DoorInstance _door;
|
||||
private final L2Character _attacker;
|
||||
|
||||
public onEventAttackedDoorTask(L2DoorInstance door, L2Character attacker)
|
||||
{
|
||||
_door = door;
|
||||
_attacker = attacker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
for (L2DefenderInstance guard : _door.getKnownDefenders())
|
||||
{
|
||||
if (_actor.isInsideRadius(guard, guard.getTemplate().getClanHelpRange(), false, true) && (Math.abs(_attacker.getZ() - guard.getZ()) < 200))
|
||||
{
|
||||
guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.L2World;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2DefenderInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
|
||||
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* @author mkizub
|
||||
*/
|
||||
public class L2DoorAI extends L2CharacterAI
|
||||
{
|
||||
public L2DoorAI(L2DoorInstance door)
|
||||
{
|
||||
super(door);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionIdle()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionRest()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionMoveTo(Location destination)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionFollow(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionPickUp(L2Object item)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionInteract(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
ThreadPoolManager.getInstance().executeGeneral(new onEventAttackedDoorTask((L2DoorInstance) _actor, attacker));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAggression(L2Character target, int aggro)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtActionBlocked(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtRooted(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtReadyToAct()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrived()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrivedRevalidate()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtArrivedBlocked(Location blocked_at_loc)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtForgetObject(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtDead()
|
||||
{
|
||||
}
|
||||
|
||||
private class onEventAttackedDoorTask implements Runnable
|
||||
{
|
||||
private final L2DoorInstance _door;
|
||||
private final L2Character _attacker;
|
||||
|
||||
public onEventAttackedDoorTask(L2DoorInstance door, L2Character attacker)
|
||||
{
|
||||
_door = door;
|
||||
_attacker = attacker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
L2World.getInstance().forEachVisibleObject(_door, L2DefenderInstance.class, guard ->
|
||||
{
|
||||
if (_actor.isInsideRadius(guard, guard.getTemplate().getClanHelpRange(), true, true))
|
||||
{
|
||||
guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,119 +1,113 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Playable;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.zone.ZoneId;
|
||||
import com.l2jmobius.gameserver.network.SystemMessageId;
|
||||
|
||||
/**
|
||||
* This class manages AI of L2Playable.<br>
|
||||
* L2PlayableAI :
|
||||
* <li>L2SummonAI</li>
|
||||
* <li>L2PlayerAI</li>
|
||||
* @author JIV
|
||||
*/
|
||||
public abstract class L2PlayableAI extends L2CharacterAI
|
||||
{
|
||||
/**
|
||||
* @param creature the creature
|
||||
*/
|
||||
public L2PlayableAI(L2Playable creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
if (target instanceof L2Playable)
|
||||
{
|
||||
if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If attacker have karma and have level >= 10 than his target and target have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isProtectionBlessingAffected() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If target have karma and have level >= 10 than his target and actor have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.onIntentionAttack(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target)
|
||||
{
|
||||
if ((target instanceof L2Playable) && skill.isBad())
|
||||
{
|
||||
if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If attacker have karma and have level >= 10 than his target and target have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isProtectionBlessingAffected() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If target have karma and have level >= 10 than his target and actor have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.getActingPlayer().isCursedWeaponEquipped() && ((_actor.getActingPlayer().getLevel() <= 20) || (target.getActingPlayer().getLevel() <= 20)))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onIntentionCast(skill, target);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Playable;
|
||||
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.zone.ZoneId;
|
||||
import com.l2jmobius.gameserver.network.SystemMessageId;
|
||||
|
||||
/**
|
||||
* This class manages AI of L2Playable.<br>
|
||||
* L2PlayableAI :
|
||||
* <li>L2SummonAI</li>
|
||||
* <li>L2PlayerAI</li>
|
||||
* @author JIV
|
||||
*/
|
||||
public abstract class L2PlayableAI extends L2CharacterAI
|
||||
{
|
||||
public L2PlayableAI(L2Playable playable)
|
||||
{
|
||||
super(playable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
if (target instanceof L2Playable)
|
||||
{
|
||||
if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getReputation() < 0) && !(target.isInsideZone(ZoneId.PVP)))
|
||||
{
|
||||
// If attacker have karma and have level >= 10 than his target and target have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isProtectionBlessingAffected() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getReputation() < 0) && !(target.isInsideZone(ZoneId.PVP)))
|
||||
{
|
||||
// If target have karma and have level >= 10 than his target and actor have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onIntentionAttack(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
|
||||
{
|
||||
if ((target.isPlayable()) && skill.isBad())
|
||||
{
|
||||
if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If attacker have karma and have level >= 10 than his target and target have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.getActingPlayer().isProtectionBlessingAffected() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getReputation() < 0) && !target.isInsideZone(ZoneId.PVP))
|
||||
{
|
||||
// If target have karma and have level >= 10 than his target and actor have
|
||||
// Newbie Protection Buff,
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.getActingPlayer().isCursedWeaponEquipped() && ((_actor.getActingPlayer().getLevel() <= 20) || (target.getActingPlayer().getLevel() <= 20)))
|
||||
{
|
||||
_actor.getActingPlayer().sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onIntentionCast(skill, target, item, forceUse, dontMove);
|
||||
}
|
||||
}
|
||||
|
@ -1,354 +1,378 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
|
||||
|
||||
import com.l2jmobius.gameserver.enums.DuelState;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.skills.targets.L2TargetType;
|
||||
import com.l2jmobius.gameserver.network.SystemMessageId;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
|
||||
|
||||
public class L2PlayerAI extends L2PlayableAI
|
||||
{
|
||||
private boolean _thinking; // to prevent recursive thinking
|
||||
|
||||
private IntentionCommand _nextIntention = null;
|
||||
|
||||
public L2PlayerAI(L2PcInstance creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1)
|
||||
{
|
||||
_nextIntention = new IntentionCommand(intention, arg0, arg1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntentionCommand getNextIntention()
|
||||
{
|
||||
return _nextIntention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.
|
||||
* @param intention The new Intention to set to the AI
|
||||
* @param arg0 The first parameter of the Intention
|
||||
* @param arg1 The second parameter of the Intention
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
|
||||
{
|
||||
// Forget next if it's not cast or it's cast and skill is toggle.
|
||||
if ((intention != AI_INTENTION_CAST) || ((arg0 != null) && !((Skill) arg0).isToggle()))
|
||||
{
|
||||
_nextIntention = null;
|
||||
super.changeIntention(intention, arg0, arg1);
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if next intention is same as current one.
|
||||
if ((intention == _intention) && (arg0 == _intentionArg0) && (arg1 == _intentionArg1))
|
||||
{
|
||||
super.changeIntention(intention, arg0, arg1);
|
||||
return;
|
||||
}
|
||||
|
||||
// save current intention so it can be used after cast
|
||||
saveNextIntention(_intention, _intentionArg0, _intentionArg1);
|
||||
super.changeIntention(intention, arg0, arg1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch actions corresponding to the Event ReadyToAct.<br>
|
||||
* <B><U> Actions</U> :</B>
|
||||
* <ul>
|
||||
* <li>Launch actions corresponding to the Event Think</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtReadyToAct()
|
||||
{
|
||||
// Launch actions corresponding to the Event Think
|
||||
if (_nextIntention != null)
|
||||
{
|
||||
setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
|
||||
_nextIntention = null;
|
||||
}
|
||||
super.onEvtReadyToAct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch actions corresponding to the Event Cancel.<br>
|
||||
* <B><U> Actions</U> :</B>
|
||||
* <ul>
|
||||
* <li>Stop an AI Follow Task</li>
|
||||
* <li>Launch actions corresponding to the Event Think</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
_nextIntention = null;
|
||||
super.onEvtCancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the casting of a skill. This method overrides L2CharacterAI method.<br>
|
||||
* <B>What it does:</B><br>
|
||||
* Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player.
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_CAST)
|
||||
{
|
||||
// run interrupted or next intention
|
||||
if (_nextIntention != null)
|
||||
{
|
||||
if (_nextIntention._crtlIntention != AI_INTENTION_CAST)
|
||||
{
|
||||
setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// set intention to idle if skill doesn't change intention.
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionRest()
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_REST)
|
||||
{
|
||||
return;
|
||||
}
|
||||
changeIntention(AI_INTENTION_REST, null, null);
|
||||
setTarget(null);
|
||||
if (getAttackTarget() != null)
|
||||
{
|
||||
setAttackTarget(null);
|
||||
}
|
||||
clientStopMoving(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<br>
|
||||
* <B><U> Actions</U> : </B>
|
||||
* <ul>
|
||||
* <li>Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)</li>
|
||||
* <li>Set the Intention of this AI to AI_INTENTION_MOVE_TO</li>
|
||||
* <li>Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onIntentionMoveTo(Location loc)
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_REST)
|
||||
{
|
||||
// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
if (_actor.getActingPlayer().getDuelState() == DuelState.DEAD)
|
||||
{
|
||||
clientActionFailed();
|
||||
_actor.getActingPlayer().sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_CANNOT_MOVE_WHILE_FROZEN_PLEASE_WAIT));
|
||||
return;
|
||||
}
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow())
|
||||
{
|
||||
clientActionFailed();
|
||||
saveNextIntention(AI_INTENTION_MOVE_TO, loc, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
|
||||
changeIntention(AI_INTENTION_MOVE_TO, loc, null);
|
||||
|
||||
// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
|
||||
clientStopAutoAttack();
|
||||
|
||||
// Abort the attack of the L2Character and send Server->Client ActionFailed packet
|
||||
_actor.abortAttack();
|
||||
|
||||
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
|
||||
moveTo(loc.getX(), loc.getY(), loc.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientNotifyDead()
|
||||
{
|
||||
_clientMovingToPawnOffset = 0;
|
||||
_clientMoving = false;
|
||||
|
||||
super.clientNotifyDead();
|
||||
}
|
||||
|
||||
private void thinkAttack()
|
||||
{
|
||||
final L2Character target = getAttackTarget();
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (checkTargetLostOrDead(target))
|
||||
{
|
||||
// Notify the target
|
||||
setAttackTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(target);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
{
|
||||
final L2Character target = getCastTarget();
|
||||
if ((_skill.getTargetType() == L2TargetType.GROUND) && (_actor instanceof L2PcInstance))
|
||||
{
|
||||
if (maybeMoveToPosition(((L2PcInstance) _actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
if (_skill.isBad() && (getAttackTarget() != null))
|
||||
{
|
||||
// Notify the target
|
||||
setCastTarget(null);
|
||||
}
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
if ((target != null) && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
_actor.setIsCastingNow(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_skill.getHitTime() > 50) && !_skill.isSimultaneousCast())
|
||||
{
|
||||
clientStopMoving(null);
|
||||
}
|
||||
|
||||
_actor.doCast(_skill);
|
||||
}
|
||||
|
||||
private void thinkPickUp()
|
||||
{
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target) || maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
_actor.getActingPlayer().doPickupItem(target);
|
||||
}
|
||||
|
||||
private void thinkInteract()
|
||||
{
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target) || maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(target instanceof L2StaticObjectInstance))
|
||||
{
|
||||
_actor.getActingPlayer().doInteract((L2Character) target);
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
if (_thinking && (getIntention() != AI_INTENTION_CAST))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_thinking = true;
|
||||
try
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_ATTACK)
|
||||
{
|
||||
thinkAttack();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_CAST)
|
||||
{
|
||||
thinkCast();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_PICK_UP)
|
||||
{
|
||||
thinkPickUp();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_INTERACT)
|
||||
{
|
||||
thinkInteract();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thinking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2StaticObjectInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.skills.targets.TargetType;
|
||||
|
||||
public class L2PlayerAI extends L2PlayableAI
|
||||
{
|
||||
private boolean _thinking; // to prevent recursive thinking
|
||||
|
||||
IntentionCommand _nextIntention = null;
|
||||
|
||||
public L2PlayerAI(L2PcInstance player)
|
||||
{
|
||||
super(player);
|
||||
}
|
||||
|
||||
void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1)
|
||||
{
|
||||
_nextIntention = new IntentionCommand(intention, arg0, arg1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntentionCommand getNextIntention()
|
||||
{
|
||||
return _nextIntention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.
|
||||
* @param intention The new Intention to set to the AI
|
||||
* @param args The first parameter of the Intention
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void changeIntention(CtrlIntention intention, Object... args)
|
||||
{
|
||||
final Object localArg0 = args.length > 0 ? args[0] : null;
|
||||
final Object localArg1 = args.length > 1 ? args[1] : null;
|
||||
|
||||
final Object globalArg0 = (_intentionArgs != null) && (_intentionArgs.length > 0) ? _intentionArgs[0] : null;
|
||||
final Object globalArg1 = (_intentionArgs != null) && (_intentionArgs.length > 1) ? _intentionArgs[1] : null;
|
||||
|
||||
// do nothing unless CAST intention
|
||||
// however, forget interrupted actions when starting to use an offensive skill
|
||||
if ((intention != AI_INTENTION_CAST) || ((Skill) args[0]).isBad())
|
||||
{
|
||||
_nextIntention = null;
|
||||
super.changeIntention(intention, args);
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if next intention is same as current one.
|
||||
if ((intention == _intention) && (globalArg0 == localArg0) && (globalArg1 == localArg1))
|
||||
{
|
||||
super.changeIntention(intention, args);
|
||||
return;
|
||||
}
|
||||
|
||||
// save current intention so it can be used after cast
|
||||
saveNextIntention(_intention, globalArg0, globalArg1);
|
||||
super.changeIntention(intention, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch actions corresponding to the Event ReadyToAct.<br>
|
||||
* <B><U> Actions</U> :</B>
|
||||
* <ul>
|
||||
* <li>Launch actions corresponding to the Event Think</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtReadyToAct()
|
||||
{
|
||||
// Launch actions corresponding to the Event Think
|
||||
if (_nextIntention != null)
|
||||
{
|
||||
setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
|
||||
_nextIntention = null;
|
||||
}
|
||||
super.onEvtReadyToAct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch actions corresponding to the Event Cancel.<br>
|
||||
* <B><U> Actions</U> :</B>
|
||||
* <ul>
|
||||
* <li>Stop an AI Follow Task</li>
|
||||
* <li>Launch actions corresponding to the Event Think</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
_nextIntention = null;
|
||||
super.onEvtCancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the casting of a skill. This method overrides L2CharacterAI method.<br>
|
||||
* <B>What it does:</B><br>
|
||||
* Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player.
|
||||
*/
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_CAST)
|
||||
{
|
||||
// run interrupted or next intention
|
||||
|
||||
final IntentionCommand nextIntention = _nextIntention;
|
||||
if (nextIntention != null)
|
||||
{
|
||||
if (nextIntention._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
|
||||
{
|
||||
setIntention(nextIntention._crtlIntention, nextIntention._arg0, nextIntention._arg1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// set intention to idle if skill doesn't change intention.
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
super.onEvtAttacked(attacker);
|
||||
|
||||
// Summons in defending mode defend its master when attacked.
|
||||
if (_actor.getActingPlayer().hasServitors())
|
||||
{
|
||||
_actor.getActingPlayer().getServitors().values().stream().filter(summon -> ((L2SummonAI) summon.getAI()).isDefending()).forEach(summon -> ((L2SummonAI) summon.getAI()).defendAttack(attacker));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtEvaded(L2Character attacker)
|
||||
{
|
||||
super.onEvtEvaded(attacker);
|
||||
|
||||
// Summons in defending mode defend its master when attacked.
|
||||
if (_actor.getActingPlayer().hasServitors())
|
||||
{
|
||||
_actor.getActingPlayer().getServitors().values().stream().filter(summon -> ((L2SummonAI) summon.getAI()).isDefending()).forEach(summon -> ((L2SummonAI) summon.getAI()).defendAttack(attacker));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionRest()
|
||||
{
|
||||
if (getIntention() != AI_INTENTION_REST)
|
||||
{
|
||||
changeIntention(AI_INTENTION_REST);
|
||||
setTarget(null);
|
||||
clientStopMoving(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<br>
|
||||
* <B><U> Actions</U> : </B>
|
||||
* <ul>
|
||||
* <li>Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)</li>
|
||||
* <li>Set the Intention of this AI to AI_INTENTION_MOVE_TO</li>
|
||||
* <li>Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
protected void onIntentionMoveTo(Location loc)
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_REST)
|
||||
{
|
||||
// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
|
||||
clientActionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow())
|
||||
{
|
||||
clientActionFailed();
|
||||
saveNextIntention(AI_INTENTION_MOVE_TO, loc, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
|
||||
changeIntention(AI_INTENTION_MOVE_TO, loc);
|
||||
|
||||
// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
|
||||
clientStopAutoAttack();
|
||||
|
||||
// Abort the attack of the L2Character and send Server->Client ActionFailed packet
|
||||
_actor.abortAttack();
|
||||
|
||||
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
|
||||
moveTo(loc.getX(), loc.getY(), loc.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientNotifyDead()
|
||||
{
|
||||
_clientMovingToPawnOffset = 0;
|
||||
_clientMoving = false;
|
||||
|
||||
super.clientNotifyDead();
|
||||
}
|
||||
|
||||
private void thinkAttack()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
if ((target == null) || !target.isCharacter())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (checkTargetLostOrDead((L2Character) target))
|
||||
{
|
||||
// Notify the target
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_actor.doAttack((L2Character) target);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
{
|
||||
final L2Object target = _skill.getTarget(_actor, _forceUse, _dontMove, false);
|
||||
if ((_skill.getTargetType() == TargetType.GROUND) && (_actor instanceof L2PcInstance))
|
||||
{
|
||||
if (maybeMoveToPosition(((L2PcInstance) _actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
if (_skill.isBad() && (target != null))
|
||||
{
|
||||
// Notify the target
|
||||
setTarget(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((target != null) && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_actor.doCast(_skill, _item, _forceUse, _dontMove);
|
||||
}
|
||||
|
||||
private void thinkPickUp()
|
||||
{
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
getActor().doPickupItem(target);
|
||||
}
|
||||
|
||||
private void thinkInteract()
|
||||
{
|
||||
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(target instanceof L2StaticObjectInstance))
|
||||
{
|
||||
getActor().doInteract((L2Character) target);
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
if (_thinking && (getIntention() != AI_INTENTION_CAST))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_thinking = true;
|
||||
try
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_ATTACK)
|
||||
{
|
||||
thinkAttack();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_CAST)
|
||||
{
|
||||
thinkCast();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_PICK_UP)
|
||||
{
|
||||
thinkPickUp();
|
||||
}
|
||||
else if (getIntention() == AI_INTENTION_INTERACT)
|
||||
{
|
||||
thinkInteract();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2PcInstance getActor()
|
||||
{
|
||||
return (L2PcInstance) super.getActor();
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +1,48 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2ShuttleInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.shuttle.ExShuttleMove;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class L2ShuttleAI extends L2VehicleAI
|
||||
{
|
||||
public L2ShuttleAI(L2ShuttleInstance actor)
|
||||
{
|
||||
super(actor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (_actor.isMovementDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new ExShuttleMove(getActor(), x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2ShuttleInstance getActor()
|
||||
{
|
||||
return (L2ShuttleInstance) _actor;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2ShuttleInstance;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.shuttle.ExShuttleMove;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class L2ShuttleAI extends L2VehicleAI
|
||||
{
|
||||
public L2ShuttleAI(L2ShuttleInstance shuttle)
|
||||
{
|
||||
super(shuttle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(int x, int y, int z)
|
||||
{
|
||||
if (!_actor.isMovementDisabled())
|
||||
{
|
||||
_clientMoving = true;
|
||||
_actor.moveToLocation(x, y, z, 0);
|
||||
_actor.broadcastPacket(new ExShuttleMove(getActor(), x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2ShuttleInstance getActor()
|
||||
{
|
||||
return (L2ShuttleInstance) _actor;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,55 +1,51 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2DefenderInstance;
|
||||
|
||||
/**
|
||||
* @author BiggBoss
|
||||
*/
|
||||
public final class L2SpecialSiegeGuardAI extends L2SiegeGuardAI
|
||||
{
|
||||
private final List<Integer> _allied = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param creature
|
||||
*/
|
||||
public L2SpecialSiegeGuardAI(L2DefenderInstance creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
public List<Integer> getAlly()
|
||||
{
|
||||
return _allied;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoAttackCondition(L2Character target)
|
||||
{
|
||||
if (_allied.contains(target.getObjectId()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.autoAttackCondition(target);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
|
||||
/**
|
||||
* @author BiggBoss
|
||||
*/
|
||||
public final class L2SpecialSiegeGuardAI extends L2SiegeGuardAI
|
||||
{
|
||||
private final List<Integer> _allied = new ArrayList<>();
|
||||
|
||||
public L2SpecialSiegeGuardAI(L2Character creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
public List<Integer> getAlly()
|
||||
{
|
||||
return _allied;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoAttackCondition(L2Character target)
|
||||
{
|
||||
if (_allied.contains(target.getObjectId()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.autoAttackCondition(target);
|
||||
}
|
||||
}
|
||||
|
@ -1,317 +1,384 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
import com.l2jmobius.gameserver.GeoData;
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Summon;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.pathfinding.PathFinding;
|
||||
import com.l2jmobius.util.Rnd;
|
||||
|
||||
public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
{
|
||||
private static final int AVOID_RADIUS = 70;
|
||||
|
||||
private volatile boolean _thinking; // to prevent recursive thinking
|
||||
private volatile boolean _startFollow = ((L2Summon) _actor).getFollowStatus();
|
||||
private L2Character _lastAttack = null;
|
||||
|
||||
private volatile boolean _startAvoid = false;
|
||||
private Future<?> _avoidTask = null;
|
||||
|
||||
public L2SummonAI(L2Summon creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
if ((Config.PATHFINDING > 0) && (PathFinding.getInstance().findPath(_actor.getX(), _actor.getY(), _actor.getZ(), target.getX(), target.getY(), target.getZ(), _actor.getInstanceId(), true) == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
super.onIntentionAttack(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionIdle()
|
||||
{
|
||||
stopFollow();
|
||||
_startFollow = false;
|
||||
onIntentionActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
if (_startFollow)
|
||||
{
|
||||
setIntention(AI_INTENTION_FOLLOW, ((L2Summon) _actor).getOwner());
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onIntentionActive();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
|
||||
{
|
||||
switch (intention)
|
||||
{
|
||||
case AI_INTENTION_ACTIVE:
|
||||
case AI_INTENTION_FOLLOW:
|
||||
{
|
||||
startAvoidTask();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
stopAvoidTask();
|
||||
}
|
||||
}
|
||||
|
||||
super.changeIntention(intention, arg0, arg1);
|
||||
}
|
||||
|
||||
private void thinkAttack()
|
||||
{
|
||||
if (checkTargetLostOrDead(getAttackTarget()))
|
||||
{
|
||||
setAttackTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(getAttackTarget(), _actor.getPhysicalAttackRange()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(getAttackTarget());
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
{
|
||||
final L2Summon summon = (L2Summon) _actor;
|
||||
if (checkTargetLost(getCastTarget()))
|
||||
{
|
||||
setCastTarget(null);
|
||||
return;
|
||||
}
|
||||
final boolean val = _startFollow;
|
||||
if (maybeMoveToPawn(getCastTarget(), _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
summon.setFollowStatus(false);
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
_startFollow = val;
|
||||
_actor.doCast(_skill);
|
||||
}
|
||||
|
||||
private void thinkPickUp()
|
||||
{
|
||||
if (checkTargetLost(getTarget()) || maybeMoveToPawn(getTarget(), 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
((L2Summon) _actor).doPickupItem(getTarget());
|
||||
}
|
||||
|
||||
private void thinkInteract()
|
||||
{
|
||||
if (checkTargetLost(getTarget()) || maybeMoveToPawn(getTarget(), 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_thinking = true;
|
||||
try
|
||||
{
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ATTACK:
|
||||
{
|
||||
thinkAttack();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_CAST:
|
||||
{
|
||||
thinkCast();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_PICK_UP:
|
||||
{
|
||||
thinkPickUp();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_INTERACT:
|
||||
{
|
||||
thinkInteract();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
if (_lastAttack == null)
|
||||
{
|
||||
((L2Summon) _actor).setFollowStatus(_startFollow);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
|
||||
_lastAttack = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
super.onEvtAttacked(attacker);
|
||||
|
||||
avoidAttack(attacker);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtEvaded(L2Character attacker)
|
||||
{
|
||||
super.onEvtEvaded(attacker);
|
||||
|
||||
avoidAttack(attacker);
|
||||
}
|
||||
|
||||
private void avoidAttack(L2Character attacker)
|
||||
{
|
||||
// trying to avoid if summon near owner
|
||||
if ((((L2Summon) _actor).getOwner() != null) && (((L2Summon) _actor).getOwner() != attacker) && ((L2Summon) _actor).getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
|
||||
{
|
||||
_startAvoid = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (!_startAvoid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_startAvoid = false;
|
||||
if (_clientMoving || _actor.isDead() || _actor.isMovementDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final int ownerX = ((L2Summon) _actor).getOwner().getX();
|
||||
final int ownerY = ((L2Summon) _actor).getOwner().getY();
|
||||
final double angle = Math.toRadians(Rnd.get(-90, 90)) + Math.atan2(ownerY - _actor.getY(), ownerX - _actor.getX());
|
||||
final int targetX = ownerX + (int) (AVOID_RADIUS * Math.cos(angle));
|
||||
final int targetY = ownerY + (int) (AVOID_RADIUS * Math.sin(angle));
|
||||
if (GeoData.getInstance().canMove(_actor.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceId()))
|
||||
{
|
||||
moveTo(targetX, targetY, _actor.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyFollowStatusChange()
|
||||
{
|
||||
_startFollow = !_startFollow;
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ACTIVE:
|
||||
case AI_INTENTION_FOLLOW:
|
||||
case AI_INTENTION_IDLE:
|
||||
case AI_INTENTION_MOVE_TO:
|
||||
case AI_INTENTION_PICK_UP:
|
||||
{
|
||||
((L2Summon) _actor).setFollowStatus(_startFollow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartFollowController(boolean val)
|
||||
{
|
||||
_startFollow = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target)
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_ATTACK)
|
||||
{
|
||||
_lastAttack = getAttackTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastAttack = null;
|
||||
}
|
||||
super.onIntentionCast(skill, target);
|
||||
}
|
||||
|
||||
private void startAvoidTask()
|
||||
{
|
||||
if (_avoidTask == null)
|
||||
{
|
||||
_avoidTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 100, 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopAvoidTask()
|
||||
{
|
||||
if (_avoidTask != null)
|
||||
{
|
||||
_avoidTask.cancel(false);
|
||||
_avoidTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopAITask()
|
||||
{
|
||||
stopAvoidTask();
|
||||
super.stopAITask();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
|
||||
import static com.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import com.l2jmobius.commons.util.Rnd;
|
||||
import com.l2jmobius.gameserver.GeoData;
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Summon;
|
||||
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.model.skills.SkillCaster;
|
||||
|
||||
public class L2SummonAI extends L2PlayableAI implements Runnable
|
||||
{
|
||||
private static final int AVOID_RADIUS = 70;
|
||||
|
||||
private volatile boolean _thinking; // to prevent recursive thinking
|
||||
private volatile boolean _startFollow = ((L2Summon) _actor).getFollowStatus();
|
||||
private L2Character _lastAttack = null;
|
||||
|
||||
private volatile boolean _startAvoid;
|
||||
private volatile boolean _isDefending;
|
||||
private Future<?> _avoidTask = null;
|
||||
|
||||
public L2SummonAI(L2Summon summon)
|
||||
{
|
||||
super(summon);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionIdle()
|
||||
{
|
||||
stopFollow();
|
||||
_startFollow = false;
|
||||
onIntentionActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionActive()
|
||||
{
|
||||
final L2Summon summon = (L2Summon) _actor;
|
||||
if (_startFollow)
|
||||
{
|
||||
setIntention(AI_INTENTION_FOLLOW, summon.getOwner());
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onIntentionActive();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized void changeIntention(CtrlIntention intention, Object... args)
|
||||
{
|
||||
switch (intention)
|
||||
{
|
||||
case AI_INTENTION_ACTIVE:
|
||||
case AI_INTENTION_FOLLOW:
|
||||
{
|
||||
startAvoidTask();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
stopAvoidTask();
|
||||
}
|
||||
}
|
||||
|
||||
super.changeIntention(intention, args);
|
||||
}
|
||||
|
||||
private void thinkAttack()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
final L2Character attackTarget = (target != null) && target.isCharacter() ? (L2Character) target : null;
|
||||
|
||||
if (checkTargetLostOrDead(attackTarget))
|
||||
{
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(attackTarget, _actor.getPhysicalAttackRange()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
clientStopMoving(null);
|
||||
_actor.doAttack(attackTarget);
|
||||
}
|
||||
|
||||
private void thinkCast()
|
||||
{
|
||||
final L2Summon summon = (L2Summon) _actor;
|
||||
if (summon.isCastingNow(SkillCaster::isAnyNormalType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final L2Object target = _skill.getTarget(_actor, _forceUse, _dontMove, false);
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
setTarget(null);
|
||||
return;
|
||||
}
|
||||
final boolean val = _startFollow;
|
||||
if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
summon.setFollowStatus(false);
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
_startFollow = val;
|
||||
_actor.doCast(_skill, _item, _forceUse, _dontMove);
|
||||
}
|
||||
|
||||
private void thinkPickUp()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
getActor().doPickupItem(target);
|
||||
}
|
||||
|
||||
private void thinkInteract()
|
||||
{
|
||||
final L2Object target = getTarget();
|
||||
if (checkTargetLost(target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (maybeMoveToPawn(target, 36))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setIntention(AI_INTENTION_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtThink()
|
||||
{
|
||||
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_thinking = true;
|
||||
try
|
||||
{
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ATTACK:
|
||||
{
|
||||
thinkAttack();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_CAST:
|
||||
{
|
||||
thinkCast();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_PICK_UP:
|
||||
{
|
||||
thinkPickUp();
|
||||
break;
|
||||
}
|
||||
case AI_INTENTION_INTERACT:
|
||||
{
|
||||
thinkInteract();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_thinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
if (_lastAttack == null)
|
||||
{
|
||||
((L2Summon) _actor).setFollowStatus(_startFollow);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
|
||||
_lastAttack = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
super.onEvtAttacked(attacker);
|
||||
|
||||
if (isDefending())
|
||||
{
|
||||
defendAttack(attacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
avoidAttack(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtEvaded(L2Character attacker)
|
||||
{
|
||||
super.onEvtEvaded(attacker);
|
||||
|
||||
if (isDefending())
|
||||
{
|
||||
defendAttack(attacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
avoidAttack(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
private void avoidAttack(L2Character attacker)
|
||||
{
|
||||
// Don't move while casting. It breaks casting animation, but still casts the skill... looks so bugged.
|
||||
if (_actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final L2Character owner = getActor().getOwner();
|
||||
// trying to avoid if summon near owner
|
||||
if ((owner != null) && (owner != attacker) && owner.isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
|
||||
{
|
||||
_startAvoid = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void defendAttack(L2Character attacker)
|
||||
{
|
||||
// Cannot defend while attacking or casting.
|
||||
if (_actor.isAttackingNow() || _actor.isCastingNow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final L2Summon summon = getActor();
|
||||
if ((summon.getOwner() != null) && (summon.getOwner() != attacker) && !summon.isMoving() && summon.canAttack(attacker, false) && summon.getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
|
||||
{
|
||||
summon.doAttack(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (_startAvoid)
|
||||
{
|
||||
_startAvoid = false;
|
||||
|
||||
if (!_clientMoving && !_actor.isDead() && !_actor.isMovementDisabled() && (_actor.getMoveSpeed() > 0))
|
||||
{
|
||||
final int ownerX = ((L2Summon) _actor).getOwner().getX();
|
||||
final int ownerY = ((L2Summon) _actor).getOwner().getY();
|
||||
final double angle = Math.toRadians(Rnd.get(-90, 90)) + Math.atan2(ownerY - _actor.getY(), ownerX - _actor.getX());
|
||||
|
||||
final int targetX = ownerX + (int) (AVOID_RADIUS * Math.cos(angle));
|
||||
final int targetY = ownerY + (int) (AVOID_RADIUS * Math.sin(angle));
|
||||
if (GeoData.getInstance().canMove(_actor, targetX, targetY, _actor.getZ()))
|
||||
{
|
||||
moveTo(targetX, targetY, _actor.getZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyFollowStatusChange()
|
||||
{
|
||||
_startFollow = !_startFollow;
|
||||
switch (getIntention())
|
||||
{
|
||||
case AI_INTENTION_ACTIVE:
|
||||
case AI_INTENTION_FOLLOW:
|
||||
case AI_INTENTION_IDLE:
|
||||
case AI_INTENTION_MOVE_TO:
|
||||
case AI_INTENTION_PICK_UP:
|
||||
{
|
||||
((L2Summon) _actor).setFollowStatus(_startFollow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartFollowController(boolean val)
|
||||
{
|
||||
_startFollow = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
|
||||
{
|
||||
if (getIntention() == AI_INTENTION_ATTACK)
|
||||
{
|
||||
_lastAttack = (getTarget() != null) && getTarget().isCharacter() ? (L2Character) getTarget() : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastAttack = null;
|
||||
}
|
||||
super.onIntentionCast(skill, target, item, forceUse, dontMove);
|
||||
}
|
||||
|
||||
private void startAvoidTask()
|
||||
{
|
||||
if (_avoidTask == null)
|
||||
{
|
||||
_avoidTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 100, 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopAvoidTask()
|
||||
{
|
||||
if (_avoidTask != null)
|
||||
{
|
||||
_avoidTask.cancel(false);
|
||||
_avoidTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopAITask()
|
||||
{
|
||||
stopAvoidTask();
|
||||
super.stopAITask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2Summon getActor()
|
||||
{
|
||||
return (L2Summon) super.getActor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the summon is defending itself or master.
|
||||
*/
|
||||
public boolean isDefending()
|
||||
{
|
||||
return _isDefending;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isDefending set the summon to defend itself and master, or be passive and avoid while being attacked.
|
||||
*/
|
||||
public void setDefending(boolean isDefending)
|
||||
{
|
||||
_isDefending = isDefending;
|
||||
}
|
||||
}
|
||||
|
@ -1,127 +1,123 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Vehicle;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public abstract class L2VehicleAI extends L2CharacterAI
|
||||
{
|
||||
/**
|
||||
* Simple AI for vehicles
|
||||
* @param creature
|
||||
*/
|
||||
public L2VehicleAI(L2Vehicle creature)
|
||||
{
|
||||
super(creature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionFollow(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionPickUp(L2Object item)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionInteract(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAggression(L2Character target, int aggro)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtStunned(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtSleeping(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtRooted(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtForgetObject(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtDead()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFakeDeath()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientActionFailed()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveToPawn(L2Object pawn, int offset)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientStoppedMoving()
|
||||
{
|
||||
}
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai;
|
||||
|
||||
import com.l2jmobius.gameserver.model.L2Object;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Vehicle;
|
||||
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
|
||||
/**
|
||||
* @author DS
|
||||
*/
|
||||
public abstract class L2VehicleAI extends L2CharacterAI
|
||||
{
|
||||
/**
|
||||
* Simple AI for vehicles
|
||||
* @param vehicle
|
||||
*/
|
||||
public L2VehicleAI(L2Vehicle vehicle)
|
||||
{
|
||||
super(vehicle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionAttack(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionCast(Skill skill, L2Object target, L2ItemInstance item, boolean forceUse, boolean dontMove)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionFollow(L2Character target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionPickUp(L2Object item)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onIntentionInteract(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAttacked(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtAggression(L2Character target, int aggro)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtActionBlocked(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtRooted(L2Character attacker)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtForgetObject(L2Object object)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtCancel()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtDead()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFakeDeath()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEvtFinishCasting()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientActionFailed()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void moveToPawn(L2Object pawn, int offset)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clientStoppedMoving()
|
||||
{
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai.npc;
|
||||
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.ai.CtrlIntention;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2QuestGuardInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.util.Util;
|
||||
import com.l2jmobius.util.Rnd;
|
||||
|
||||
/**
|
||||
* @author Mobius
|
||||
*/
|
||||
public final class FighterAI implements Runnable
|
||||
{
|
||||
private L2PcInstance _player;
|
||||
private final L2QuestGuardInstance _guard;
|
||||
private int _followRange = 150;
|
||||
|
||||
public FighterAI(L2PcInstance player, L2QuestGuardInstance guard)
|
||||
{
|
||||
_player = player;
|
||||
_guard = guard;
|
||||
_guard.setIsRunning(true);
|
||||
if (_guard.getSpawn() != null)
|
||||
{
|
||||
_guard.setSpawn(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlayer(L2PcInstance player)
|
||||
{
|
||||
_player = player;
|
||||
}
|
||||
|
||||
public void setFollowRange(int range)
|
||||
{
|
||||
_followRange = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
// Schedule new task only when necessary.
|
||||
if ((_guard == null) || _guard.isDead() || (_player == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new FighterAI(_player, _guard), _guard.isInCombat() ? 1000 : 3000);
|
||||
|
||||
// Guard is occupied. Use skills logic.
|
||||
if (_guard.isInCombat())
|
||||
{
|
||||
if ((_guard.getTarget() != null) && _guard.getTarget().isMonster() && ((L2Character) _guard.getTarget()).isAlikeDead())
|
||||
{
|
||||
for (Skill skill : _guard.getSkills().values())
|
||||
{
|
||||
if (skill.isBad() && (skill.getCoolTime() <= 0) && !_guard.isCastingNow() && (_guard.calculateDistance(_guard.getTarget(), false, false) < skill.getCastRange()))
|
||||
{
|
||||
_guard.setHeading(Util.calculateHeadingFrom(_guard, _guard.getTarget()));
|
||||
skill.activateSkill(_guard, _guard.getTarget());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return; // Guard is occupied, no need to proceed.
|
||||
}
|
||||
|
||||
// Assist combat logic.
|
||||
if (_player.isInCombat() && (_player.getTarget() != null) && _player.getTarget().isMonster() && !_player.getTarget().isInvul() //
|
||||
&& ((L2Character) _player.getTarget()).isInCombat() && !((L2Character) _player.getTarget()).isAlikeDead())
|
||||
{
|
||||
if (_guard.calculateDistance(_player.getTarget(), false, false) > 50)
|
||||
{
|
||||
_guard.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _player.getTarget().getLocation());
|
||||
}
|
||||
else if (_guard.getTarget() != _player.getTarget())
|
||||
{
|
||||
_guard.addDamageHate((L2Character) _player.getTarget(), 0, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to kill nearby monsters logic.
|
||||
for (L2Character ch : _guard.getKnownList().getKnownCharacters())
|
||||
{
|
||||
if (ch.isMonster() && !ch.isInvul() && !ch.isAlikeDead())
|
||||
{
|
||||
_guard.addDamageHate(ch, 0, 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Out of combat follow logic.
|
||||
if (!_guard.isInCombat())
|
||||
{
|
||||
_guard.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location((_player.getLocation().getX() + Rnd.get(_followRange * -1, _followRange)), (_player.getLocation().getY() + Rnd.get(_followRange * -1, _followRange)), _player.getLocation().getZ()));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.ai.npc;
|
||||
|
||||
import com.l2jmobius.gameserver.ThreadPoolManager;
|
||||
import com.l2jmobius.gameserver.ai.CtrlIntention;
|
||||
import com.l2jmobius.gameserver.model.Location;
|
||||
import com.l2jmobius.gameserver.model.actor.L2Character;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2QuestGuardInstance;
|
||||
import com.l2jmobius.gameserver.model.skills.Skill;
|
||||
import com.l2jmobius.gameserver.util.Util;
|
||||
import com.l2jmobius.util.Rnd;
|
||||
|
||||
/**
|
||||
* @author Mobius
|
||||
*/
|
||||
public final class HealerAI implements Runnable
|
||||
{
|
||||
private L2PcInstance _player;
|
||||
private final L2QuestGuardInstance _guard;
|
||||
private int _followRange = 200;
|
||||
|
||||
public HealerAI(L2PcInstance player, L2QuestGuardInstance guard)
|
||||
{
|
||||
_player = player;
|
||||
_guard = guard;
|
||||
_guard.setIsRunning(true);
|
||||
if (_guard.getSpawn() != null)
|
||||
{
|
||||
_guard.setSpawn(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlayer(L2PcInstance player)
|
||||
{
|
||||
_player = player;
|
||||
}
|
||||
|
||||
public void setFollowRange(int range)
|
||||
{
|
||||
_followRange = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
// Schedule new task only when necessary.
|
||||
if ((_guard == null) || _guard.isDead() || (_player == null))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new HealerAI(_player, _guard), _guard.isInCombat() ? 1000 : 3000);
|
||||
|
||||
// Guard is occupied. Use skills logic.
|
||||
if (_guard.isInCombat())
|
||||
{
|
||||
L2PcInstance targetPlayer = null;
|
||||
for (L2Character ch : _guard.getKnownList().getKnownCharacters())
|
||||
{
|
||||
if (ch.isPlayer() && !ch.isAlikeDead())
|
||||
{
|
||||
targetPlayer = (L2PcInstance) ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (Skill skill : _guard.getSkills().values())
|
||||
{
|
||||
if ((targetPlayer != null) && !targetPlayer.isAlikeDead() //
|
||||
&& !skill.isBad() && !_guard.isCastingNow() && (_guard.calculateDistance(targetPlayer, false, false) < skill.getCastRange()))
|
||||
{
|
||||
_guard.setHeading(Util.calculateHeadingFrom(_guard, targetPlayer));
|
||||
_guard.setTarget(targetPlayer);
|
||||
skill.activateSkill(_guard, targetPlayer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return; // Guard is occupied, no need to proceed.
|
||||
}
|
||||
|
||||
// Assist combat logic.
|
||||
if (_player.isInCombat() && (_player.getTarget() != null) && _player.getTarget().isMonster() && !_player.getTarget().isInvul() //
|
||||
&& ((L2Character) _player.getTarget()).isInCombat() && !((L2Character) _player.getTarget()).isAlikeDead())
|
||||
{
|
||||
if (_guard.calculateDistance(_player.getTarget(), false, false) > 50)
|
||||
{
|
||||
_guard.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, _player.getTarget().getLocation());
|
||||
}
|
||||
else if (_guard.getTarget() != _player.getTarget())
|
||||
{
|
||||
_guard.addDamageHate((L2Character) _player.getTarget(), 0, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to kill nearby monsters logic.
|
||||
for (L2Character ch : _guard.getKnownList().getKnownCharacters())
|
||||
{
|
||||
if (ch.isMonster() && !ch.isInvul() && !ch.isAlikeDead())
|
||||
{
|
||||
_guard.addDamageHate(ch, 0, 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Out of combat follow logic.
|
||||
if (!_guard.isInCombat())
|
||||
{
|
||||
_guard.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location((_player.getLocation().getX() + Rnd.get(_followRange * -1, _followRange)), (_player.getLocation().getY() + Rnd.get(_followRange * -1, _followRange)), _player.getLocation().getZ()));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user