TradeList.java 27 KB

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