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