L2Object.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /*
  2. * Copyright (C) 2004-2013 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.model;
  20. import java.util.Map;
  21. import javolution.util.FastMap;
  22. import com.l2jserver.gameserver.enums.InstanceType;
  23. import com.l2jserver.gameserver.enums.ShotType;
  24. import com.l2jserver.gameserver.handler.ActionHandler;
  25. import com.l2jserver.gameserver.handler.ActionShiftHandler;
  26. import com.l2jserver.gameserver.handler.IActionHandler;
  27. import com.l2jserver.gameserver.idfactory.IdFactory;
  28. import com.l2jserver.gameserver.instancemanager.InstanceManager;
  29. import com.l2jserver.gameserver.model.actor.L2Character;
  30. import com.l2jserver.gameserver.model.actor.L2Npc;
  31. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  32. import com.l2jserver.gameserver.model.actor.knownlist.ObjectKnownList;
  33. import com.l2jserver.gameserver.model.actor.poly.ObjectPoly;
  34. import com.l2jserver.gameserver.model.entity.Instance;
  35. import com.l2jserver.gameserver.model.interfaces.IDecayable;
  36. import com.l2jserver.gameserver.model.interfaces.IIdentifiable;
  37. import com.l2jserver.gameserver.model.interfaces.INamable;
  38. import com.l2jserver.gameserver.model.interfaces.ISpawnable;
  39. import com.l2jserver.gameserver.model.interfaces.IUniqueId;
  40. import com.l2jserver.gameserver.model.zone.ZoneId;
  41. import com.l2jserver.gameserver.network.SystemMessageId;
  42. import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
  43. import com.l2jserver.gameserver.network.serverpackets.ExSendUIEvent;
  44. import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
  45. import com.l2jserver.gameserver.util.Point3D;
  46. /**
  47. * Base class for all interactive objects.
  48. * @author unknown
  49. */
  50. public abstract class L2Object extends Point3D implements IIdentifiable, INamable, ISpawnable, IUniqueId, IDecayable
  51. {
  52. private boolean _isVisible;
  53. private ObjectKnownList _knownList;
  54. private String _name;
  55. private int _objectId;
  56. private L2WorldRegion _worldRegion;
  57. private InstanceType _instanceType = null;
  58. private volatile Map<String, Object> _scripts;
  59. public L2Object(int objectId)
  60. {
  61. super(0, 0, 0);
  62. setInstanceType(InstanceType.L2Object);
  63. _objectId = objectId;
  64. initKnownList();
  65. }
  66. protected final void setInstanceType(InstanceType i)
  67. {
  68. _instanceType = i;
  69. }
  70. public final InstanceType getInstanceType()
  71. {
  72. return _instanceType;
  73. }
  74. public final boolean isInstanceType(InstanceType i)
  75. {
  76. return _instanceType.isType(i);
  77. }
  78. public final boolean isInstanceTypes(InstanceType... i)
  79. {
  80. return _instanceType.isTypes(i);
  81. }
  82. public final void onAction(L2PcInstance player)
  83. {
  84. onAction(player, true);
  85. }
  86. public void onAction(L2PcInstance player, boolean interact)
  87. {
  88. IActionHandler handler = ActionHandler.getInstance().getHandler(getInstanceType());
  89. if (handler != null)
  90. {
  91. handler.action(player, this, interact);
  92. }
  93. player.sendPacket(ActionFailed.STATIC_PACKET);
  94. }
  95. public void onActionShift(L2PcInstance player)
  96. {
  97. IActionHandler handler = ActionShiftHandler.getInstance().getHandler(getInstanceType());
  98. if (handler != null)
  99. {
  100. handler.action(player, this, true);
  101. }
  102. player.sendPacket(ActionFailed.STATIC_PACKET);
  103. }
  104. public void onForcedAttack(L2PcInstance player)
  105. {
  106. player.sendPacket(ActionFailed.STATIC_PACKET);
  107. }
  108. public void onSpawn()
  109. {
  110. }
  111. /**
  112. * UnAfraid: TODO: Add listener here.
  113. * @param instanceId The id of the instance zone the object is in - id 0 is global
  114. */
  115. @Override
  116. public void setInstanceId(int instanceId)
  117. {
  118. if ((instanceId < 0) || (getInstanceId() == instanceId))
  119. {
  120. return;
  121. }
  122. Instance oldI = InstanceManager.getInstance().getInstance(getInstanceId());
  123. Instance newI = InstanceManager.getInstance().getInstance(instanceId);
  124. if (newI == null)
  125. {
  126. return;
  127. }
  128. if (isPlayer())
  129. {
  130. final L2PcInstance player = getActingPlayer();
  131. if ((getInstanceId() > 0) && (oldI != null))
  132. {
  133. oldI.removePlayer(getObjectId());
  134. if (oldI.isShowTimer())
  135. {
  136. sendInstanceUpdate(oldI, true);
  137. }
  138. }
  139. if (instanceId > 0)
  140. {
  141. newI.addPlayer(getObjectId());
  142. if (newI.isShowTimer())
  143. {
  144. sendInstanceUpdate(newI, false);
  145. }
  146. }
  147. if (player.hasSummon())
  148. {
  149. player.getSummon().setInstanceId(instanceId);
  150. }
  151. }
  152. else if (isNpc())
  153. {
  154. final L2Npc npc = (L2Npc) this;
  155. if ((getInstanceId() > 0) && (oldI != null))
  156. {
  157. oldI.removeNpc(npc);
  158. }
  159. if (instanceId > 0)
  160. {
  161. newI.addNpc(npc);
  162. }
  163. }
  164. super.setInstanceId(instanceId);
  165. if (_isVisible && (_knownList != null))
  166. {
  167. // We don't want some ugly looking disappear/appear effects, so don't update
  168. // the knownlist here, but players usually enter instancezones through teleporting
  169. // and the teleport will do the revalidation for us.
  170. if (!isPlayer())
  171. {
  172. decayMe();
  173. spawnMe();
  174. }
  175. }
  176. }
  177. private final void sendInstanceUpdate(Instance instance, boolean hide)
  178. {
  179. final int startTime = (int) ((System.currentTimeMillis() - instance.getInstanceStartTime()) / 1000);
  180. final int endTime = (int) ((instance.getInstanceEndTime() - instance.getInstanceStartTime()) / 1000);
  181. if (instance.isTimerIncrease())
  182. {
  183. sendPacket(new ExSendUIEvent(getActingPlayer(), hide, true, startTime, endTime, instance.getTimerText()));
  184. }
  185. else
  186. {
  187. sendPacket(new ExSendUIEvent(getActingPlayer(), hide, false, endTime - startTime, 0, instance.getTimerText()));
  188. }
  189. }
  190. @Override
  191. public boolean decayMe()
  192. {
  193. assert getWorldRegion() != null;
  194. L2WorldRegion reg = getWorldRegion();
  195. synchronized (this)
  196. {
  197. _isVisible = false;
  198. setWorldRegion(null);
  199. }
  200. // this can synchronize on others instances, so it's out of
  201. // synchronized, to avoid deadlocks
  202. // Remove the L2Object from the world
  203. L2World.getInstance().removeVisibleObject(this, reg);
  204. L2World.getInstance().removeObject(this);
  205. return true;
  206. }
  207. public void refreshID()
  208. {
  209. L2World.getInstance().removeObject(this);
  210. IdFactory.getInstance().releaseId(getObjectId());
  211. _objectId = IdFactory.getInstance().getNextId();
  212. }
  213. @Override
  214. public final boolean spawnMe()
  215. {
  216. assert (getWorldRegion() == null) && (getWorldPosition().getX() != 0) && (getWorldPosition().getY() != 0) && (getWorldPosition().getZ() != 0);
  217. synchronized (this)
  218. {
  219. // Set the x,y,z position of the L2Object spawn and update its _worldregion
  220. _isVisible = true;
  221. setWorldRegion(L2World.getInstance().getRegion(getWorldPosition()));
  222. // Add the L2Object spawn in the _allobjects of L2World
  223. L2World.getInstance().storeObject(this);
  224. // Add the L2Object spawn to _visibleObjects and if necessary to _allplayers of its L2WorldRegion
  225. getWorldRegion().addVisibleObject(this);
  226. }
  227. // this can synchronize on others instances, so it's out of synchronized, to avoid deadlocks
  228. // Add the L2Object spawn in the world as a visible object
  229. L2World.getInstance().addVisibleObject(this, getWorldRegion());
  230. onSpawn();
  231. return true;
  232. }
  233. public final void spawnMe(int x, int y, int z)
  234. {
  235. assert getWorldRegion() == null;
  236. synchronized (this)
  237. {
  238. // Set the x,y,z position of the L2Object spawn and update its _worldregion
  239. _isVisible = true;
  240. if (x > L2World.MAP_MAX_X)
  241. {
  242. x = L2World.MAP_MAX_X - 5000;
  243. }
  244. if (x < L2World.MAP_MIN_X)
  245. {
  246. x = L2World.MAP_MIN_X + 5000;
  247. }
  248. if (y > L2World.MAP_MAX_Y)
  249. {
  250. y = L2World.MAP_MAX_Y - 5000;
  251. }
  252. if (y < L2World.MAP_MIN_Y)
  253. {
  254. y = L2World.MAP_MIN_Y + 5000;
  255. }
  256. setXYZ(x, y, z);
  257. setWorldRegion(L2World.getInstance().getRegion(getWorldPosition()));
  258. // Add the L2Object spawn in the _allobjects of L2World
  259. }
  260. L2World.getInstance().storeObject(this);
  261. // these can synchronize on others instances, so they're out of
  262. // synchronized, to avoid deadlocks
  263. // Add the L2Object spawn to _visibleObjects and if necessary to _allplayers of its L2WorldRegion
  264. getWorldRegion().addVisibleObject(this);
  265. // Add the L2Object spawn in the world as a visible object
  266. L2World.getInstance().addVisibleObject(this, getWorldRegion());
  267. onSpawn();
  268. }
  269. public boolean isAttackable()
  270. {
  271. return false;
  272. }
  273. public abstract boolean isAutoAttackable(L2Character attacker);
  274. public final boolean isVisible()
  275. {
  276. return getWorldRegion() != null;
  277. }
  278. public final void setIsVisible(boolean value)
  279. {
  280. _isVisible = value;
  281. if (!_isVisible)
  282. {
  283. setWorldRegion(null);
  284. }
  285. }
  286. public void toggleVisible()
  287. {
  288. if (isVisible())
  289. {
  290. decayMe();
  291. }
  292. else
  293. {
  294. spawnMe();
  295. }
  296. }
  297. public ObjectKnownList getKnownList()
  298. {
  299. return _knownList;
  300. }
  301. public void initKnownList()
  302. {
  303. _knownList = new ObjectKnownList(this);
  304. }
  305. public final void setKnownList(ObjectKnownList value)
  306. {
  307. _knownList = value;
  308. }
  309. @Override
  310. public final String getName()
  311. {
  312. return _name;
  313. }
  314. public void setName(String value)
  315. {
  316. _name = value;
  317. }
  318. @Override
  319. public final int getObjectId()
  320. {
  321. return _objectId;
  322. }
  323. public final ObjectPoly getPoly()
  324. {
  325. final ObjectPoly poly = getScript(ObjectPoly.class);
  326. return (poly == null) ? addScript(new ObjectPoly(this)) : poly;
  327. }
  328. public abstract void sendInfo(L2PcInstance activeChar);
  329. public void sendPacket(L2GameServerPacket mov)
  330. {
  331. }
  332. public void sendPacket(SystemMessageId id)
  333. {
  334. }
  335. public L2PcInstance getActingPlayer()
  336. {
  337. return null;
  338. }
  339. /**
  340. * @return {@code true} if object is instance of L2PcInstance
  341. */
  342. public boolean isPlayer()
  343. {
  344. return false;
  345. }
  346. /**
  347. * @return {@code true} if object is instance of L2Playable
  348. */
  349. public boolean isPlayable()
  350. {
  351. return false;
  352. }
  353. /**
  354. * @return {@code true} if object is instance of L2Summon
  355. */
  356. public boolean isSummon()
  357. {
  358. return false;
  359. }
  360. /**
  361. * @return {@code true} if object is instance of L2PetInstance
  362. */
  363. public boolean isPet()
  364. {
  365. return false;
  366. }
  367. /**
  368. * @return {@code true} if object is instance of L2ServitorInstance
  369. */
  370. public boolean isServitor()
  371. {
  372. return false;
  373. }
  374. /**
  375. * @return {@code true} if object is instance of L2Attackable
  376. */
  377. public boolean isCharacter()
  378. {
  379. return false;
  380. }
  381. /**
  382. * @return {@code true} if object is instance of L2DoorInstance
  383. */
  384. public boolean isDoor()
  385. {
  386. return false;
  387. }
  388. /**
  389. * @return {@code true} if object is instance of L2Npc
  390. */
  391. public boolean isNpc()
  392. {
  393. return false;
  394. }
  395. /**
  396. * @return {@code true} if object is instance of L2Attackable
  397. */
  398. public boolean isL2Attackable()
  399. {
  400. return false;
  401. }
  402. /**
  403. * @return {@code true} if object is instance of L2MonsterInstance
  404. */
  405. public boolean isMonster()
  406. {
  407. return false;
  408. }
  409. /**
  410. * @return {@code true} if object is instance of L2TrapInstance
  411. */
  412. public boolean isTrap()
  413. {
  414. return false;
  415. }
  416. /**
  417. * @return {@code true} if object is instance of L2ItemInstance
  418. */
  419. public boolean isItem()
  420. {
  421. return false;
  422. }
  423. /**
  424. * @return {@code true} if object Npc Walker or Vehicle
  425. */
  426. public boolean isWalker()
  427. {
  428. return false;
  429. }
  430. /**
  431. * @return {@code true} if object Can be targeted
  432. */
  433. public boolean isTargetable()
  434. {
  435. return true;
  436. }
  437. /**
  438. * Check if the object is in the given zone Id.
  439. * @param zone the zone Id to check
  440. * @return {@code true} if the object is in that zone Id
  441. */
  442. public boolean isInsideZone(ZoneId zone)
  443. {
  444. return false;
  445. }
  446. /**
  447. * Check if current object has charged shot.
  448. * @param type of the shot to be checked.
  449. * @return {@code true} if the object has charged shot
  450. */
  451. public boolean isChargedShot(ShotType type)
  452. {
  453. return false;
  454. }
  455. /**
  456. * Charging shot into the current object.
  457. * @param type of the shot to be charged.
  458. * @param charged
  459. */
  460. public void setChargedShot(ShotType type, boolean charged)
  461. {
  462. }
  463. /**
  464. * Try to recharge a shot.
  465. * @param physical skill are using Soul shots.
  466. * @param magical skill are using Spirit shots.
  467. */
  468. public void rechargeShots(boolean physical, boolean magical)
  469. {
  470. }
  471. /**
  472. * @param <T>
  473. * @param script
  474. * @return
  475. */
  476. public final <T> T addScript(T script)
  477. {
  478. if (_scripts == null)
  479. {
  480. // Double-checked locking
  481. synchronized (this)
  482. {
  483. if (_scripts == null)
  484. {
  485. _scripts = new FastMap<String, Object>().shared();
  486. }
  487. }
  488. }
  489. _scripts.put(script.getClass().getName(), script);
  490. return script;
  491. }
  492. /**
  493. * @param <T>
  494. * @param script
  495. * @return
  496. */
  497. @SuppressWarnings("unchecked")
  498. public final <T> T removeScript(Class<T> script)
  499. {
  500. if (_scripts == null)
  501. {
  502. return null;
  503. }
  504. return (T) _scripts.remove(script.getName());
  505. }
  506. /**
  507. * @param <T>
  508. * @param script
  509. * @return
  510. */
  511. @SuppressWarnings("unchecked")
  512. public final <T> T getScript(Class<T> script)
  513. {
  514. if (_scripts == null)
  515. {
  516. return null;
  517. }
  518. return (T) _scripts.get(script.getName());
  519. }
  520. public void removeStatusListener(L2Character object)
  521. {
  522. }
  523. @Override
  524. public final void setXYZ(int x, int y, int z)
  525. {
  526. assert getWorldRegion() != null;
  527. super.setXYZ(x, y, z);
  528. try
  529. {
  530. if (L2World.getInstance().getRegion(getWorldPosition()) != getWorldRegion())
  531. {
  532. updateWorldRegion();
  533. }
  534. }
  535. catch (Exception e)
  536. {
  537. badCoords();
  538. }
  539. }
  540. protected void badCoords()
  541. {
  542. if (isCharacter())
  543. {
  544. this.decayMe();
  545. }
  546. else if (isPlayer())
  547. {
  548. ((L2Character) this).teleToLocation(new Location(0, 0, 0), false);
  549. ((L2Character) this).sendMessage("Error with your coords, Please ask a GM for help!");
  550. }
  551. }
  552. public final void setXYZInvisible(int x, int y, int z)
  553. {
  554. assert getWorldRegion() == null;
  555. if (x > L2World.MAP_MAX_X)
  556. {
  557. x = L2World.MAP_MAX_X - 5000;
  558. }
  559. if (x < L2World.MAP_MIN_X)
  560. {
  561. x = L2World.MAP_MIN_X + 5000;
  562. }
  563. if (y > L2World.MAP_MAX_Y)
  564. {
  565. y = L2World.MAP_MAX_Y - 5000;
  566. }
  567. if (y < L2World.MAP_MIN_Y)
  568. {
  569. y = L2World.MAP_MIN_Y + 5000;
  570. }
  571. setXYZ(x, y, z);
  572. this.setIsVisible(false);
  573. }
  574. public final void setLocationInvisible(Location loc)
  575. {
  576. setXYZInvisible(loc.getX(), loc.getY(), loc.getZ());
  577. }
  578. public void updateWorldRegion()
  579. {
  580. if (!this.isVisible())
  581. {
  582. return;
  583. }
  584. L2WorldRegion newRegion = L2World.getInstance().getRegion(getWorldPosition());
  585. if (newRegion != getWorldRegion())
  586. {
  587. getWorldRegion().removeVisibleObject(this);
  588. setWorldRegion(newRegion);
  589. // Add the L2Oject spawn to _visibleObjects and if necessary to _allplayers of its L2WorldRegion
  590. getWorldRegion().addVisibleObject(this);
  591. }
  592. }
  593. public final void setWorldPosition(Point3D newPosition)
  594. {
  595. setXYZ(newPosition.getX(), newPosition.getY(), newPosition.getZ());
  596. }
  597. public final L2WorldRegion getWorldRegion()
  598. {
  599. return _worldRegion;
  600. }
  601. public void setWorldRegion(L2WorldRegion value)
  602. {
  603. if ((getWorldRegion() != null) && isCharacter()) // confirm revalidation of old region's zones
  604. {
  605. if (value != null)
  606. {
  607. getWorldRegion().revalidateZones((L2Character) this); // at world region change
  608. }
  609. else
  610. {
  611. getWorldRegion().removeFromZones((L2Character) this); // at world region change
  612. }
  613. }
  614. _worldRegion = value;
  615. }
  616. @Override
  617. public String toString()
  618. {
  619. return (getClass().getSimpleName() + ":" + getName() + "[" + getObjectId() + "]");
  620. }
  621. }