L2PlayerAI.java 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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_PICK_UP;
  21. import static net.sf.l2j.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
  22. import java.util.EmptyStackException;
  23. import java.util.Stack;
  24. import net.sf.l2j.gameserver.ThreadPoolManager;
  25. import net.sf.l2j.gameserver.model.L2Character;
  26. import net.sf.l2j.gameserver.model.L2Object;
  27. import net.sf.l2j.gameserver.model.L2Character.AIAccessor;
  28. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  29. import net.sf.l2j.gameserver.model.actor.instance.L2StaticObjectInstance;
  30. import net.sf.l2j.gameserver.model.actor.knownlist.ObjectKnownList.KnownListAsynchronousUpdateTask;
  31. public class L2PlayerAI extends L2CharacterAI
  32. {
  33. private boolean _thinking; // to prevent recursive thinking
  34. class IntentionCommand
  35. {
  36. protected CtrlIntention _crtlIntention;
  37. protected Object _arg0, _arg1;
  38. protected IntentionCommand(CtrlIntention pIntention, Object pArg0, Object pArg1)
  39. {
  40. _crtlIntention = pIntention;
  41. _arg0 = pArg0;
  42. _arg1 = pArg1;
  43. }
  44. }
  45. private Stack<IntentionCommand> _interuptedIntentions = new Stack<IntentionCommand>();
  46. public L2PlayerAI(AIAccessor accessor)
  47. {
  48. super(accessor);
  49. }
  50. /**
  51. * Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.<BR><BR>
  52. *
  53. * @param intention The new Intention to set to the AI
  54. * @param arg0 The first parameter of the Intention
  55. * @param arg1 The second parameter of the Intention
  56. *
  57. */
  58. @Override
  59. synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
  60. {
  61. /*
  62. if (Config.DEBUG)
  63. _log.warning("L2PlayerAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
  64. */
  65. // nothing to do if it does not CAST intention
  66. if (intention != AI_INTENTION_CAST)
  67. {
  68. super.changeIntention(intention, arg0, arg1);
  69. return;
  70. }
  71. // do nothing if next intention is same as current one.
  72. if (intention == _intention && arg0 == _intentionArg0 && arg1 == _intentionArg1)
  73. {
  74. super.changeIntention(intention, arg0, arg1);
  75. return;
  76. }
  77. /*
  78. if (Config.DEBUG)
  79. _log.warning("L2PlayerAI: changeIntention -> Saving current intention: " + _intention + " " + _intention_arg0 + " " + _intention_arg1);
  80. */
  81. // push current intention to stack
  82. _interuptedIntentions.push(new IntentionCommand(_intention, _intentionArg0, _intentionArg1));
  83. super.changeIntention(intention, arg0, arg1);
  84. }
  85. /**
  86. * Finalize the casting of a skill. This method overrides L2CharacterAI method.<BR><BR>
  87. *
  88. * <B>What it does:</B>
  89. * Check if actual intention is set to CAST and, if so, retrieves latest intention
  90. * before the actual CAST and set it as the current intention for the player
  91. */
  92. @Override
  93. protected void onEvtFinishCasting()
  94. {
  95. // forget interupted actions after offensive skill
  96. if (_skill != null && _skill.isOffensive()) _interuptedIntentions.clear();
  97. if (getIntention() == AI_INTENTION_CAST)
  98. {
  99. // run interupted intention if it remain.
  100. if (!_interuptedIntentions.isEmpty())
  101. {
  102. IntentionCommand cmd = null;
  103. try
  104. {
  105. cmd = _interuptedIntentions.pop();
  106. }
  107. catch (EmptyStackException ese)
  108. {
  109. }
  110. /*
  111. if (Config.DEBUG)
  112. _log.warning("L2PlayerAI: onEvtFinishCasting -> " + cmd._intention + " " + cmd._arg0 + " " + cmd._arg1);
  113. */
  114. if (cmd != null && cmd._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
  115. {
  116. setIntention(cmd._crtlIntention, cmd._arg0, cmd._arg1);
  117. }
  118. else setIntention(AI_INTENTION_IDLE);
  119. }
  120. else
  121. {
  122. /*
  123. if (Config.DEBUG)
  124. _log.warning("L2PlayerAI: no previous intention set... Setting it to IDLE");
  125. */
  126. // set intention to idle if skill doesn't change intention.
  127. setIntention(AI_INTENTION_IDLE);
  128. }
  129. }
  130. }
  131. @Override
  132. protected void onIntentionRest()
  133. {
  134. if (getIntention() != AI_INTENTION_REST)
  135. {
  136. changeIntention(AI_INTENTION_REST, null, null);
  137. setTarget(null);
  138. if (getAttackTarget() != null)
  139. {
  140. setAttackTarget(null);
  141. }
  142. clientStopMoving(null);
  143. }
  144. }
  145. @Override
  146. protected void onIntentionActive()
  147. {
  148. setIntention(AI_INTENTION_IDLE);
  149. }
  150. @Override
  151. protected void clientNotifyDead()
  152. {
  153. _clientMovingToPawnOffset = 0;
  154. _clientMoving = false;
  155. super.clientNotifyDead();
  156. }
  157. private void thinkAttack()
  158. {
  159. L2Character target = getAttackTarget();
  160. if (target == null) return;
  161. if (checkTargetLostOrDead(target))
  162. {
  163. if (target != null)
  164. {
  165. // Notify the target
  166. setAttackTarget(null);
  167. }
  168. return;
  169. }
  170. if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange())) return;
  171. _accessor.doAttack(target);
  172. return;
  173. }
  174. private void thinkCast()
  175. {
  176. L2Character target = getCastTarget();
  177. //if (Config.DEBUG) _log.warning("L2PlayerAI: thinkCast -> Start");
  178. if (checkTargetLost(target))
  179. {
  180. if (_skill.isOffensive() && getAttackTarget() != null)
  181. {
  182. //Notify the target
  183. setCastTarget(null);
  184. }
  185. return;
  186. }
  187. if (target != null)
  188. if (maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill))) return;
  189. if (_skill.getHitTime() > 50) clientStopMoving(null);
  190. L2Object oldTarget = _actor.getTarget();
  191. if (oldTarget != null)
  192. {
  193. // Replace the current target by the cast target
  194. if (target != null && oldTarget != target) _actor.setTarget(getCastTarget());
  195. // Launch the Cast of the skill
  196. _accessor.doCast(_skill);
  197. // Restore the initial target
  198. if (target != null && oldTarget != target) _actor.setTarget(oldTarget);
  199. }
  200. else _accessor.doCast(_skill);
  201. return;
  202. }
  203. private void thinkPickUp()
  204. {
  205. if (_actor.isAllSkillsDisabled()) return;
  206. L2Object target = getTarget();
  207. if (checkTargetLost(target)) return;
  208. if (maybeMoveToPawn(target, 36)) return;
  209. setIntention(AI_INTENTION_IDLE);
  210. ((L2PcInstance.AIAccessor) _accessor).doPickupItem(target);
  211. return;
  212. }
  213. private void thinkInteract()
  214. {
  215. if (_actor.isAllSkillsDisabled()) return;
  216. L2Object target = getTarget();
  217. if (checkTargetLost(target)) return;
  218. if (maybeMoveToPawn(target, 36)) return;
  219. if (!(target instanceof L2StaticObjectInstance)) ((L2PcInstance.AIAccessor) _accessor).doInteract((L2Character) target);
  220. setIntention(AI_INTENTION_IDLE);
  221. return;
  222. }
  223. @Override
  224. protected void onEvtThink()
  225. {
  226. if (_thinking || _actor.isAllSkillsDisabled()) return;
  227. /*
  228. if (Config.DEBUG)
  229. _log.warning("L2PlayerAI: onEvtThink -> Check intention");
  230. */
  231. _thinking = true;
  232. try
  233. {
  234. if (getIntention() == AI_INTENTION_ATTACK) thinkAttack();
  235. else if (getIntention() == AI_INTENTION_CAST) thinkCast();
  236. else if (getIntention() == AI_INTENTION_PICK_UP) thinkPickUp();
  237. else if (getIntention() == AI_INTENTION_INTERACT) thinkInteract();
  238. }
  239. finally
  240. {
  241. _thinking = false;
  242. }
  243. }
  244. @Override
  245. protected void onEvtArrivedRevalidate()
  246. {
  247. ThreadPoolManager.getInstance().executeTask(new KnownListAsynchronousUpdateTask(_actor));
  248. super.onEvtArrivedRevalidate();
  249. }
  250. }