MultiSellChoose.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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.network.clientpackets;
  16. import java.util.logging.Logger;
  17. import com.l2jserver.Config;
  18. import com.l2jserver.gameserver.datatables.ItemTable;
  19. import com.l2jserver.gameserver.model.Elementals;
  20. import com.l2jserver.gameserver.model.L2Augmentation;
  21. import com.l2jserver.gameserver.model.L2ItemInstance;
  22. import com.l2jserver.gameserver.model.L2Multisell;
  23. import com.l2jserver.gameserver.model.L2Object;
  24. import com.l2jserver.gameserver.model.L2Multisell.MultiSellEntry;
  25. import com.l2jserver.gameserver.model.L2Multisell.MultiSellIngredient;
  26. import com.l2jserver.gameserver.model.L2Multisell.MultiSellListContainer;
  27. import com.l2jserver.gameserver.model.actor.L2Npc;
  28. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  29. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  30. import com.l2jserver.gameserver.network.SystemMessageId;
  31. import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
  32. import com.l2jserver.gameserver.network.serverpackets.ItemList;
  33. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  34. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  35. import com.l2jserver.gameserver.network.serverpackets.UserInfo;
  36. import com.l2jserver.gameserver.templates.item.L2Armor;
  37. import com.l2jserver.gameserver.templates.item.L2Item;
  38. import com.l2jserver.gameserver.templates.item.L2Weapon;
  39. import javolution.util.FastList;
  40. /**
  41. * The Class MultiSellChoose.
  42. */
  43. public class MultiSellChoose extends L2GameClientPacket
  44. {
  45. private static final String _C__A7_MULTISELLCHOOSE = "[C] A7 MultiSellChoose";
  46. private static Logger _log = Logger.getLogger(MultiSellChoose.class.getName());
  47. private int _listId;
  48. private int _entryId;
  49. private long _amount;
  50. private int _enchantment;
  51. private long _transactionTax; // local handling of taxation
  52. @SuppressWarnings("unused")
  53. private int _unk1;
  54. @SuppressWarnings("unused")
  55. private int _unk2;
  56. @SuppressWarnings("unused")
  57. private int _unk3;
  58. @SuppressWarnings("unused")
  59. private int _unk7;
  60. @SuppressWarnings("unused")
  61. private int _unk4;
  62. @SuppressWarnings("unused")
  63. private int _unk5;
  64. @SuppressWarnings("unused")
  65. private int _unk6;
  66. @SuppressWarnings("unused")
  67. private int _unk8;
  68. @SuppressWarnings("unused")
  69. private int _unk9;
  70. @SuppressWarnings("unused")
  71. private int _unk10;
  72. @SuppressWarnings("unused")
  73. private int _unk11;
  74. /* (non-Javadoc)
  75. * @see com.l2jserver.gameserver.network.clientpackets.L2GameClientPacket#readImpl()
  76. */
  77. @Override
  78. protected void readImpl()
  79. {
  80. _listId = readD();
  81. _entryId = readD();
  82. _amount = readQ();
  83. _unk1 = readH();
  84. _unk2 = readD();
  85. _unk3 = readD();
  86. _unk4 = readH(); // elemental attributes
  87. _unk5 = readH();// elemental attributes
  88. _unk6 = readH();// elemental attributes
  89. _unk7 = readH();// elemental attributes
  90. _unk8 = readH();// elemental attributes
  91. _unk9 = readH();// elemental attributes
  92. _unk10 = readH();// elemental attributes
  93. _unk11 = readH();// elemental attributes
  94. _enchantment = _entryId % 100000;
  95. _entryId = _entryId / 100000;
  96. _transactionTax = 0; // initialize tax amount to 0...
  97. }
  98. /* (non-Javadoc)
  99. * @see com.l2jserver.gameserver.network.clientpackets.L2GameClientPacket#runImpl()
  100. */
  101. @Override
  102. public void runImpl()
  103. {
  104. L2PcInstance player = getClient().getActiveChar();
  105. if (player == null)
  106. return;
  107. if (!getClient().getFloodProtectors().getMultiSell().tryPerformAction("multisell choose"))
  108. return;
  109. if (_amount < 1 || _amount > 5000)
  110. return;
  111. MultiSellListContainer list = L2Multisell.getInstance().getList(_listId);
  112. if (list == null)
  113. return;
  114. L2Object target = player.getTarget();
  115. if (!player.isGM() && (target == null
  116. || !(target instanceof L2Npc)
  117. || !list.checkNpcId(((L2Npc)target).getNpcId())
  118. || !((L2Npc)target).canInteract(player)))
  119. return;
  120. for (MultiSellEntry entry : list.getEntries())
  121. {
  122. if (entry.getEntryId() == _entryId)
  123. {
  124. doExchange(player, entry, list.getApplyTaxes(), list.getMaintainEnchantment(), _enchantment);
  125. return;
  126. }
  127. }
  128. }
  129. /**
  130. * Do exchange.
  131. *
  132. * @param player the player
  133. * @param templateEntry the template entry
  134. * @param applyTaxes the apply taxes
  135. * @param maintainEnchantment the maintain enchantment
  136. * @param enchantment the enchantment
  137. */
  138. private void doExchange(L2PcInstance player, MultiSellEntry templateEntry, boolean applyTaxes, boolean maintainEnchantment, int enchantment)
  139. {
  140. PcInventory inv = player.getInventory();
  141. // given the template entry and information about maintaining enchantment and applying taxes
  142. // re-create the instance of the entry that will be used for this exchange
  143. // i.e. change the enchantment level of select ingredient/products and adena amount appropriately.
  144. L2Npc merchant = (player.getTarget() instanceof L2Npc) ? (L2Npc) player.getTarget() : null;
  145. if (merchant == null)
  146. return;
  147. MultiSellEntry entry = prepareEntry(merchant, templateEntry, applyTaxes, maintainEnchantment, enchantment);
  148. int slots = 0;
  149. int weight = 0;
  150. for (MultiSellIngredient e : entry.getProducts())
  151. {
  152. if (e.getItemId() < 0)
  153. continue;
  154. L2Item template = ItemTable.getInstance().getTemplate(e.getItemId());
  155. if (template == null)
  156. continue;
  157. if (!template.isStackable())
  158. slots += e.getItemCount() * _amount;
  159. else if (player.getInventory().getItemByItemId(e.getItemId()) == null)
  160. slots++;
  161. weight += e.getItemCount() * _amount * template.getWeight();
  162. }
  163. if (!inv.validateWeight(weight))
  164. {
  165. player.sendPacket(new SystemMessage(SystemMessageId.WEIGHT_LIMIT_EXCEEDED));
  166. return;
  167. }
  168. if (!inv.validateCapacity(slots))
  169. {
  170. player.sendPacket(new SystemMessage(SystemMessageId.SLOTS_FULL));
  171. return;
  172. }
  173. // Generate a list of distinct ingredients and counts in order to check if the correct item-counts
  174. // are possessed by the player
  175. FastList<MultiSellIngredient> _ingredientsList = FastList.newInstance();
  176. boolean newIng = true;
  177. for (MultiSellIngredient e : entry.getIngredients())
  178. {
  179. newIng = true;
  180. // at this point, the template has already been modified so that enchantments are properly included
  181. // whenever they need to be applied. Uniqueness of items is thus judged by item id AND enchantment level
  182. for (MultiSellIngredient ex : _ingredientsList)
  183. {
  184. // if the item was already added in the list, merely increment the count
  185. // this happens if 1 list entry has the same ingredient twice (example 2 swords = 1 dual)
  186. if ((ex.getItemId() == e.getItemId()) && (ex.getEnchantmentLevel() == e.getEnchantmentLevel()))
  187. {
  188. if ((double) ex.getItemCount() + e.getItemCount() > Integer.MAX_VALUE)
  189. {
  190. player.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED));
  191. _ingredientsList.clear();
  192. _ingredientsList = null;
  193. return;
  194. }
  195. ex.setItemCount(ex.getItemCount() + e.getItemCount());
  196. newIng = false;
  197. }
  198. }
  199. if (newIng)
  200. {
  201. // if it's a new ingredient, just store its info directly (item id, count, enchantment)
  202. _ingredientsList.add(L2Multisell.getInstance().new MultiSellIngredient(e));
  203. }
  204. }
  205. // now check if the player has sufficient items in the inventory to cover the ingredients' expences
  206. for (MultiSellIngredient e : _ingredientsList)
  207. {
  208. if ((double) e.getItemCount() * _amount > Integer.MAX_VALUE)
  209. {
  210. player.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED));
  211. _ingredientsList.clear();
  212. _ingredientsList = null;
  213. return;
  214. }
  215. switch (e.getItemId())
  216. {
  217. case -200: // Clan Reputation Score
  218. {
  219. if (player.getClan() == null)
  220. {
  221. player.sendPacket(new SystemMessage(SystemMessageId.YOU_ARE_NOT_A_CLAN_MEMBER));
  222. return;
  223. }
  224. if (!player.isClanLeader())
  225. {
  226. player.sendPacket(new SystemMessage(SystemMessageId.ONLY_THE_CLAN_LEADER_IS_ENABLED));
  227. return;
  228. }
  229. if (player.getClan().getReputationScore() < e.getItemCount() * _amount)
  230. {
  231. player.sendPacket(new SystemMessage(SystemMessageId.THE_CLAN_REPUTATION_SCORE_IS_TOO_LOW));
  232. return;
  233. }
  234. break;
  235. }
  236. case -300: // Player Fame
  237. {
  238. if (player.getFame() < e.getItemCount() * _amount)
  239. {
  240. player.sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_FAME_POINTS));
  241. return;
  242. }
  243. break;
  244. }
  245. default:
  246. {
  247. // if this is not a list that maintains enchantment, check the count of all items that have the given id.
  248. // otherwise, check only the count of items with exactly the needed enchantment level
  249. if (inv.getInventoryItemCount(e.getItemId(), maintainEnchantment ? e.getEnchantmentLevel() : -1, false) < ((Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient()) ? (e.getItemCount() * _amount) : e.getItemCount()))
  250. {
  251. player.sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_REQUIRED_ITEMS));//Update by rocknow
  252. _ingredientsList.clear();
  253. _ingredientsList = null;
  254. return;
  255. }
  256. break;
  257. }
  258. }
  259. }
  260. FastList.recycle(_ingredientsList);
  261. FastList<L2Augmentation> augmentation = FastList.newInstance();
  262. Elementals elemental = null;
  263. /** All ok, remove items and add final product */
  264. for (MultiSellIngredient e : entry.getIngredients())
  265. {
  266. switch (e.getItemId())
  267. {
  268. case -200: // Clan Reputation Score
  269. {
  270. int repCost = (int) (e.getItemCount() * _amount);
  271. player.getClan().takeReputationScore(repCost, true);
  272. SystemMessage smsg = new SystemMessage(SystemMessageId.S1_DEDUCTED_FROM_CLAN_REP);
  273. smsg.addItemNumber(e.getItemCount() * _amount);
  274. player.sendPacket(smsg);
  275. break;
  276. }
  277. case -300: // Player Fame
  278. {
  279. int fameCost = (int) (player.getFame() - (e.getItemCount() * _amount));
  280. player.setFame(fameCost);
  281. player.sendPacket(new UserInfo(player));
  282. player.sendPacket(new ExBrExtraUserInfo(player));
  283. break;
  284. }
  285. default:
  286. {
  287. L2ItemInstance itemToTake = inv.getItemByItemId(e.getItemId()); // initialize and initial guess for the item to take.
  288. if (itemToTake == null)
  289. { //this is a cheat, transaction will be aborted and if any items already taken will not be returned back to inventory!
  290. _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, merchatnt id:" + merchant.getNpcId());
  291. return;
  292. }
  293. /*if (itemToTake.isEquipped())
  294. { //this is a cheat, transaction will be aborted and if any items already taken will not be returned back to inventory!
  295. _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, exchanging equipped item, merchatnt id:" + merchant.getNpcId());
  296. return;
  297. }*/
  298. if (itemToTake.isWear())
  299. {//Player trying to buy something from the Multisell store with an item that's just being used from the Wear option from merchants.
  300. _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, merchatnt id:" + merchant.getNpcId());
  301. return;
  302. }
  303. if (Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient())
  304. {
  305. // if it's a stackable item, just reduce the amount from the first (only) instance that is found in the inventory
  306. if (itemToTake.isStackable())
  307. {
  308. if (!player.destroyItem("Multisell", itemToTake.getObjectId(), (e.getItemCount() * _amount), player.getTarget(), true))
  309. return;
  310. }
  311. else
  312. {
  313. // for non-stackable items, one of two scenaria are possible:
  314. // a) list maintains enchantment: get the instances that exactly match the requested enchantment level
  315. // b) list does not maintain enchantment: get the instances with the LOWEST enchantment level
  316. // a) if enchantment is maintained, then get a list of items that exactly match this enchantment
  317. if (maintainEnchantment)
  318. {
  319. // loop through this list and remove (one by one) each item until the required amount is taken.
  320. L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), e.getEnchantmentLevel(), false);
  321. for (int i = 0; i < (e.getItemCount() * _amount); i++)
  322. {
  323. if (inventoryContents[i].isAugmented())
  324. augmentation.add(inventoryContents[i].getAugmentation());
  325. if(inventoryContents[i].getElementals() != null)
  326. elemental = inventoryContents[i].getElementals();
  327. if (!player.destroyItem("Multisell", inventoryContents[i].getObjectId(), 1, player.getTarget(), true))
  328. return;
  329. }
  330. }
  331. else
  332. // b) enchantment is not maintained. Get the instances with the LOWEST enchantment level
  333. {
  334. /* NOTE: There are 2 ways to achieve the above goal.
  335. * 1) Get all items that have the correct itemId, loop through them until the lowest enchantment
  336. * level is found. Repeat all this for the next item until proper count of items is reached.
  337. * 2) Get all items that have the correct itemId, sort them once based on enchantment level,
  338. * and get the range of items that is necessary.
  339. * Method 1 is faster for a small number of items to be exchanged.
  340. * Method 2 is faster for large amounts.
  341. *
  342. * EXPLANATION:
  343. * Worst case scenario for algorithm 1 will make it run in a number of cycles given by:
  344. * m*(2n-m+1)/2 where m is the number of items to be exchanged and n is the total
  345. * number of inventory items that have a matching id.
  346. * With algorithm 2 (sort), sorting takes n*log(n) time and the choice is done in a single cycle
  347. * for case b (just grab the m first items) or in linear time for case a (find the beginning of items
  348. * with correct enchantment, index x, and take all items from x to x+m).
  349. * Basically, whenever m > log(n) we have: m*(2n-m+1)/2 = (2nm-m*m+m)/2 >
  350. * (2nlogn-logn*logn+logn)/2 = nlog(n) - log(n*n) + log(n) = nlog(n) + log(n/n*n) =
  351. * nlog(n) + log(1/n) = nlog(n) - log(n) = (n-1)log(n)
  352. * So for m < log(n) then m*(2n-m+1)/2 > (n-1)log(n) and m*(2n-m+1)/2 > nlog(n)
  353. *
  354. * IDEALLY:
  355. * In order to best optimize the performance, choose which algorithm to run, based on whether 2^m > n
  356. * if ( (2<<(e.getItemCount() * _amount)) < inventoryContents.length )
  357. * // do Algorithm 1, no sorting
  358. * else
  359. * // do Algorithm 2, sorting
  360. *
  361. * CURRENT IMPLEMENTATION:
  362. * In general, it is going to be very rare for a person to do a massive exchange of non-stackable items
  363. * For this reason, we assume that algorithm 1 will always suffice and we keep things simple.
  364. * If, in the future, it becomes necessary that we optimize, the above discussion should make it clear
  365. * what optimization exactly is necessary (based on the comments under "IDEALLY").
  366. */
  367. // choice 1. Small number of items exchanged. No sorting.
  368. for (int i = 1; i <= (e.getItemCount() * _amount); i++)
  369. {
  370. L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), false);
  371. itemToTake = inventoryContents[0];
  372. // get item with the LOWEST enchantment level from the inventory...
  373. // +0 is lowest by default...
  374. if (itemToTake.getEnchantLevel() > 0)
  375. {
  376. for (L2ItemInstance item : inventoryContents)
  377. {
  378. if (item.getEnchantLevel() < itemToTake.getEnchantLevel())
  379. {
  380. itemToTake = item;
  381. // nothing will have enchantment less than 0. If a zero-enchanted
  382. // item is found, just take it
  383. if (itemToTake.getEnchantLevel() == 0)
  384. break;
  385. }
  386. }
  387. }
  388. if (!player.destroyItem("Multisell", itemToTake.getObjectId(), 1, player.getTarget(), true))
  389. return;
  390. }
  391. }
  392. }
  393. }
  394. break;
  395. }
  396. }
  397. }
  398. // Generate the appropriate items
  399. for (MultiSellIngredient e : entry.getProducts())
  400. {
  401. switch (e.getItemId())
  402. {
  403. case -200: // Clan Reputation Score - now not supported
  404. {
  405. //player.getClan().setReputationScore((int)(player.getClan().getReputationScore() + e.getItemCount() * _amount), true);
  406. break;
  407. }
  408. case -300: // Player Fame
  409. {
  410. player.setFame((int)(player.getFame() + e.getItemCount() * _amount));
  411. player.sendPacket(new UserInfo(player));
  412. player.sendPacket(new ExBrExtraUserInfo(player));
  413. break;
  414. }
  415. default:
  416. {
  417. L2ItemInstance tempItem = ItemTable.getInstance().createDummyItem(e.getItemId());
  418. if (tempItem == null)
  419. {
  420. _log.severe("Problem with multisell ID:"+_listId+" entry ID:"+_entryId+" - Product ID:"+e.getItemId()+" not exist.");
  421. return;
  422. }
  423. if (tempItem.isStackable())
  424. {
  425. inv.addItem("Multisell", e.getItemId(), (e.getItemCount() * _amount), player, player.getTarget());
  426. }
  427. else
  428. {
  429. L2ItemInstance product = null;
  430. for (int i = 0; i < (e.getItemCount() * _amount); i++)
  431. {
  432. product = inv.addItem("Multisell", e.getItemId(), 1, player, player.getTarget());
  433. if (maintainEnchantment)
  434. {
  435. if (i < augmentation.size())
  436. product.setAugmentation(new L2Augmentation(augmentation.get(i).getAugmentationId(), augmentation.get(i).getSkill()));
  437. if (elemental != null)
  438. product.setElementAttr(elemental.getElement(), elemental.getValue());
  439. product.setEnchantLevel(e.getEnchantmentLevel());
  440. product.updateDatabase();
  441. }
  442. }
  443. }
  444. // msg part
  445. SystemMessage sm;
  446. if (e.getItemCount() * _amount > 1)
  447. {
  448. sm = new SystemMessage(SystemMessageId.EARNED_S2_S1_S);
  449. sm.addItemName(e.getItemId());
  450. sm.addItemNumber(e.getItemCount() * _amount);
  451. player.sendPacket(sm);
  452. sm = null;
  453. }
  454. else
  455. {
  456. if (maintainEnchantment && e.getEnchantmentLevel() > 0)
  457. {
  458. sm = new SystemMessage(SystemMessageId.ACQUIRED_S1_S2);
  459. sm.addItemNumber(e.getEnchantmentLevel());
  460. sm.addItemName(e.getItemId());
  461. }
  462. else
  463. {
  464. sm = new SystemMessage(SystemMessageId.EARNED_ITEM);
  465. sm.addItemName(e.getItemId());
  466. }
  467. player.sendPacket(sm);
  468. sm = null;
  469. }
  470. }
  471. }
  472. }
  473. player.sendPacket(new ItemList(player, false));
  474. StatusUpdate su = new StatusUpdate(player.getObjectId());
  475. su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  476. player.sendPacket(su);
  477. su = null;
  478. // finally, give the tax to the castle...
  479. if (merchant.getIsInTown() && merchant.getCastle().getOwnerId() > 0)
  480. merchant.getCastle().addToTreasury(_transactionTax * _amount);
  481. FastList.recycle(augmentation);
  482. }
  483. // Regarding taxation, the following appears to be the case:
  484. // a) The count of aa remains unchanged (taxes do not affect aa directly).
  485. // b) 5/6 of the amount of aa is taxed by the normal tax rate.
  486. // c) the resulting taxes are added as normal adena value.
  487. // d) normal adena are taxed fully.
  488. // e) Items other than adena and ancient adena are not taxed even when the list is taxable.
  489. // example: If the template has an item worth 120aa, and the tax is 10%,
  490. // then from 120aa, take 5/6 so that is 100aa, apply the 10% tax in adena (10a)
  491. // so the final price will be 120aa and 10a!
  492. /**
  493. * Prepare entry.
  494. *
  495. * @param merchant the merchant
  496. * @param templateEntry the template entry
  497. * @param applyTaxes the apply taxes
  498. * @param maintainEnchantment the maintain enchantment
  499. * @param enchantLevel the enchant level
  500. * @return the multi sell entry
  501. */
  502. private MultiSellEntry prepareEntry(L2Npc merchant, MultiSellEntry templateEntry, boolean applyTaxes, boolean maintainEnchantment, int enchantLevel)
  503. {
  504. MultiSellEntry newEntry = L2Multisell.getInstance().new MultiSellEntry();
  505. newEntry.setEntryId(templateEntry.getEntryId());
  506. long totalAdenaCount = 0;
  507. boolean hasIngredient = false;
  508. for (MultiSellIngredient ing : templateEntry.getIngredients())
  509. {
  510. // load the ingredient from the template
  511. MultiSellIngredient newIngredient = L2Multisell.getInstance().new MultiSellIngredient(ing);
  512. if (newIngredient.getItemId() == 57 && newIngredient.isTaxIngredient())
  513. {
  514. double taxRate = 0.0;
  515. if (applyTaxes)
  516. {
  517. if (merchant != null && merchant.getIsInTown())
  518. taxRate = merchant.getCastle().getTaxRate();
  519. }
  520. _transactionTax = Math.round(newIngredient.getItemCount() * taxRate);
  521. totalAdenaCount += _transactionTax;
  522. continue; // do not yet add this adena amount to the list as non-taxIngredient adena might be entered later (order not guaranteed)
  523. }
  524. else if (ing.getItemId() == 57) // && !ing.isTaxIngredient()
  525. {
  526. totalAdenaCount += newIngredient.getItemCount();
  527. continue; // do not yet add this adena amount to the list as taxIngredient adena might be entered later (order not guaranteed)
  528. }
  529. // if it is an armor/weapon, modify the enchantment level appropriately, if necessary
  530. // not used for clan reputation and fame
  531. else if (maintainEnchantment && newIngredient.getItemId() > 0)
  532. {
  533. L2Item tempItem = ItemTable.getInstance().createDummyItem(newIngredient.getItemId()).getItem();
  534. if ((tempItem instanceof L2Armor) || (tempItem instanceof L2Weapon))
  535. {
  536. newIngredient.setEnchantmentLevel(enchantLevel);
  537. hasIngredient = true;
  538. }
  539. }
  540. // finally, add this ingredient to the entry
  541. newEntry.addIngredient(newIngredient);
  542. }
  543. // Next add the adena amount, if any
  544. if (totalAdenaCount > 0)
  545. newEntry.addIngredient(L2Multisell.getInstance().new MultiSellIngredient(57, totalAdenaCount, false, false));
  546. // Now modify the enchantment level of products, if necessary
  547. for (MultiSellIngredient ing : templateEntry.getProducts())
  548. {
  549. // load the ingredient from the template
  550. MultiSellIngredient newIngredient = L2Multisell.getInstance().new MultiSellIngredient(ing);
  551. if (maintainEnchantment && hasIngredient)
  552. {
  553. // if it is an armor/weapon, modify the enchantment level appropriately
  554. // (note, if maintain enchantment is "false" this modification will result to a +0)
  555. L2Item tempItem = ItemTable.getInstance().createDummyItem(newIngredient.getItemId()).getItem();
  556. if ((tempItem instanceof L2Armor) || (tempItem instanceof L2Weapon))
  557. newIngredient.setEnchantmentLevel(enchantLevel);
  558. }
  559. newEntry.addProduct(newIngredient);
  560. }
  561. return newEntry;
  562. }
  563. /* (non-Javadoc)
  564. * @see com.l2jserver.gameserver.network.clientpackets.L2GameClientPacket#getType()
  565. */
  566. @Override
  567. public String getType()
  568. {
  569. return _C__A7_MULTISELLCHOOSE;
  570. }
  571. }