ItemContainer.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  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.model.itemcontainer;
  16. import java.sql.Connection;
  17. import java.sql.PreparedStatement;
  18. import java.sql.ResultSet;
  19. import java.util.List;
  20. import java.util.logging.Level;
  21. import java.util.logging.Logger;
  22. import javolution.util.FastList;
  23. import net.sf.l2j.Config;
  24. import net.sf.l2j.L2DatabaseFactory;
  25. import net.sf.l2j.gameserver.GameTimeController;
  26. import net.sf.l2j.gameserver.datatables.ItemTable;
  27. import net.sf.l2j.gameserver.model.L2ItemInstance;
  28. import net.sf.l2j.gameserver.model.L2Object;
  29. import net.sf.l2j.gameserver.model.L2World;
  30. import net.sf.l2j.gameserver.model.L2ItemInstance.ItemLocation;
  31. import net.sf.l2j.gameserver.model.actor.L2Character;
  32. import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  33. import net.sf.l2j.gameserver.templates.item.L2Item;
  34. /**
  35. * @author Advi
  36. *
  37. */
  38. public abstract class ItemContainer
  39. {
  40. protected static final Logger _log = Logger.getLogger(ItemContainer.class.getName());
  41. protected final List<L2ItemInstance> _items;
  42. protected ItemContainer()
  43. {
  44. _items = new FastList<L2ItemInstance>();
  45. }
  46. protected abstract L2Character getOwner();
  47. protected abstract ItemLocation getBaseLocation();
  48. public String getName() { return "ItemContainer"; };
  49. /**
  50. * Returns the ownerID of the inventory
  51. * @return int
  52. */
  53. public int getOwnerId()
  54. {
  55. return getOwner() == null ? 0 : getOwner().getObjectId();
  56. }
  57. /**
  58. * Returns the quantity of items in the inventory
  59. * @return int
  60. */
  61. public int getSize()
  62. {
  63. return _items.size();
  64. }
  65. /**
  66. * Returns the list of items in inventory
  67. * @return L2ItemInstance : items in inventory
  68. */
  69. public L2ItemInstance[] getItems()
  70. {
  71. return _items.toArray(new L2ItemInstance[_items.size()]);
  72. }
  73. /**
  74. * Returns the item from inventory by using its <B>itemId</B><BR><BR>
  75. *
  76. * @param itemId : int designating the ID of the item
  77. * @return L2ItemInstance designating the item or null if not found in inventory
  78. */
  79. public L2ItemInstance getItemByItemId(int itemId)
  80. {
  81. for (L2ItemInstance item : _items)
  82. if (item != null && item.getItemId() == itemId)
  83. return item;
  84. return null;
  85. }
  86. /**
  87. * Returns the item's list from inventory by using its <B>itemId</B><BR><BR>
  88. *
  89. * @param itemId : int designating the ID of the item
  90. * @return List<L2ItemInstance> designating the items list (empty list if not found)
  91. */
  92. public List<L2ItemInstance> getItemsByItemId(int itemId)
  93. {
  94. List<L2ItemInstance> returnList = new FastList<L2ItemInstance>();
  95. for (L2ItemInstance item : _items)
  96. {
  97. if (item != null && item.getItemId() == itemId)
  98. {
  99. returnList.add(item);
  100. }
  101. }
  102. return returnList;
  103. }
  104. /**
  105. * Returns the item from inventory by using its <B>itemId</B><BR><BR>
  106. *
  107. * @param itemId : int designating the ID of the item
  108. * @param itemToIgnore : used during a loop, to avoid returning the same item
  109. * @return L2ItemInstance designating the item or null if not found in inventory
  110. */
  111. public L2ItemInstance getItemByItemId(int itemId, L2ItemInstance itemToIgnore)
  112. {
  113. for (L2ItemInstance item : _items)
  114. if (item != null && item.getItemId() == itemId && !item.equals(itemToIgnore))
  115. return item;
  116. return null;
  117. }
  118. /**
  119. * Returns item from inventory by using its <B>objectId</B>
  120. * @param objectId : int designating the ID of the object
  121. * @return L2ItemInstance designating the item or null if not found in inventory
  122. */
  123. public L2ItemInstance getItemByObjectId(int objectId)
  124. {
  125. for (L2ItemInstance item : _items)
  126. {
  127. if (item == null)
  128. continue;
  129. if (item.getObjectId() == objectId)
  130. return item;
  131. }
  132. return null;
  133. }
  134. /**
  135. * Gets count of item in the inventory
  136. * @param itemId : Item to look for
  137. * @param enchantLevel : enchant level to match on, or -1 for ANY enchant level
  138. * @return int corresponding to the number of items matching the above conditions.
  139. */
  140. public long getInventoryItemCount(int itemId, int enchantLevel)
  141. {
  142. long count = 0;
  143. for (L2ItemInstance item : _items)
  144. if (item.getItemId() == itemId && ((item.getEnchantLevel() == enchantLevel) || (enchantLevel < 0)))
  145. //if (item.isAvailable((L2PcInstance)getOwner(), true) || item.getItem().getType2() == 3)//available or quest item
  146. if (item.isStackable())
  147. count = item.getCount();
  148. else
  149. count++;
  150. return count;
  151. }
  152. /**
  153. * Adds item to inventory
  154. * @param process : String Identifier of process triggering this action
  155. * @param item : L2ItemInstance to be added
  156. * @param actor : L2PcInstance Player requesting the item add
  157. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  158. * @return L2ItemInstance corresponding to the new item or the updated item in inventory
  159. */
  160. public L2ItemInstance addItem(String process, L2ItemInstance item, L2PcInstance actor, L2Object reference)
  161. {
  162. L2ItemInstance olditem = getItemByItemId(item.getItemId());
  163. // If stackable item is found in inventory just add to current quantity
  164. if (olditem != null && olditem.isStackable())
  165. {
  166. long count = item.getCount();
  167. olditem.changeCount(process, count, actor, reference);
  168. olditem.setLastChange(L2ItemInstance.MODIFIED);
  169. // And destroys the item
  170. ItemTable.getInstance().destroyItem(process, item, actor, reference);
  171. item.updateDatabase();
  172. item = olditem;
  173. // Updates database
  174. if (item.getItemId() == 57 && count < 10000 * Config.RATE_DROP_ADENA)
  175. {
  176. // Small adena changes won't be saved to database all the time
  177. if (GameTimeController.getGameTicks() % 5 == 0)
  178. item.updateDatabase();
  179. }
  180. else
  181. item.updateDatabase();
  182. }
  183. // If item hasn't be found in inventory, create new one
  184. else
  185. {
  186. item.setOwnerId(process, getOwnerId(), actor, reference);
  187. item.setLocation(getBaseLocation());
  188. item.setLastChange((L2ItemInstance.ADDED));
  189. // Add item in inventory
  190. addItem(item);
  191. // Updates database
  192. item.updateDatabase();
  193. }
  194. refreshWeight();
  195. return item;
  196. }
  197. /**
  198. * Adds item to inventory
  199. * @param process : String Identifier of process triggering this action
  200. * @param itemId : int Item Identifier of the item to be added
  201. * @param count : int Quantity of items to be added
  202. * @param actor : L2PcInstance Player requesting the item add
  203. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  204. * @return L2ItemInstance corresponding to the new item or the updated item in inventory
  205. */
  206. public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, L2Object reference)
  207. {
  208. L2ItemInstance item = getItemByItemId(itemId);
  209. // If stackable item is found in inventory just add to current quantity
  210. if (item != null && item.isStackable())
  211. {
  212. item.changeCount(process, count, actor, reference);
  213. item.setLastChange(L2ItemInstance.MODIFIED);
  214. // Updates database
  215. if (itemId == 57 && count < 10000 * Config.RATE_DROP_ADENA)
  216. {
  217. // Small adena changes won't be saved to database all the time
  218. if (GameTimeController.getGameTicks() % 5 == 0)
  219. item.updateDatabase();
  220. }
  221. else
  222. item.updateDatabase();
  223. }
  224. // If item hasn't be found in inventory, create new one
  225. else
  226. {
  227. for (int i = 0; i < count; i++)
  228. {
  229. L2Item template = ItemTable.getInstance().getTemplate(itemId);
  230. if (template == null)
  231. {
  232. _log.log(Level.WARNING, (actor != null ? "[" + actor.getName() + "] " : "") + "Invalid ItemId requested: ", itemId);
  233. return null;
  234. }
  235. item = ItemTable.getInstance().createItem(process, itemId, template.isStackable() ? count : 1, actor, reference);
  236. item.setOwnerId(getOwnerId());
  237. item.setLocation(getBaseLocation());
  238. item.setLastChange(L2ItemInstance.ADDED);
  239. // Add item in inventory
  240. addItem(item);
  241. // Updates database
  242. item.updateDatabase();
  243. // If stackable, end loop as entire count is included in 1 instance of item
  244. if (template.isStackable() || !Config.MULTIPLE_ITEM_DROP)
  245. break;
  246. }
  247. }
  248. refreshWeight();
  249. return item;
  250. }
  251. /**
  252. * Adds Wear/Try On item to inventory<BR><BR>
  253. *
  254. * @param process : String Identifier of process triggering this action
  255. * @param itemId : int Item Identifier of the item to be added
  256. * @param actor : L2PcInstance Player requesting the item add
  257. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  258. * @return L2ItemInstance corresponding to the new weared item
  259. */
  260. public L2ItemInstance addWearItem(String process, int itemId, L2PcInstance actor, L2Object reference)
  261. {
  262. // Surch the item in the inventory of the player
  263. L2ItemInstance item = getItemByItemId(itemId);
  264. // There is such item already in inventory
  265. if (item != null)
  266. return item;
  267. // Create and Init the L2ItemInstance corresponding to the Item Identifier and quantity
  268. // Add the L2ItemInstance object to _allObjects of L2world
  269. item = ItemTable.getInstance().createItem(process, itemId, 1, actor, reference);
  270. // Set Item Properties
  271. item.setWear(true); // "Try On" Item -> Don't save it in database
  272. item.setOwnerId(getOwnerId());
  273. item.setLocation(getBaseLocation());
  274. item.setLastChange((L2ItemInstance.ADDED));
  275. // Add item in inventory and equip it if necessary (item location defined)
  276. addItem(item);
  277. // Calculate the weight loaded by player
  278. refreshWeight();
  279. return item;
  280. }
  281. /**
  282. * Transfers item to another inventory
  283. * @param process : String Identifier of process triggering this action
  284. * @param itemId : int Item Identifier of the item to be transfered
  285. * @param count : int Quantity of items to be transfered
  286. * @param actor : L2PcInstance Player requesting the item transfer
  287. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  288. * @return L2ItemInstance corresponding to the new item or the updated item in inventory
  289. */
  290. public L2ItemInstance transferItem(String process, int objectId, long count, ItemContainer target, L2PcInstance actor, L2Object reference)
  291. {
  292. if (target == null)
  293. {
  294. return null;
  295. }
  296. L2ItemInstance sourceitem = getItemByObjectId(objectId);
  297. if (sourceitem == null)
  298. {
  299. return null;
  300. }
  301. L2ItemInstance targetitem = sourceitem.isStackable() ? target.getItemByItemId(sourceitem.getItemId()) : null;
  302. synchronized (sourceitem)
  303. {
  304. // check if this item still present in this container
  305. if (getItemByObjectId(objectId) != sourceitem)
  306. {
  307. return null;
  308. }
  309. // Check if requested quantity is available
  310. if (count > sourceitem.getCount())
  311. count = sourceitem.getCount();
  312. // If possible, move entire item object
  313. if (sourceitem.getCount() == count && targetitem == null)
  314. {
  315. removeItem(sourceitem);
  316. target.addItem(process, sourceitem, actor, reference);
  317. targetitem = sourceitem;
  318. }
  319. else
  320. {
  321. if (sourceitem.getCount() > count) // If possible, only update counts
  322. {
  323. sourceitem.changeCount(process, -count, actor, reference);
  324. }
  325. else
  326. // Otherwise destroy old item
  327. {
  328. removeItem(sourceitem);
  329. ItemTable.getInstance().destroyItem(process, sourceitem, actor, reference);
  330. }
  331. if (targetitem != null) // If possible, only update counts
  332. {
  333. targetitem.changeCount(process, count, actor, reference);
  334. }
  335. else
  336. // Otherwise add new item
  337. {
  338. targetitem = target.addItem(process, sourceitem.getItemId(), count, actor, reference);
  339. }
  340. }
  341. // Updates database
  342. sourceitem.updateDatabase(true);
  343. if (targetitem != sourceitem && targetitem != null)
  344. targetitem.updateDatabase();
  345. if (sourceitem.isAugmented())
  346. sourceitem.getAugmentation().removeBonus(actor);
  347. refreshWeight();
  348. }
  349. return targetitem;
  350. }
  351. /**
  352. * Destroy item from inventory and updates database
  353. * @param process : String Identifier of process triggering this action
  354. * @param item : L2ItemInstance to be destroyed
  355. * @param actor : L2PcInstance Player requesting the item destroy
  356. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  357. * @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
  358. */
  359. public L2ItemInstance destroyItem(String process, L2ItemInstance item, L2PcInstance actor, L2Object reference)
  360. {
  361. return this.destroyItem(process, item, item.getCount(), actor, reference);
  362. }
  363. /**
  364. * Destroy item from inventory and updates database
  365. * @param process : String Identifier of process triggering this action
  366. * @param item : L2ItemInstance to be destroyed
  367. * @param actor : L2PcInstance Player requesting the item destroy
  368. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  369. * @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
  370. */
  371. public L2ItemInstance destroyItem(String process, L2ItemInstance item, long count, L2PcInstance actor, L2Object reference)
  372. {
  373. synchronized (item)
  374. {
  375. // Adjust item quantity
  376. if (item.getCount() > count)
  377. {
  378. item.changeCount(process, -count, actor, reference);
  379. item.setLastChange(L2ItemInstance.MODIFIED);
  380. // don't update often for untraced items
  381. if (process != null || GameTimeController.getGameTicks() % 10 == 0)
  382. {
  383. item.updateDatabase();
  384. }
  385. refreshWeight();
  386. return item;
  387. }
  388. else
  389. {
  390. if (item.getCount() < count)
  391. return null;
  392. boolean removed = this.removeItem(item);
  393. if (!removed)
  394. return null;
  395. ItemTable.getInstance().destroyItem(process, item, actor, reference);
  396. item.updateDatabase();
  397. refreshWeight();
  398. }
  399. }
  400. return item;
  401. }
  402. /**
  403. * Destroy item from inventory by using its <B>objectID</B> and updates database
  404. * @param process : String Identifier of process triggering this action
  405. * @param objectId : int Item Instance identifier of the item to be destroyed
  406. * @param count : int Quantity of items to be destroyed
  407. * @param actor : L2PcInstance Player requesting the item destroy
  408. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  409. * @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
  410. */
  411. public L2ItemInstance destroyItem(String process, int objectId, long count, L2PcInstance actor, L2Object reference)
  412. {
  413. L2ItemInstance item = getItemByObjectId(objectId);
  414. if (item == null)
  415. {
  416. return null;
  417. }
  418. return this.destroyItem(process, item, count, actor, reference);
  419. }
  420. /**
  421. * Destroy item from inventory by using its <B>itemId</B> and updates database
  422. * @param process : String Identifier of process triggering this action
  423. * @param itemId : int Item identifier of the item to be destroyed
  424. * @param count : int Quantity of items to be destroyed
  425. * @param actor : L2PcInstance Player requesting the item destroy
  426. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  427. * @return L2ItemInstance corresponding to the destroyed item or the updated item in inventory
  428. */
  429. public L2ItemInstance destroyItemByItemId(String process, int itemId, long count, L2PcInstance actor, L2Object reference)
  430. {
  431. L2ItemInstance item = getItemByItemId(itemId);
  432. if (item == null)
  433. {
  434. return null;
  435. }
  436. return this.destroyItem(process, item, count, actor, reference);
  437. }
  438. /**
  439. * Destroy all items from inventory and updates database
  440. * @param process : String Identifier of process triggering this action
  441. * @param actor : L2PcInstance Player requesting the item destroy
  442. * @param reference : L2Object Object referencing current action like NPC selling item or previous item in transformation
  443. */
  444. public synchronized void destroyAllItems(String process, L2PcInstance actor, L2Object reference)
  445. {
  446. for (L2ItemInstance item : _items)
  447. {
  448. if (item != null)
  449. destroyItem(process, item, actor, reference);
  450. }
  451. }
  452. /**
  453. * Get warehouse adena
  454. */
  455. public long getAdena()
  456. {
  457. long count = 0;
  458. for (L2ItemInstance item : _items)
  459. {
  460. if (item.getItemId() == 57)
  461. {
  462. count = item.getCount();
  463. return count;
  464. }
  465. }
  466. return count;
  467. }
  468. /**
  469. * Adds item to inventory for further adjustments.
  470. * @param item : L2ItemInstance to be added from inventory
  471. */
  472. protected void addItem(L2ItemInstance item)
  473. {
  474. _items.add(item);
  475. }
  476. /**
  477. * Removes item from inventory for further adjustments.
  478. * @param item : L2ItemInstance to be removed from inventory
  479. */
  480. protected boolean removeItem(L2ItemInstance item)
  481. {
  482. return _items.remove(item);
  483. }
  484. /**
  485. * Refresh the weight of equipment loaded
  486. */
  487. protected void refreshWeight()
  488. {
  489. }
  490. /**
  491. * Delete item object from world
  492. */
  493. public void deleteMe()
  494. {
  495. try
  496. {
  497. updateDatabase();
  498. }
  499. catch (Exception e)
  500. {
  501. _log.log(Level.SEVERE, "deletedMe()", e);
  502. }
  503. List<L2Object> items = new FastList<L2Object>(_items);
  504. _items.clear();
  505. L2World.getInstance().removeObjects(items);
  506. }
  507. /**
  508. * Update database with items in inventory
  509. */
  510. public void updateDatabase()
  511. {
  512. if (getOwner() != null)
  513. {
  514. for (L2ItemInstance item : _items)
  515. {
  516. if (item != null)
  517. {
  518. item.updateDatabase(true);
  519. }
  520. }
  521. }
  522. }
  523. /**
  524. * Get back items in container from database
  525. */
  526. public void restore()
  527. {
  528. Connection con = null;
  529. try
  530. {
  531. con = L2DatabaseFactory.getInstance().getConnection();
  532. PreparedStatement statement = con.prepareStatement("SELECT object_id, item_id, count, enchant_level, loc, loc_data, custom_type1, custom_type2, mana_left, time FROM items WHERE owner_id=? AND (loc=?)");
  533. statement.setInt(1, getOwnerId());
  534. statement.setString(2, getBaseLocation().name());
  535. ResultSet inv = statement.executeQuery();
  536. L2ItemInstance item;
  537. while (inv.next())
  538. {
  539. item = L2ItemInstance.restoreFromDb(getOwnerId(), inv);
  540. if (item == null)
  541. continue;
  542. L2World.getInstance().storeObject(item);
  543. // If stackable item is found in inventory just add to current quantity
  544. if (item.isStackable() && getItemByItemId(item.getItemId()) != null)
  545. addItem("Restore", item, getOwner().getActingPlayer(), null);
  546. else
  547. addItem(item);
  548. }
  549. inv.close();
  550. statement.close();
  551. refreshWeight();
  552. }
  553. catch (Exception e)
  554. {
  555. _log.log(Level.WARNING, "could not restore container:", e);
  556. }
  557. finally
  558. {
  559. try
  560. {
  561. con.close();
  562. }
  563. catch (Exception e)
  564. {
  565. }
  566. }
  567. }
  568. public boolean validateCapacity(int slots)
  569. {
  570. return true;
  571. }
  572. public boolean validateWeight(int weight)
  573. {
  574. return true;
  575. }
  576. }