AbstractAI.java 28 KB

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