L2PlayerAI.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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_CAST;
  18. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
  19. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
  20. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
  21. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
  22. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
  23. import net.sf.l2j.Config;
  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.L2Character.AIAccessor;
  29. import net.sf.l2j.gameserver.model.L2Skill.SkillTargetType;
  30. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  31. import net.sf.l2j.gameserver.model.actor.instance.L2StaticObjectInstance;
  32. public class L2PlayerAI extends L2CharacterAI
  33. {
  34. private boolean _thinking; // to prevent recursive thinking
  35. //private Stack<IntentionCommand> _interruptedIntentions = new Stack<IntentionCommand>();
  36. IntentionCommand _nextIntention = null;
  37. public L2PlayerAI(AIAccessor accessor)
  38. {
  39. super(accessor);
  40. }
  41. void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1)
  42. {
  43. /*
  44. if (Config.DEBUG)
  45. _log.warning("L2PlayerAI: changeIntention -> Saving next intention: " + _intention + " " + _intention_arg0 + " " + _intention_arg1);
  46. */
  47. _nextIntention = new IntentionCommand(intention, arg0, arg1);
  48. }
  49. @Override
  50. public IntentionCommand getNextIntention()
  51. {
  52. return _nextIntention;
  53. }
  54. /**
  55. * Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.<BR><BR>
  56. *
  57. * @param intention The new Intention to set to the AI
  58. * @param arg0 The first parameter of the Intention
  59. * @param arg1 The second parameter of the Intention
  60. *
  61. */
  62. @Override
  63. synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
  64. {
  65. /*
  66. if (Config.DEBUG)
  67. _log.warning("L2PlayerAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
  68. */
  69. // do nothing unless CAST intention
  70. // however, forget interrupted actions when starting to use an offensive skill
  71. if (intention != AI_INTENTION_CAST || (arg0 != null && ((L2Skill)arg0).isOffensive()))
  72. {
  73. _nextIntention = null;
  74. super.changeIntention(intention, arg0, arg1);
  75. return;
  76. }
  77. // do nothing if next intention is same as current one.
  78. if (intention == _intention && arg0 == _intentionArg0 && arg1 == _intentionArg1)
  79. {
  80. super.changeIntention(intention, arg0, arg1);
  81. return;
  82. }
  83. // save current intention so it can be used after cast
  84. saveNextIntention(_intention, _intentionArg0, _intentionArg1);
  85. super.changeIntention(intention, arg0, arg1);
  86. }
  87. /**
  88. * Launch actions corresponding to the Event ReadyToAct.<BR><BR>
  89. *
  90. * <B><U> Actions</U> :</B><BR><BR>
  91. * <li>Launch actions corresponding to the Event Think</li><BR><BR>
  92. *
  93. */
  94. @Override
  95. protected void onEvtReadyToAct()
  96. {
  97. // Launch actions corresponding to the Event Think
  98. if (_nextIntention != null)
  99. {
  100. setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
  101. _nextIntention = null;
  102. }
  103. super.onEvtReadyToAct();
  104. }
  105. /**
  106. * Launch actions corresponding to the Event Cancel.<BR><BR>
  107. *
  108. * <B><U> Actions</U> :</B><BR><BR>
  109. * <li>Stop an AI Follow Task</li>
  110. * <li>Launch actions corresponding to the Event Think</li><BR><BR>
  111. *
  112. */
  113. @Override
  114. protected void onEvtCancel()
  115. {
  116. _nextIntention = null;
  117. super.onEvtCancel();
  118. }
  119. /**
  120. * Finalize the casting of a skill. This method overrides L2CharacterAI method.<BR><BR>
  121. *
  122. * <B>What it does:</B>
  123. * Check if actual intention is set to CAST and, if so, retrieves latest intention
  124. * before the actual CAST and set it as the current intention for the player
  125. */
  126. @Override
  127. protected void onEvtFinishCasting()
  128. {
  129. if (getIntention() == AI_INTENTION_CAST)
  130. {
  131. // run interrupted or next intention
  132. if (_nextIntention != null)
  133. {
  134. if (_nextIntention._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
  135. {
  136. setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
  137. }
  138. else setIntention(AI_INTENTION_IDLE);
  139. }
  140. else
  141. {
  142. /*
  143. if (Config.DEBUG)
  144. _log.warning("L2PlayerAI: no previous intention set... Setting it to IDLE");
  145. */
  146. // set intention to idle if skill doesn't change intention.
  147. setIntention(AI_INTENTION_IDLE);
  148. }
  149. }
  150. }
  151. @Override
  152. protected void onIntentionRest()
  153. {
  154. if (getIntention() != AI_INTENTION_REST)
  155. {
  156. changeIntention(AI_INTENTION_REST, null, null);
  157. setTarget(null);
  158. if (getAttackTarget() != null)
  159. {
  160. setAttackTarget(null);
  161. }
  162. clientStopMoving(null);
  163. }
  164. }
  165. @Override
  166. protected void onIntentionActive()
  167. {
  168. setIntention(AI_INTENTION_IDLE);
  169. }
  170. /**
  171. * Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<BR><BR>
  172. *
  173. * <B><U> Actions</U> : </B><BR><BR>
  174. * <li>Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast) </li>
  175. * <li>Set the Intention of this AI to AI_INTENTION_MOVE_TO </li>
  176. * <li>Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast) </li><BR><BR>
  177. *
  178. */
  179. @Override
  180. protected void onIntentionMoveTo(L2CharPosition pos)
  181. {
  182. if (getIntention() == AI_INTENTION_REST)
  183. {
  184. // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
  185. clientActionFailed();
  186. return;
  187. }
  188. if (_actor.isAllSkillsDisabled() || _actor.isAttackingNow())
  189. {
  190. clientActionFailed();
  191. saveNextIntention(AI_INTENTION_MOVE_TO, pos, null);
  192. return;
  193. }
  194. // Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
  195. changeIntention(AI_INTENTION_MOVE_TO, pos, null);
  196. // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
  197. clientStopAutoAttack();
  198. // Abort the attack of the L2Character and send Server->Client ActionFailed packet
  199. _actor.abortAttack();
  200. // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
  201. moveTo(pos.x, pos.y, pos.z);
  202. }
  203. @Override
  204. protected void clientNotifyDead()
  205. {
  206. _clientMovingToPawnOffset = 0;
  207. _clientMoving = false;
  208. super.clientNotifyDead();
  209. }
  210. private void thinkAttack()
  211. {
  212. L2Character target = getAttackTarget();
  213. if (target == null) return;
  214. if (checkTargetLostOrDead(target))
  215. {
  216. if (target != null)
  217. {
  218. // Notify the target
  219. setAttackTarget(null);
  220. }
  221. return;
  222. }
  223. if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange())) return;
  224. _accessor.doAttack(target);
  225. return;
  226. }
  227. private void thinkCast()
  228. {
  229. L2Character target = getCastTarget();
  230. if (Config.DEBUG)
  231. _log.warning("L2PlayerAI: thinkCast -> Start");
  232. if (_skill.getTargetType() == SkillTargetType.TARGET_GROUND && _actor instanceof L2PcInstance)
  233. {
  234. if (maybeMoveToPosition(((L2PcInstance)_actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill)))
  235. return;
  236. }
  237. else
  238. {
  239. if (checkTargetLost(target))
  240. {
  241. if (_skill.isOffensive() && getAttackTarget() != null)
  242. {
  243. //Notify the target
  244. setCastTarget(null);
  245. }
  246. return;
  247. }
  248. if (target != null && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
  249. return;
  250. }
  251. if (_skill.getHitTime() > 50) clientStopMoving(null);
  252. L2Object oldTarget = _actor.getTarget();
  253. if (oldTarget != null)
  254. {
  255. // Replace the current target by the cast target
  256. if (target != null && oldTarget != target) _actor.setTarget(getCastTarget());
  257. // Launch the Cast of the skill
  258. _accessor.doCast(_skill);
  259. // Restore the initial target
  260. if (target != null && oldTarget != target) _actor.setTarget(oldTarget);
  261. }
  262. else _accessor.doCast(_skill);
  263. return;
  264. }
  265. private void thinkPickUp()
  266. {
  267. if (_actor.isAllSkillsDisabled()) return;
  268. L2Object target = getTarget();
  269. if (checkTargetLost(target)) return;
  270. if (maybeMoveToPawn(target, 36)) return;
  271. setIntention(AI_INTENTION_IDLE);
  272. ((L2PcInstance.AIAccessor) _accessor).doPickupItem(target);
  273. return;
  274. }
  275. private void thinkInteract()
  276. {
  277. if (_actor.isAllSkillsDisabled()) return;
  278. L2Object target = getTarget();
  279. if (checkTargetLost(target)) return;
  280. if (maybeMoveToPawn(target, 36)) return;
  281. if (!(target instanceof L2StaticObjectInstance)) ((L2PcInstance.AIAccessor) _accessor).doInteract((L2Character) target);
  282. setIntention(AI_INTENTION_IDLE);
  283. return;
  284. }
  285. @Override
  286. protected void onEvtThink()
  287. {
  288. if (_thinking || _actor.isAllSkillsDisabled()) return;
  289. /*
  290. if (Config.DEBUG)
  291. _log.warning("L2PlayerAI: onEvtThink -> Check intention");
  292. */
  293. _thinking = true;
  294. try
  295. {
  296. if (getIntention() == AI_INTENTION_ATTACK) thinkAttack();
  297. else if (getIntention() == AI_INTENTION_CAST) thinkCast();
  298. else if (getIntention() == AI_INTENTION_PICK_UP) thinkPickUp();
  299. else if (getIntention() == AI_INTENTION_INTERACT) thinkInteract();
  300. }
  301. finally
  302. {
  303. _thinking = false;
  304. }
  305. }
  306. @Override
  307. protected void onEvtArrivedRevalidate()
  308. {
  309. if (Config.MOVE_BASED_KNOWNLIST) getActor().getKnownList().findObjects();
  310. super.onEvtArrivedRevalidate();
  311. }
  312. }