TradeList.java 27 KB

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