2
0

L2PlayerAI.java 9.6 KB

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