ItemContainer.java 21 KB

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