AbstractAI.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /*
  2. * Copyright (C) 2004-2015 L2J Server
  3. *
  4. * This file is part of L2J Server.
  5. *
  6. * L2J Server is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * L2J Server is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.l2jserver.gameserver.ai;
  20. import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
  21. import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
  22. import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
  23. import java.util.concurrent.Future;
  24. import org.slf4j.Logger;
  25. import org.slf4j.LoggerFactory;
  26. import com.l2jserver.gameserver.GameTimeController;
  27. import com.l2jserver.gameserver.ThreadPoolManager;
  28. import com.l2jserver.gameserver.model.L2Object;
  29. import com.l2jserver.gameserver.model.Location;
  30. import com.l2jserver.gameserver.model.actor.L2Character;
  31. import com.l2jserver.gameserver.model.actor.L2Summon;
  32. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  33. import com.l2jserver.gameserver.model.skills.Skill;
  34. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  35. import com.l2jserver.gameserver.network.serverpackets.AutoAttackStart;
  36. import com.l2jserver.gameserver.network.serverpackets.AutoAttackStop;
  37. import com.l2jserver.gameserver.network.serverpackets.Die;
  38. import com.l2jserver.gameserver.network.serverpackets.MoveToLocation;
  39. import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
  40. import com.l2jserver.gameserver.network.serverpackets.StopMove;
  41. import com.l2jserver.gameserver.network.serverpackets.StopRotation;
  42. import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
  43. /**
  44. * Mother class of all objects AI in the world.<br>
  45. * AbastractAI :<br>
  46. * <li>L2CharacterAI</li>
  47. */
  48. public abstract class AbstractAI implements Ctrl
  49. {
  50. protected static final Logger _log = LoggerFactory.getLogger(AbstractAI.class);
  51. private NextAction _nextAction;
  52. /**
  53. * @return the _nextAction
  54. */
  55. public NextAction getNextAction()
  56. {
  57. return _nextAction;
  58. }
  59. /**
  60. * @param nextAction the next action to set.
  61. */
  62. public void setNextAction(NextAction nextAction)
  63. {
  64. _nextAction = nextAction;
  65. }
  66. private class FollowTask implements Runnable
  67. {
  68. protected int _range = 70;
  69. public FollowTask()
  70. {
  71. }
  72. public FollowTask(int range)
  73. {
  74. _range = range;
  75. }
  76. @Override
  77. public void run()
  78. {
  79. try
  80. {
  81. if (_followTask == null)
  82. {
  83. return;
  84. }
  85. L2Character followTarget = _followTarget; // copy to prevent NPE
  86. if (followTarget == null)
  87. {
  88. if (_actor instanceof L2Summon)
  89. {
  90. ((L2Summon) _actor).setFollowStatus(false);
  91. }
  92. setIntention(AI_INTENTION_IDLE);
  93. return;
  94. }
  95. if (!_actor.isInsideRadius(followTarget, _range, true, false))
  96. {
  97. if (!_actor.isInsideRadius(followTarget, 3000, true, false))
  98. {
  99. // if the target is too far (maybe also teleported)
  100. if (_actor instanceof L2Summon)
  101. {
  102. ((L2Summon) _actor).setFollowStatus(false);
  103. }
  104. setIntention(AI_INTENTION_IDLE);
  105. return;
  106. }
  107. moveToPawn(followTarget, _range);
  108. }
  109. }
  110. catch (Exception e)
  111. {
  112. _log.warn("{}: There has been a problem running the follow task!", getClass().getSimpleName(), e);
  113. }
  114. }
  115. }
  116. /** The character that this AI manages */
  117. protected final L2Character _actor;
  118. /** Current long-term intention */
  119. protected CtrlIntention _intention = AI_INTENTION_IDLE;
  120. /** Current long-term intention parameter */
  121. protected Object _intentionArg0 = null;
  122. /** Current long-term intention parameter */
  123. protected Object _intentionArg1 = null;
  124. /** Flags about client's state, in order to know which messages to send */
  125. protected volatile boolean _clientMoving;
  126. /** Flags about client's state, in order to know which messages to send */
  127. protected volatile boolean _clientAutoAttacking;
  128. /** Flags about client's state, in order to know which messages to send */
  129. protected int _clientMovingToPawnOffset;
  130. /** Different targets this AI maintains */
  131. private L2Object _target;
  132. private L2Character _castTarget;
  133. protected L2Character _attackTarget;
  134. protected L2Character _followTarget;
  135. /** The skill we are currently casting by INTENTION_CAST */
  136. Skill _skill;
  137. /** Different internal state flags */
  138. private int _moveToPawnTimeout;
  139. protected Future<?> _followTask = null;
  140. private static final int FOLLOW_INTERVAL = 1000;
  141. private static final int ATTACK_FOLLOW_INTERVAL = 500;
  142. /**
  143. * Constructor of AbstractAI.
  144. * @param creature the creature
  145. */
  146. protected AbstractAI(L2Character creature)
  147. {
  148. _actor = creature;
  149. }
  150. /**
  151. * @return the L2Character managed by this Accessor AI.
  152. */
  153. @Override
  154. public L2Character getActor()
  155. {
  156. return _actor;
  157. }
  158. /**
  159. * @return the current Intention.
  160. */
  161. @Override
  162. public CtrlIntention getIntention()
  163. {
  164. return _intention;
  165. }
  166. protected void setCastTarget(L2Character target)
  167. {
  168. _castTarget = target;
  169. }
  170. /**
  171. * @return the current cast target.
  172. */
  173. public L2Character getCastTarget()
  174. {
  175. return _castTarget;
  176. }
  177. protected void setAttackTarget(L2Character target)
  178. {
  179. _attackTarget = target;
  180. }
  181. /**
  182. * @return current attack target.
  183. */
  184. @Override
  185. public L2Character getAttackTarget()
  186. {
  187. return _attackTarget;
  188. }
  189. /**
  190. * Set the Intention of this AbstractAI.<br>
  191. * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is USED by AI classes</B></FONT><B><U><br>
  192. * Overridden in </U> : </B><BR>
  193. * <B>L2AttackableAI</B> : Create an AI Task executed every 1s (if necessary)<BR>
  194. * <B>L2PlayerAI</B> : Stores the current AI intention parameters to later restore it if necessary.
  195. * @param intention The new Intention to set to the AI
  196. * @param arg0 The first parameter of the Intention
  197. * @param arg1 The second parameter of the Intention
  198. */
  199. synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
  200. {
  201. _intention = intention;
  202. _intentionArg0 = arg0;
  203. _intentionArg1 = arg1;
  204. }
  205. /**
  206. * Launch the L2CharacterAI onIntention method corresponding to the new Intention.<br>
  207. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT>
  208. * @param intention The new Intention to set to the AI
  209. */
  210. @Override
  211. public final void setIntention(CtrlIntention intention)
  212. {
  213. setIntention(intention, null, null);
  214. }
  215. /**
  216. * Launch the L2CharacterAI onIntention method corresponding to the new Intention.<br>
  217. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT>
  218. * @param intention The new Intention to set to the AI
  219. * @param arg0 The first parameter of the Intention (optional target)
  220. */
  221. @Override
  222. public final void setIntention(CtrlIntention intention, Object arg0)
  223. {
  224. setIntention(intention, arg0, null);
  225. }
  226. @Override
  227. public final void setIntention(CtrlIntention intention, Object arg0, Object arg1)
  228. {
  229. // Stop the follow mode if necessary
  230. if ((intention != AI_INTENTION_FOLLOW) && (intention != AI_INTENTION_ATTACK))
  231. {
  232. stopFollow();
  233. }
  234. // Launch the onIntention method of the L2CharacterAI corresponding to the new Intention
  235. switch (intention)
  236. {
  237. case AI_INTENTION_IDLE:
  238. onIntentionIdle();
  239. break;
  240. case AI_INTENTION_ACTIVE:
  241. onIntentionActive();
  242. break;
  243. case AI_INTENTION_REST:
  244. onIntentionRest();
  245. break;
  246. case AI_INTENTION_ATTACK:
  247. onIntentionAttack((L2Character) arg0);
  248. break;
  249. case AI_INTENTION_CAST:
  250. onIntentionCast((Skill) arg0, (L2Object) arg1);
  251. break;
  252. case AI_INTENTION_MOVE_TO:
  253. onIntentionMoveTo((Location) arg0);
  254. break;
  255. case AI_INTENTION_FOLLOW:
  256. onIntentionFollow((L2Character) arg0);
  257. break;
  258. case AI_INTENTION_PICK_UP:
  259. onIntentionPickUp((L2Object) arg0);
  260. break;
  261. case AI_INTENTION_INTERACT:
  262. onIntentionInteract((L2Object) arg0);
  263. break;
  264. }
  265. // If do move or follow intention drop next action.
  266. if ((_nextAction != null) && _nextAction.getIntentions().contains(intention))
  267. {
  268. _nextAction = null;
  269. }
  270. }
  271. /**
  272. * Launch the L2CharacterAI onEvt method corresponding to the Event.<br>
  273. * <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT>
  274. * @param evt The event whose the AI must be notified
  275. */
  276. @Override
  277. public final void notifyEvent(CtrlEvent evt)
  278. {
  279. notifyEvent(evt, null, null);
  280. }
  281. /**
  282. * Launch the L2CharacterAI onEvt method corresponding to the Event. <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT>
  283. * @param evt The event whose the AI must be notified
  284. * @param arg0 The first parameter of the Event (optional target)
  285. */
  286. @Override
  287. public final void notifyEvent(CtrlEvent evt, Object arg0)
  288. {
  289. notifyEvent(evt, arg0, null);
  290. }
  291. /**
  292. * Launch the L2CharacterAI onEvt method corresponding to the Event. <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT>
  293. * @param evt The event whose the AI must be notified
  294. */
  295. @Override
  296. public final void notifyEvent(CtrlEvent evt, Object... args)
  297. {
  298. if ((!_actor.isVisible() && !_actor.isTeleporting()) || !_actor.hasAI())
  299. {
  300. return;
  301. }
  302. switch (evt)
  303. {
  304. case EVT_THINK:
  305. onEvtThink();
  306. break;
  307. case EVT_ATTACKED:
  308. onEvtAttacked((L2Character) args[0]);
  309. break;
  310. case EVT_AGGRESSION:
  311. onEvtAggression((L2Character) args[0], ((Number) args[1]).intValue());
  312. break;
  313. case EVT_STUNNED:
  314. onEvtStunned((L2Character) args[0]);
  315. break;
  316. case EVT_PARALYZED:
  317. onEvtParalyzed((L2Character) args[0]);
  318. break;
  319. case EVT_SLEEPING:
  320. onEvtSleeping((L2Character) args[0]);
  321. break;
  322. case EVT_ROOTED:
  323. onEvtRooted((L2Character) args[0]);
  324. break;
  325. case EVT_CONFUSED:
  326. onEvtConfused((L2Character) args[0]);
  327. break;
  328. case EVT_MUTED:
  329. onEvtMuted((L2Character) args[0]);
  330. break;
  331. case EVT_EVADED:
  332. onEvtEvaded((L2Character) args[0]);
  333. break;
  334. case EVT_READY_TO_ACT:
  335. if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
  336. {
  337. onEvtReadyToAct();
  338. }
  339. break;
  340. case EVT_USER_CMD:
  341. onEvtUserCmd(args[0], args[1]);
  342. break;
  343. case EVT_ARRIVED:
  344. // happens e.g. from stopmove but we don't process it if we're casting
  345. if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
  346. {
  347. onEvtArrived();
  348. }
  349. break;
  350. case EVT_ARRIVED_REVALIDATE:
  351. // this is disregarded if the char is not moving any more
  352. if (_actor.isMoving())
  353. {
  354. onEvtArrivedRevalidate();
  355. }
  356. break;
  357. case EVT_ARRIVED_BLOCKED:
  358. onEvtArrivedBlocked((Location) args[0]);
  359. break;
  360. case EVT_FORGET_OBJECT:
  361. onEvtForgetObject((L2Object) args[0]);
  362. break;
  363. case EVT_CANCEL:
  364. onEvtCancel();
  365. break;
  366. case EVT_DEAD:
  367. onEvtDead();
  368. break;
  369. case EVT_FAKE_DEATH:
  370. onEvtFakeDeath();
  371. break;
  372. case EVT_FINISH_CASTING:
  373. onEvtFinishCasting();
  374. break;
  375. case EVT_AFRAID:
  376. {
  377. onEvtAfraid((L2Character) args[0], (Boolean) args[1]);
  378. break;
  379. }
  380. }
  381. // Do next action.
  382. if ((_nextAction != null) && _nextAction.getEvents().contains(evt))
  383. {
  384. _nextAction.doAction();
  385. }
  386. }
  387. protected abstract void onIntentionIdle();
  388. protected abstract void onIntentionActive();
  389. protected abstract void onIntentionRest();
  390. protected abstract void onIntentionAttack(L2Character target);
  391. protected abstract void onIntentionCast(Skill skill, L2Object target);
  392. protected abstract void onIntentionMoveTo(Location destination);
  393. protected abstract void onIntentionFollow(L2Character target);
  394. protected abstract void onIntentionPickUp(L2Object item);
  395. protected abstract void onIntentionInteract(L2Object object);
  396. protected abstract void onEvtThink();
  397. protected abstract void onEvtAttacked(L2Character attacker);
  398. protected abstract void onEvtAggression(L2Character target, int aggro);
  399. protected abstract void onEvtStunned(L2Character attacker);
  400. protected abstract void onEvtParalyzed(L2Character attacker);
  401. protected abstract void onEvtSleeping(L2Character attacker);
  402. protected abstract void onEvtRooted(L2Character attacker);
  403. protected abstract void onEvtConfused(L2Character attacker);
  404. protected abstract void onEvtMuted(L2Character attacker);
  405. protected abstract void onEvtEvaded(L2Character attacker);
  406. protected abstract void onEvtReadyToAct();
  407. protected abstract void onEvtUserCmd(Object arg0, Object arg1);
  408. protected abstract void onEvtArrived();
  409. protected abstract void onEvtArrivedRevalidate();
  410. protected abstract void onEvtArrivedBlocked(Location blocked_at_pos);
  411. protected abstract void onEvtForgetObject(L2Object object);
  412. protected abstract void onEvtCancel();
  413. protected abstract void onEvtDead();
  414. protected abstract void onEvtFakeDeath();
  415. protected abstract void onEvtFinishCasting();
  416. protected abstract void onEvtAfraid(L2Character effector, boolean start);
  417. /**
  418. * Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor. <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  419. */
  420. protected void clientActionFailed()
  421. {
  422. if (_actor instanceof L2PcInstance)
  423. {
  424. _actor.sendPacket(ActionFailed.STATIC_PACKET);
  425. }
  426. }
  427. /**
  428. * Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn <I>(broadcast)</I>.<br>
  429. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  430. * @param pawn
  431. * @param offset
  432. */
  433. protected void moveToPawn(L2Object pawn, int offset)
  434. {
  435. // Check if actor can move
  436. if (!_actor.isMovementDisabled())
  437. {
  438. if (offset < 10)
  439. {
  440. offset = 10;
  441. }
  442. // prevent possible extra calls to this function (there is none?),
  443. // also don't send movetopawn packets too often
  444. boolean sendPacket = true;
  445. if (_clientMoving && (_target == pawn))
  446. {
  447. if (_clientMovingToPawnOffset == offset)
  448. {
  449. if (GameTimeController.getInstance().getGameTicks() < _moveToPawnTimeout)
  450. {
  451. return;
  452. }
  453. sendPacket = false;
  454. }
  455. else if (_actor.isOnGeodataPath())
  456. {
  457. // minimum time to calculate new route is 2 seconds
  458. if (GameTimeController.getInstance().getGameTicks() < (_moveToPawnTimeout + 10))
  459. {
  460. return;
  461. }
  462. }
  463. }
  464. // Set AI movement data
  465. _clientMoving = true;
  466. _clientMovingToPawnOffset = offset;
  467. _target = pawn;
  468. _moveToPawnTimeout = GameTimeController.getInstance().getGameTicks();
  469. _moveToPawnTimeout += 1000 / GameTimeController.MILLIS_IN_TICK;
  470. if (pawn == null)
  471. {
  472. return;
  473. }
  474. // Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
  475. _actor.moveToLocation(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
  476. if (!_actor.isMoving())
  477. {
  478. clientActionFailed();
  479. return;
  480. }
  481. // Send a Server->Client packet MoveToPawn/CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
  482. if (pawn instanceof L2Character)
  483. {
  484. if (_actor.isOnGeodataPath())
  485. {
  486. _actor.broadcastPacket(new MoveToLocation(_actor));
  487. _clientMovingToPawnOffset = 0;
  488. }
  489. else if (sendPacket)
  490. {
  491. _actor.broadcastPacket(new MoveToPawn(_actor, (L2Character) pawn, offset));
  492. }
  493. }
  494. else
  495. {
  496. _actor.broadcastPacket(new MoveToLocation(_actor));
  497. }
  498. }
  499. else
  500. {
  501. clientActionFailed();
  502. }
  503. }
  504. /**
  505. * Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation <I>(broadcast)</I>.<br>
  506. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  507. * @param x
  508. * @param y
  509. * @param z
  510. */
  511. protected void moveTo(int x, int y, int z)
  512. {
  513. // Chek if actor can move
  514. if (!_actor.isMovementDisabled())
  515. {
  516. // Set AI movement data
  517. _clientMoving = true;
  518. _clientMovingToPawnOffset = 0;
  519. // Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
  520. _actor.moveToLocation(x, y, z, 0);
  521. // Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
  522. _actor.broadcastPacket(new MoveToLocation(_actor));
  523. }
  524. else
  525. {
  526. clientActionFailed();
  527. }
  528. }
  529. /**
  530. * Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation <I>(broadcast)</I>.<br>
  531. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  532. * @param loc
  533. */
  534. protected void clientStopMoving(Location loc)
  535. {
  536. // Stop movement of the L2Character
  537. if (_actor.isMoving())
  538. {
  539. _actor.stopMove(loc);
  540. }
  541. _clientMovingToPawnOffset = 0;
  542. if (_clientMoving || (loc != null))
  543. {
  544. _clientMoving = false;
  545. // Send a Server->Client packet StopMove to the actor and all L2PcInstance in its _knownPlayers
  546. _actor.broadcastPacket(new StopMove(_actor));
  547. if (loc != null)
  548. {
  549. // Send a Server->Client packet StopRotation to the actor and all L2PcInstance in its _knownPlayers
  550. _actor.broadcastPacket(new StopRotation(_actor.getObjectId(), loc.getHeading(), 0));
  551. }
  552. }
  553. }
  554. /**
  555. * Client has already arrived to target, no need to force StopMove packet.
  556. */
  557. protected void clientStoppedMoving()
  558. {
  559. if (_clientMovingToPawnOffset > 0) // movetoPawn needs to be stopped
  560. {
  561. _clientMovingToPawnOffset = 0;
  562. _actor.broadcastPacket(new StopMove(_actor));
  563. }
  564. _clientMoving = false;
  565. }
  566. public boolean isAutoAttacking()
  567. {
  568. return _clientAutoAttacking;
  569. }
  570. public void setAutoAttacking(boolean isAutoAttacking)
  571. {
  572. if (_actor instanceof L2Summon)
  573. {
  574. L2Summon summon = (L2Summon) _actor;
  575. if (summon.getOwner() != null)
  576. {
  577. summon.getOwner().getAI().setAutoAttacking(isAutoAttacking);
  578. }
  579. return;
  580. }
  581. _clientAutoAttacking = isAutoAttacking;
  582. }
  583. /**
  584. * Start the actor Auto Attack client side by sending Server->Client packet AutoAttackStart <I>(broadcast)</I>.<br>
  585. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  586. */
  587. public void clientStartAutoAttack()
  588. {
  589. if (_actor instanceof L2Summon)
  590. {
  591. L2Summon summon = (L2Summon) _actor;
  592. if (summon.getOwner() != null)
  593. {
  594. summon.getOwner().getAI().clientStartAutoAttack();
  595. }
  596. return;
  597. }
  598. if (!isAutoAttacking())
  599. {
  600. if (_actor.isPlayer() && _actor.hasSummon())
  601. {
  602. _actor.getSummon().broadcastPacket(new AutoAttackStart(_actor.getSummon().getObjectId()));
  603. }
  604. // Send a Server->Client packet AutoAttackStart to the actor and all L2PcInstance in its _knownPlayers
  605. _actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId()));
  606. setAutoAttacking(true);
  607. }
  608. AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
  609. }
  610. /**
  611. * Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop <I>(broadcast)</I>.<br>
  612. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  613. */
  614. public void clientStopAutoAttack()
  615. {
  616. if (_actor instanceof L2Summon)
  617. {
  618. L2Summon summon = (L2Summon) _actor;
  619. if (summon.getOwner() != null)
  620. {
  621. summon.getOwner().getAI().clientStopAutoAttack();
  622. }
  623. return;
  624. }
  625. if (_actor instanceof L2PcInstance)
  626. {
  627. if (!AttackStanceTaskManager.getInstance().hasAttackStanceTask(_actor) && isAutoAttacking())
  628. {
  629. AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
  630. }
  631. }
  632. else if (isAutoAttacking())
  633. {
  634. _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
  635. setAutoAttacking(false);
  636. }
  637. }
  638. /**
  639. * Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die <I>(broadcast)</I>.<br>
  640. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  641. */
  642. protected void clientNotifyDead()
  643. {
  644. // Send a Server->Client packet Die to the actor and all L2PcInstance in its _knownPlayers
  645. Die msg = new Die(_actor);
  646. _actor.broadcastPacket(msg);
  647. // Init AI
  648. _intention = AI_INTENTION_IDLE;
  649. _target = null;
  650. _castTarget = null;
  651. _attackTarget = null;
  652. // Cancel the follow task if necessary
  653. stopFollow();
  654. }
  655. /**
  656. * Update the state of this actor client side by sending Server->Client packet MoveToPawn/CharMoveToLocation and AutoAttackStart to the L2PcInstance player.<br>
  657. * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>
  658. * @param player The L2PcIstance to notify with state of this L2Character
  659. */
  660. public void describeStateToPlayer(L2PcInstance player)
  661. {
  662. if (getActor().isVisibleFor(player))
  663. {
  664. if (_clientMoving)
  665. {
  666. if ((_clientMovingToPawnOffset != 0) && (_followTarget != null))
  667. {
  668. // Send a Server->Client packet MoveToPawn to the actor and all L2PcInstance in its _knownPlayers
  669. player.sendPacket(new MoveToPawn(_actor, _followTarget, _clientMovingToPawnOffset));
  670. }
  671. else
  672. {
  673. // Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
  674. player.sendPacket(new MoveToLocation(_actor));
  675. }
  676. }
  677. }
  678. }
  679. /**
  680. * Create and Launch an AI Follow Task to execute every 1s.
  681. * @param target The L2Character to follow
  682. */
  683. public synchronized void startFollow(L2Character target)
  684. {
  685. if (_followTask != null)
  686. {
  687. _followTask.cancel(false);
  688. _followTask = null;
  689. }
  690. // Create and Launch an AI Follow Task to execute every 1s
  691. _followTarget = target;
  692. _followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL);
  693. }
  694. /**
  695. * Create and Launch an AI Follow Task to execute every 0.5s, following at specified range.
  696. * @param target The L2Character to follow
  697. * @param range
  698. */
  699. public synchronized void startFollow(L2Character target, int range)
  700. {
  701. if (_followTask != null)
  702. {
  703. _followTask.cancel(false);
  704. _followTask = null;
  705. }
  706. _followTarget = target;
  707. _followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL);
  708. }
  709. /**
  710. * Stop an AI Follow Task.
  711. */
  712. public synchronized void stopFollow()
  713. {
  714. if (_followTask != null)
  715. {
  716. // Stop the Follow Task
  717. _followTask.cancel(false);
  718. _followTask = null;
  719. }
  720. _followTarget = null;
  721. }
  722. protected L2Character getFollowTarget()
  723. {
  724. return _followTarget;
  725. }
  726. protected L2Object getTarget()
  727. {
  728. return _target;
  729. }
  730. protected void setTarget(L2Object target)
  731. {
  732. _target = target;
  733. }
  734. /**
  735. * Stop all Ai tasks and futures.
  736. */
  737. public void stopAITask()
  738. {
  739. stopFollow();
  740. }
  741. @Override
  742. public String toString()
  743. {
  744. return "Actor: " + _actor;
  745. }
  746. }