TradeList.java 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. /*
  2. * Copyright (C) 2004-2015 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 static com.l2jserver.gameserver.model.itemcontainer.Inventory.MAX_ADENA;
  21. import java.util.LinkedList;
  22. import java.util.List;
  23. import java.util.Set;
  24. import java.util.concurrent.CopyOnWriteArrayList;
  25. import java.util.logging.Logger;
  26. import com.l2jserver.Config;
  27. import com.l2jserver.gameserver.datatables.ItemTable;
  28. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  29. import com.l2jserver.gameserver.model.itemcontainer.Inventory;
  30. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  31. import com.l2jserver.gameserver.model.items.L2Item;
  32. import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
  33. import com.l2jserver.gameserver.network.SystemMessageId;
  34. import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate;
  35. import com.l2jserver.gameserver.network.serverpackets.ItemList;
  36. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  37. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  38. import com.l2jserver.gameserver.util.Util;
  39. /**
  40. * @author Advi
  41. */
  42. public class TradeList
  43. {
  44. private static final Logger _log = Logger.getLogger(TradeList.class.getName());
  45. private final L2PcInstance _owner;
  46. private L2PcInstance _partner;
  47. private final List<TradeItem> _items = new CopyOnWriteArrayList<>();
  48. private String _title;
  49. private boolean _packaged;
  50. private boolean _confirmed = false;
  51. private boolean _locked = false;
  52. public TradeList(L2PcInstance owner)
  53. {
  54. _owner = owner;
  55. }
  56. public L2PcInstance getOwner()
  57. {
  58. return _owner;
  59. }
  60. public void setPartner(L2PcInstance partner)
  61. {
  62. _partner = partner;
  63. }
  64. public L2PcInstance getPartner()
  65. {
  66. return _partner;
  67. }
  68. public void setTitle(String title)
  69. {
  70. _title = title;
  71. }
  72. public String getTitle()
  73. {
  74. return _title;
  75. }
  76. public boolean isLocked()
  77. {
  78. return _locked;
  79. }
  80. public boolean isConfirmed()
  81. {
  82. return _confirmed;
  83. }
  84. public boolean isPackaged()
  85. {
  86. return _packaged;
  87. }
  88. public void setPackaged(boolean value)
  89. {
  90. _packaged = value;
  91. }
  92. /**
  93. * @return all items from TradeList
  94. */
  95. public TradeItem[] getItems()
  96. {
  97. return _items.toArray(new TradeItem[_items.size()]);
  98. }
  99. /**
  100. * Returns the list of items in inventory available for transaction
  101. * @param inventory
  102. * @return L2ItemInstance : items in inventory
  103. */
  104. public List<TradeItem> getAvailableItems(PcInventory inventory)
  105. {
  106. final List<TradeItem> list = new LinkedList<>();
  107. for (TradeItem item : _items)
  108. {
  109. item = new TradeItem(item, item.getCount(), item.getPrice());
  110. inventory.adjustAvailableItem(item);
  111. list.add(item);
  112. }
  113. return list;
  114. }
  115. /**
  116. * @return Item List size
  117. */
  118. public int getItemCount()
  119. {
  120. return _items.size();
  121. }
  122. /**
  123. * Adjust available item from Inventory by the one in this list
  124. * @param item : L2ItemInstance to be adjusted
  125. * @return TradeItem representing adjusted item
  126. */
  127. public TradeItem adjustAvailableItem(L2ItemInstance item)
  128. {
  129. if (item.isStackable())
  130. {
  131. for (TradeItem exclItem : _items)
  132. {
  133. if (exclItem.getItem().getId() == item.getId())
  134. {
  135. if (item.getCount() <= exclItem.getCount())
  136. {
  137. return null;
  138. }
  139. return new TradeItem(item, item.getCount() - exclItem.getCount(), item.getReferencePrice());
  140. }
  141. }
  142. }
  143. return new TradeItem(item, item.getCount(), item.getReferencePrice());
  144. }
  145. /**
  146. * Adjust ItemRequest by corresponding item in this list using its <b>ObjectId</b>
  147. * @param item : ItemRequest to be adjusted
  148. */
  149. public void adjustItemRequest(ItemRequest item)
  150. {
  151. for (TradeItem filtItem : _items)
  152. {
  153. if (filtItem.getObjectId() == item.getObjectId())
  154. {
  155. if (filtItem.getCount() < item.getCount())
  156. {
  157. item.setCount(filtItem.getCount());
  158. }
  159. return;
  160. }
  161. }
  162. item.setCount(0);
  163. }
  164. /**
  165. * Add simplified item to TradeList
  166. * @param objectId : int
  167. * @param count : int
  168. * @return
  169. */
  170. public TradeItem addItem(int objectId, long count)
  171. {
  172. return addItem(objectId, count, 0);
  173. }
  174. /**
  175. * Add item to TradeList
  176. * @param objectId : int
  177. * @param count : long
  178. * @param price : long
  179. * @return
  180. */
  181. public synchronized TradeItem addItem(int objectId, long count, long price)
  182. {
  183. if (isLocked())
  184. {
  185. _log.warning(_owner.getName() + ": Attempt to modify locked TradeList!");
  186. return null;
  187. }
  188. L2Object o = L2World.getInstance().findObject(objectId);
  189. if (!(o instanceof L2ItemInstance))
  190. {
  191. _log.warning(_owner.getName() + ": Trying to add something other than an item!");
  192. return null;
  193. }
  194. L2ItemInstance item = (L2ItemInstance) o;
  195. if (!(item.isTradeable() || (getOwner().isGM() && Config.GM_TRADE_RESTRICTED_ITEMS)) || item.isQuestItem())
  196. {
  197. _log.warning(_owner.getName() + ": Attempt to add a restricted item!");
  198. return null;
  199. }
  200. if (!getOwner().getInventory().canManipulateWithItemId(item.getId()))
  201. {
  202. _log.warning(_owner.getName() + ": Attempt to add an item that can't manipualte!");
  203. return null;
  204. }
  205. if ((count <= 0) || (count > item.getCount()))
  206. {
  207. _log.warning(_owner.getName() + ": Attempt to add an item with invalid item count!");
  208. return null;
  209. }
  210. if (!item.isStackable() && (count > 1))
  211. {
  212. _log.warning(_owner.getName() + ": Attempt to add non-stackable item to TradeList with count > 1!");
  213. return null;
  214. }
  215. if ((Inventory.MAX_ADENA / count) < price)
  216. {
  217. _log.warning(_owner.getName() + ": Attempt to overflow adena !");
  218. return null;
  219. }
  220. for (TradeItem checkitem : _items)
  221. {
  222. if (checkitem.getObjectId() == objectId)
  223. {
  224. _log.warning(_owner.getName() + ": Attempt to add an item that is already present!");
  225. return null;
  226. }
  227. }
  228. TradeItem titem = new TradeItem(item, count, price);
  229. _items.add(titem);
  230. // If Player has already confirmed this trade, invalidate the confirmation
  231. invalidateConfirmation();
  232. return titem;
  233. }
  234. /**
  235. * Add item to TradeList
  236. * @param itemId
  237. * @param count
  238. * @param price
  239. * @return
  240. */
  241. public synchronized TradeItem addItemByItemId(int itemId, long count, long price)
  242. {
  243. if (isLocked())
  244. {
  245. _log.warning(_owner.getName() + ": Attempt to modify locked TradeList!");
  246. return null;
  247. }
  248. L2Item item = ItemTable.getInstance().getTemplate(itemId);
  249. if (item == null)
  250. {
  251. _log.warning(_owner.getName() + ": Attempt to add invalid item to TradeList!");
  252. return null;
  253. }
  254. if (!item.isTradeable() || item.isQuestItem())
  255. {
  256. return null;
  257. }
  258. if (!item.isStackable() && (count > 1))
  259. {
  260. _log.warning(_owner.getName() + ": Attempt to add non-stackable item to TradeList with count > 1!");
  261. return null;
  262. }
  263. if ((Inventory.MAX_ADENA / count) < price)
  264. {
  265. _log.warning(_owner.getName() + ": Attempt to overflow adena !");
  266. return null;
  267. }
  268. TradeItem titem = new TradeItem(item, count, price);
  269. _items.add(titem);
  270. // If Player has already confirmed this trade, invalidate the confirmation
  271. invalidateConfirmation();
  272. return titem;
  273. }
  274. /**
  275. * Remove item from TradeList
  276. * @param objectId : int
  277. * @param itemId
  278. * @param count : int
  279. * @return
  280. */
  281. public synchronized TradeItem removeItem(int objectId, int itemId, long count)
  282. {
  283. if (isLocked())
  284. {
  285. _log.warning(_owner.getName() + ": Attempt to modify locked TradeList!");
  286. return null;
  287. }
  288. for (TradeItem titem : _items)
  289. {
  290. if ((titem.getObjectId() == objectId) || (titem.getItem().getId() == itemId))
  291. {
  292. // If Partner has already confirmed this trade, invalidate the confirmation
  293. if (_partner != null)
  294. {
  295. TradeList partnerList = _partner.getActiveTradeList();
  296. if (partnerList == null)
  297. {
  298. _log.warning(_partner.getName() + ": Trading partner (" + _partner.getName() + ") is invalid in this trade!");
  299. return null;
  300. }
  301. partnerList.invalidateConfirmation();
  302. }
  303. // Reduce item count or complete item
  304. if ((count != -1) && (titem.getCount() > count))
  305. {
  306. titem.setCount(titem.getCount() - count);
  307. }
  308. else
  309. {
  310. _items.remove(titem);
  311. }
  312. return titem;
  313. }
  314. }
  315. return null;
  316. }
  317. /**
  318. * Update items in TradeList according their quantity in owner inventory
  319. */
  320. public synchronized void updateItems()
  321. {
  322. for (TradeItem titem : _items)
  323. {
  324. L2ItemInstance item = _owner.getInventory().getItemByObjectId(titem.getObjectId());
  325. if ((item == null) || (titem.getCount() < 1))
  326. {
  327. removeItem(titem.getObjectId(), -1, -1);
  328. }
  329. else if (item.getCount() < titem.getCount())
  330. {
  331. titem.setCount(item.getCount());
  332. }
  333. }
  334. }
  335. /**
  336. * Lockes TradeList, no further changes are allowed
  337. */
  338. public void lock()
  339. {
  340. _locked = true;
  341. }
  342. /**
  343. * Clears item list
  344. */
  345. public synchronized void clear()
  346. {
  347. _items.clear();
  348. _locked = false;
  349. }
  350. /**
  351. * Confirms TradeList
  352. * @return : boolean
  353. */
  354. public boolean confirm()
  355. {
  356. if (_confirmed)
  357. {
  358. return true; // Already confirmed
  359. }
  360. // If Partner has already confirmed this trade, proceed exchange
  361. if (_partner != null)
  362. {
  363. TradeList partnerList = _partner.getActiveTradeList();
  364. if (partnerList == null)
  365. {
  366. _log.warning(_partner.getName() + ": Trading partner (" + _partner.getName() + ") is invalid in this trade!");
  367. return false;
  368. }
  369. // Synchronization order to avoid deadlock
  370. TradeList sync1, sync2;
  371. if (getOwner().getObjectId() > partnerList.getOwner().getObjectId())
  372. {
  373. sync1 = partnerList;
  374. sync2 = this;
  375. }
  376. else
  377. {
  378. sync1 = this;
  379. sync2 = partnerList;
  380. }
  381. synchronized (sync1)
  382. {
  383. synchronized (sync2)
  384. {
  385. _confirmed = true;
  386. if (partnerList.isConfirmed())
  387. {
  388. partnerList.lock();
  389. lock();
  390. if (!partnerList.validate())
  391. {
  392. return false;
  393. }
  394. if (!validate())
  395. {
  396. return false;
  397. }
  398. doExchange(partnerList);
  399. }
  400. else
  401. {
  402. _partner.onTradeConfirm(_owner);
  403. }
  404. }
  405. }
  406. }
  407. else
  408. {
  409. _confirmed = true;
  410. }
  411. return _confirmed;
  412. }
  413. /**
  414. * Cancels TradeList confirmation
  415. */
  416. public void invalidateConfirmation()
  417. {
  418. _confirmed = false;
  419. }
  420. /**
  421. * Validates TradeList with owner inventory
  422. * @return
  423. */
  424. private boolean validate()
  425. {
  426. // Check for Owner validity
  427. if ((_owner == null) || (L2World.getInstance().getPlayer(_owner.getObjectId()) == null))
  428. {
  429. _log.warning("Invalid owner of TradeList");
  430. return false;
  431. }
  432. // Check for Item validity
  433. for (TradeItem titem : _items)
  434. {
  435. L2ItemInstance item = _owner.checkItemManipulation(titem.getObjectId(), titem.getCount(), "transfer");
  436. if ((item == null) || (item.getCount() < 1))
  437. {
  438. _log.warning(_owner.getName() + ": Invalid Item in TradeList");
  439. return false;
  440. }
  441. }
  442. return true;
  443. }
  444. /**
  445. * Transfers all TradeItems from inventory to partner
  446. * @param partner
  447. * @param ownerIU
  448. * @param partnerIU
  449. * @return
  450. */
  451. private boolean TransferItems(L2PcInstance partner, InventoryUpdate ownerIU, InventoryUpdate partnerIU)
  452. {
  453. for (TradeItem titem : _items)
  454. {
  455. L2ItemInstance oldItem = _owner.getInventory().getItemByObjectId(titem.getObjectId());
  456. if (oldItem == null)
  457. {
  458. return false;
  459. }
  460. L2ItemInstance newItem = _owner.getInventory().transferItem("Trade", titem.getObjectId(), titem.getCount(), partner.getInventory(), _owner, _partner);
  461. if (newItem == null)
  462. {
  463. return false;
  464. }
  465. // Add changes to inventory update packets
  466. if (ownerIU != null)
  467. {
  468. if ((oldItem.getCount() > 0) && (oldItem != newItem))
  469. {
  470. ownerIU.addModifiedItem(oldItem);
  471. }
  472. else
  473. {
  474. ownerIU.addRemovedItem(oldItem);
  475. }
  476. }
  477. if (partnerIU != null)
  478. {
  479. if (newItem.getCount() > titem.getCount())
  480. {
  481. partnerIU.addModifiedItem(newItem);
  482. }
  483. else
  484. {
  485. partnerIU.addNewItem(newItem);
  486. }
  487. }
  488. }
  489. return true;
  490. }
  491. /**
  492. * @param partner
  493. * @return items slots count
  494. */
  495. public int countItemsSlots(L2PcInstance partner)
  496. {
  497. int slots = 0;
  498. for (TradeItem item : _items)
  499. {
  500. if (item == null)
  501. {
  502. continue;
  503. }
  504. L2Item template = ItemTable.getInstance().getTemplate(item.getItem().getId());
  505. if (template == null)
  506. {
  507. continue;
  508. }
  509. if (!template.isStackable())
  510. {
  511. slots += item.getCount();
  512. }
  513. else if (partner.getInventory().getItemByItemId(item.getItem().getId()) == null)
  514. {
  515. slots++;
  516. }
  517. }
  518. return slots;
  519. }
  520. /**
  521. * @return the weight of items in tradeList
  522. */
  523. public int calcItemsWeight()
  524. {
  525. long weight = 0;
  526. for (TradeItem item : _items)
  527. {
  528. if (item == null)
  529. {
  530. continue;
  531. }
  532. L2Item template = ItemTable.getInstance().getTemplate(item.getItem().getId());
  533. if (template == null)
  534. {
  535. continue;
  536. }
  537. weight += item.getCount() * template.getWeight();
  538. }
  539. return (int) Math.min(weight, Integer.MAX_VALUE);
  540. }
  541. /**
  542. * Proceeds with trade
  543. * @param partnerList
  544. */
  545. private void doExchange(TradeList partnerList)
  546. {
  547. boolean success = false;
  548. // check weight and slots
  549. if ((!getOwner().getInventory().validateWeight(partnerList.calcItemsWeight())) || !(partnerList.getOwner().getInventory().validateWeight(calcItemsWeight())))
  550. {
  551. partnerList.getOwner().sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED);
  552. getOwner().sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED);
  553. }
  554. else if ((!getOwner().getInventory().validateCapacity(partnerList.countItemsSlots(getOwner()))) || (!partnerList.getOwner().getInventory().validateCapacity(countItemsSlots(partnerList.getOwner()))))
  555. {
  556. partnerList.getOwner().sendPacket(SystemMessageId.SLOTS_FULL);
  557. getOwner().sendPacket(SystemMessageId.SLOTS_FULL);
  558. }
  559. else
  560. {
  561. // Prepare inventory update packet
  562. InventoryUpdate ownerIU = Config.FORCE_INVENTORY_UPDATE ? null : new InventoryUpdate();
  563. InventoryUpdate partnerIU = Config.FORCE_INVENTORY_UPDATE ? null : new InventoryUpdate();
  564. // Transfer items
  565. partnerList.TransferItems(getOwner(), partnerIU, ownerIU);
  566. TransferItems(partnerList.getOwner(), ownerIU, partnerIU);
  567. // Send inventory update packet
  568. if (ownerIU != null)
  569. {
  570. _owner.sendPacket(ownerIU);
  571. }
  572. else
  573. {
  574. _owner.sendPacket(new ItemList(_owner, false));
  575. }
  576. if (partnerIU != null)
  577. {
  578. _partner.sendPacket(partnerIU);
  579. }
  580. else
  581. {
  582. _partner.sendPacket(new ItemList(_partner, false));
  583. }
  584. // Update current load as well
  585. StatusUpdate playerSU = new StatusUpdate(_owner);
  586. playerSU.addAttribute(StatusUpdate.CUR_LOAD, _owner.getCurrentLoad());
  587. _owner.sendPacket(playerSU);
  588. playerSU = new StatusUpdate(_partner);
  589. playerSU.addAttribute(StatusUpdate.CUR_LOAD, _partner.getCurrentLoad());
  590. _partner.sendPacket(playerSU);
  591. success = true;
  592. }
  593. // Finish the trade
  594. partnerList.getOwner().onTradeFinish(success);
  595. getOwner().onTradeFinish(success);
  596. }
  597. /**
  598. * Buy items from this PrivateStore list
  599. * @param player
  600. * @param items
  601. * @return int: result of trading. 0 - ok, 1 - canceled (no adena), 2 - failed (item error)
  602. */
  603. public synchronized int privateStoreBuy(L2PcInstance player, Set<ItemRequest> items)
  604. {
  605. if (_locked)
  606. {
  607. return 1;
  608. }
  609. if (!validate())
  610. {
  611. lock();
  612. return 1;
  613. }
  614. if (!_owner.isOnline() || !player.isOnline())
  615. {
  616. return 1;
  617. }
  618. int slots = 0;
  619. int weight = 0;
  620. long totalPrice = 0;
  621. final PcInventory ownerInventory = _owner.getInventory();
  622. final PcInventory playerInventory = player.getInventory();
  623. for (ItemRequest item : items)
  624. {
  625. boolean found = false;
  626. for (TradeItem ti : _items)
  627. {
  628. if (ti.getObjectId() == item.getObjectId())
  629. {
  630. if (ti.getPrice() == item.getPrice())
  631. {
  632. if (ti.getCount() < item.getCount())
  633. {
  634. item.setCount(ti.getCount());
  635. }
  636. found = true;
  637. }
  638. break;
  639. }
  640. }
  641. // item with this objectId and price not found in tradelist
  642. if (!found)
  643. {
  644. if (isPackaged())
  645. {
  646. Util.handleIllegalPlayerAction(player, "[TradeList.privateStoreBuy()] Player " + player.getName() + " tried to cheat the package sell and buy only a part of the package! Ban this player for bot usage!", Config.DEFAULT_PUNISH);
  647. return 2;
  648. }
  649. item.setCount(0);
  650. continue;
  651. }
  652. // check for overflow in the single item
  653. if ((MAX_ADENA / item.getCount()) < item.getPrice())
  654. {
  655. // private store attempting to overflow - disable it
  656. lock();
  657. return 1;
  658. }
  659. totalPrice += item.getCount() * item.getPrice();
  660. // check for overflow of the total price
  661. if ((MAX_ADENA < totalPrice) || (totalPrice < 0))
  662. {
  663. // private store attempting to overflow - disable it
  664. lock();
  665. return 1;
  666. }
  667. // Check if requested item is available for manipulation
  668. L2ItemInstance oldItem = _owner.checkItemManipulation(item.getObjectId(), item.getCount(), "sell");
  669. if ((oldItem == null) || !oldItem.isTradeable())
  670. {
  671. // private store sell invalid item - disable it
  672. lock();
  673. return 2;
  674. }
  675. L2Item template = ItemTable.getInstance().getTemplate(item.getItemId());
  676. if (template == null)
  677. {
  678. continue;
  679. }
  680. weight += item.getCount() * template.getWeight();
  681. if (!template.isStackable())
  682. {
  683. slots += item.getCount();
  684. }
  685. else if (playerInventory.getItemByItemId(item.getItemId()) == null)
  686. {
  687. slots++;
  688. }
  689. }
  690. if (totalPrice > playerInventory.getAdena())
  691. {
  692. player.sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
  693. return 1;
  694. }
  695. if (!playerInventory.validateWeight(weight))
  696. {
  697. player.sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED);
  698. return 1;
  699. }
  700. if (!playerInventory.validateCapacity(slots))
  701. {
  702. player.sendPacket(SystemMessageId.SLOTS_FULL);
  703. return 1;
  704. }
  705. // Prepare inventory update packets
  706. final InventoryUpdate ownerIU = new InventoryUpdate();
  707. final InventoryUpdate playerIU = new InventoryUpdate();
  708. final L2ItemInstance adenaItem = playerInventory.getAdenaInstance();
  709. if (!playerInventory.reduceAdena("PrivateStore", totalPrice, player, _owner))
  710. {
  711. player.sendPacket(SystemMessageId.YOU_NOT_ENOUGH_ADENA);
  712. return 1;
  713. }
  714. playerIU.addItem(adenaItem);
  715. ownerInventory.addAdena("PrivateStore", totalPrice, _owner, player);
  716. // ownerIU.addItem(ownerInventory.getAdenaInstance());
  717. boolean ok = true;
  718. // Transfer items
  719. for (ItemRequest item : items)
  720. {
  721. if (item.getCount() == 0)
  722. {
  723. continue;
  724. }
  725. // Check if requested item is available for manipulation
  726. L2ItemInstance oldItem = _owner.checkItemManipulation(item.getObjectId(), item.getCount(), "sell");
  727. if (oldItem == null)
  728. {
  729. // should not happens - validation already done
  730. lock();
  731. ok = false;
  732. break;
  733. }
  734. // Proceed with item transfer
  735. L2ItemInstance newItem = ownerInventory.transferItem("PrivateStore", item.getObjectId(), item.getCount(), playerInventory, _owner, player);
  736. if (newItem == null)
  737. {
  738. ok = false;
  739. break;
  740. }
  741. removeItem(item.getObjectId(), -1, item.getCount());
  742. // Add changes to inventory update packets
  743. if ((oldItem.getCount() > 0) && (oldItem != newItem))
  744. {
  745. ownerIU.addModifiedItem(oldItem);
  746. }
  747. else
  748. {
  749. ownerIU.addRemovedItem(oldItem);
  750. }
  751. if (newItem.getCount() > item.getCount())
  752. {
  753. playerIU.addModifiedItem(newItem);
  754. }
  755. else
  756. {
  757. playerIU.addNewItem(newItem);
  758. }
  759. // Send messages about the transaction to both players
  760. if (newItem.isStackable())
  761. {
  762. SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_PURCHASED_S3_S2_S);
  763. msg.addString(player.getName());
  764. msg.addItemName(newItem);
  765. msg.addLong(item.getCount());
  766. _owner.sendPacket(msg);
  767. msg = SystemMessage.getSystemMessage(SystemMessageId.PURCHASED_S3_S2_S_FROM_C1);
  768. msg.addString(_owner.getName());
  769. msg.addItemName(newItem);
  770. msg.addLong(item.getCount());
  771. player.sendPacket(msg);
  772. }
  773. else
  774. {
  775. SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_PURCHASED_S2);
  776. msg.addString(player.getName());
  777. msg.addItemName(newItem);
  778. _owner.sendPacket(msg);
  779. msg = SystemMessage.getSystemMessage(SystemMessageId.PURCHASED_S2_FROM_C1);
  780. msg.addString(_owner.getName());
  781. msg.addItemName(newItem);
  782. player.sendPacket(msg);
  783. }
  784. }
  785. // Send inventory update packet
  786. _owner.sendPacket(ownerIU);
  787. player.sendPacket(playerIU);
  788. if (ok)
  789. {
  790. return 0;
  791. }
  792. return 2;
  793. }
  794. /**
  795. * Sell items to this PrivateStore list
  796. * @param player
  797. * @param items
  798. * @return : boolean true if success
  799. */
  800. public synchronized boolean privateStoreSell(L2PcInstance player, ItemRequest[] items)
  801. {
  802. if (_locked)
  803. {
  804. return false;
  805. }
  806. if (!_owner.isOnline() || !player.isOnline())
  807. {
  808. return false;
  809. }
  810. boolean ok = false;
  811. final PcInventory ownerInventory = _owner.getInventory();
  812. final PcInventory playerInventory = player.getInventory();
  813. // Prepare inventory update packet
  814. final InventoryUpdate ownerIU = new InventoryUpdate();
  815. final InventoryUpdate playerIU = new InventoryUpdate();
  816. long totalPrice = 0;
  817. for (ItemRequest item : items)
  818. {
  819. // searching item in tradelist using itemId
  820. boolean found = false;
  821. for (TradeItem ti : _items)
  822. {
  823. if (ti.getItem().getId() == item.getItemId())
  824. {
  825. // price should be the same
  826. if (ti.getPrice() == item.getPrice())
  827. {
  828. // if requesting more than available - decrease count
  829. if (ti.getCount() < item.getCount())
  830. {
  831. item.setCount(ti.getCount());
  832. }
  833. found = item.getCount() > 0;
  834. }
  835. break;
  836. }
  837. }
  838. // not found any item in the tradelist with same itemId and price
  839. // maybe another player already sold this item ?
  840. if (!found)
  841. {
  842. continue;
  843. }
  844. // check for overflow in the single item
  845. if ((MAX_ADENA / item.getCount()) < item.getPrice())
  846. {
  847. lock();
  848. break;
  849. }
  850. long _totalPrice = totalPrice + (item.getCount() * item.getPrice());
  851. // check for overflow of the total price
  852. if ((MAX_ADENA < _totalPrice) || (_totalPrice < 0))
  853. {
  854. lock();
  855. break;
  856. }
  857. if (ownerInventory.getAdena() < _totalPrice)
  858. {
  859. continue;
  860. }
  861. // Check if requested item is available for manipulation
  862. int objectId = item.getObjectId();
  863. L2ItemInstance oldItem = player.checkItemManipulation(objectId, item.getCount(), "sell");
  864. // private store - buy use same objectId for buying several non-stackable items
  865. if (oldItem == null)
  866. {
  867. // searching other items using same itemId
  868. oldItem = playerInventory.getItemByItemId(item.getItemId());
  869. if (oldItem == null)
  870. {
  871. continue;
  872. }
  873. objectId = oldItem.getObjectId();
  874. oldItem = player.checkItemManipulation(objectId, item.getCount(), "sell");
  875. if (oldItem == null)
  876. {
  877. continue;
  878. }
  879. }
  880. if (oldItem.getId() != item.getItemId())
  881. {
  882. Util.handleIllegalPlayerAction(player, player + " is cheating with sell items", Config.DEFAULT_PUNISH);
  883. return false;
  884. }
  885. if (!oldItem.isTradeable())
  886. {
  887. continue;
  888. }
  889. // Proceed with item transfer
  890. L2ItemInstance newItem = playerInventory.transferItem("PrivateStore", objectId, item.getCount(), ownerInventory, player, _owner);
  891. if (newItem == null)
  892. {
  893. continue;
  894. }
  895. removeItem(-1, item.getItemId(), item.getCount());
  896. ok = true;
  897. // increase total price only after successful transaction
  898. totalPrice = _totalPrice;
  899. // Add changes to inventory update packets
  900. if ((oldItem.getCount() > 0) && (oldItem != newItem))
  901. {
  902. playerIU.addModifiedItem(oldItem);
  903. }
  904. else
  905. {
  906. playerIU.addRemovedItem(oldItem);
  907. }
  908. if (newItem.getCount() > item.getCount())
  909. {
  910. ownerIU.addModifiedItem(newItem);
  911. }
  912. else
  913. {
  914. ownerIU.addNewItem(newItem);
  915. }
  916. // Send messages about the transaction to both players
  917. if (newItem.isStackable())
  918. {
  919. SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.PURCHASED_S3_S2_S_FROM_C1);
  920. msg.addString(player.getName());
  921. msg.addItemName(newItem);
  922. msg.addLong(item.getCount());
  923. _owner.sendPacket(msg);
  924. msg = SystemMessage.getSystemMessage(SystemMessageId.C1_PURCHASED_S3_S2_S);
  925. msg.addString(_owner.getName());
  926. msg.addItemName(newItem);
  927. msg.addLong(item.getCount());
  928. player.sendPacket(msg);
  929. }
  930. else
  931. {
  932. SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.PURCHASED_S2_FROM_C1);
  933. msg.addString(player.getName());
  934. msg.addItemName(newItem);
  935. _owner.sendPacket(msg);
  936. msg = SystemMessage.getSystemMessage(SystemMessageId.C1_PURCHASED_S2);
  937. msg.addString(_owner.getName());
  938. msg.addItemName(newItem);
  939. player.sendPacket(msg);
  940. }
  941. }
  942. if (totalPrice > 0)
  943. {
  944. // Transfer adena
  945. if (totalPrice > ownerInventory.getAdena())
  946. {
  947. // should not happens, just a precaution
  948. return false;
  949. }
  950. final L2ItemInstance adenaItem = ownerInventory.getAdenaInstance();
  951. ownerInventory.reduceAdena("PrivateStore", totalPrice, _owner, player);
  952. ownerIU.addItem(adenaItem);
  953. playerInventory.addAdena("PrivateStore", totalPrice, player, _owner);
  954. playerIU.addItem(playerInventory.getAdenaInstance());
  955. }
  956. if (ok)
  957. {
  958. // Send inventory update packet
  959. _owner.sendPacket(ownerIU);
  960. player.sendPacket(playerIU);
  961. }
  962. return ok;
  963. }
  964. }