TradeList.java 28 KB

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