Advertisement
Guest User

Untitled

a guest
Aug 13th, 2011
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 16.43 KB | None | 0 0
  1. package com.l2jserver.gameserver.network.clientpackets;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.logging.Logger;
  5.  
  6. import javolution.util.FastList;
  7.  
  8. import com.l2jserver.Config;
  9. import com.l2jserver.gameserver.datatables.MultiSell;
  10. import com.l2jserver.gameserver.model.Elementals;
  11. import com.l2jserver.gameserver.model.L2Augmentation;
  12. import com.l2jserver.gameserver.model.L2ItemInstance;
  13. import com.l2jserver.gameserver.model.actor.L2Npc;
  14. import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
  15. import com.l2jserver.gameserver.model.itemcontainer.PcInventory;
  16. import com.l2jserver.gameserver.model.multisell.Entry;
  17. import com.l2jserver.gameserver.model.multisell.Ingredient;
  18. import com.l2jserver.gameserver.model.multisell.PreparedListContainer;
  19. import com.l2jserver.gameserver.network.SystemMessageId;
  20. import com.l2jserver.gameserver.network.serverpackets.ItemList;
  21. import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
  22. import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
  23.  
  24. /**
  25.  * The Class MultiSellChoose.
  26.  */
  27. public class MultiSellChoose extends L2GameClientPacket
  28. {
  29.     private static final String _C__B0_MULTISELLCHOOSE = "[C] B0 MultiSellChoose";
  30.     private static Logger _log = Logger.getLogger(MultiSellChoose.class.getName());
  31.     private int _listId;
  32.     private int _entryId;
  33.     private long _amount;
  34.     /*@SuppressWarnings("unused")
  35.     private int _unk1;
  36.     @SuppressWarnings("unused")
  37.     private int _unk2;
  38.     @SuppressWarnings("unused")
  39.     private int _unk3;
  40.     @SuppressWarnings("unused")
  41.     private int _unk7;
  42.     @SuppressWarnings("unused")
  43.     private int _unk4;
  44.     @SuppressWarnings("unused")
  45.     private int _unk5;
  46.     @SuppressWarnings("unused")
  47.     private int _unk6;
  48.     @SuppressWarnings("unused")
  49.     private int _unk8;
  50.     @SuppressWarnings("unused")
  51.     private int _unk9;
  52.     @SuppressWarnings("unused")
  53.     private int _unk10;
  54.     @SuppressWarnings("unused")
  55.     private int _unk11;*/
  56.    
  57.     @Override
  58.     protected void readImpl()
  59.     {
  60.         _listId = readD();
  61.         _entryId = readD();
  62.         _amount = readQ();
  63.         /*_unk1 = readH();
  64.         _unk2 = readD();
  65.         _unk3 = readD();
  66.         _unk4 = readH(); // elemental attributes
  67.         _unk5 = readH(); // elemental attributes
  68.         _unk6 = readH(); // elemental attributes
  69.         _unk7 = readH(); // elemental attributes
  70.         _unk8 = readH(); // elemental attributes
  71.         _unk9 = readH(); // elemental attributes
  72.         _unk10 = readH(); // elemental attributes
  73.         _unk11 = readH(); // elemental attributes*/
  74.     }
  75.    
  76.     @Override
  77.     public void runImpl()
  78.     {
  79.         final L2PcInstance player = getClient().getActiveChar();
  80.         if (player == null)
  81.             return;
  82.        
  83.         if (!getClient().getFloodProtectors().getMultiSell().tryPerformAction("multisell choose"))
  84.         {
  85.             player.setMultiSell(null);
  86.             return;
  87.         }
  88.        
  89.         if (_amount < 1 || _amount > 5000)
  90.         {
  91.             player.setMultiSell(null);
  92.             return;
  93.         }
  94.        
  95.         PreparedListContainer list = player.getMultiSell();
  96.         if (list == null || list.getListId() != _listId)
  97.         {
  98.             player.setMultiSell(null);
  99.             return;
  100.         }
  101.        
  102.         int bbsids[] = {1111,2222};
  103.         boolean isBbsList = false;
  104.         for (int i : bbsids)
  105.             if (i==_listId)
  106.             {
  107.                 isBbsList = true;
  108.                 break;
  109.             }
  110.  
  111.         if (!isBbsList)
  112.         {
  113.             L2Npc target = player.getLastFolkNPC();
  114.             if (!player.isGM() && (target == null || !list.checkNpcObjectId(target.getObjectId()) || !target.canInteract(player)))
  115.             {
  116.                 player.setMultiSell(null);
  117.                 return;
  118.             }
  119.         }
  120.        
  121.         for (Entry entry : list.getEntries())
  122.         {
  123.             if (entry.getEntryId() == _entryId)
  124.             {
  125.                 if (!entry.isStackable() && _amount > 1)
  126.                 {
  127.                     _log.severe("Character: " + player.getName() + " is trying to set amount > 1 on non-stackable multisell, id:" + _listId + ":" + _entryId);
  128.                     player.setMultiSell(null);
  129.                     return;
  130.                 }
  131.                
  132.                 final PcInventory inv = player.getInventory();
  133.                
  134.                 int slots = 0;
  135.                 int weight = 0;
  136.                 for (Ingredient e : entry.getProducts())
  137.                 {
  138.                     if (e.getItemId() < 0) // special
  139.                         continue;
  140.                    
  141.                     if (!e.isStackable())
  142.                         slots += e.getItemCount() * _amount;
  143.                     else if (player.getInventory().getItemByItemId(e.getItemId()) == null)
  144.                         slots++;
  145.                     weight += e.getItemCount() * _amount * e.getWeight();
  146.                 }
  147.                
  148.                 if (!inv.validateWeight(weight))
  149.                 {
  150.                     player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.WEIGHT_LIMIT_EXCEEDED));
  151.                     return;
  152.                 }
  153.                
  154.                 if (!inv.validateCapacity(slots))
  155.                 {
  156.                     player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.SLOTS_FULL));
  157.                     return;
  158.                 }
  159.                
  160.                 ArrayList<Ingredient> ingredientsList = new ArrayList<Ingredient>(entry.getIngredients().size());
  161.                 // Generate a list of distinct ingredients and counts in order to check if the correct item-counts
  162.                 // are possessed by the player
  163.                 boolean newIng;
  164.                 for (Ingredient e : entry.getIngredients())
  165.                 {
  166.                     newIng = true;
  167.                     // at this point, the template has already been modified so that enchantments are properly included
  168.                     // whenever they need to be applied.  Uniqueness of items is thus judged by item id AND enchantment level
  169.                     for (int i = ingredientsList.size(); --i >= 0;)
  170.                     {
  171.                         Ingredient ex = ingredientsList.get(i);
  172.                         // if the item was already added in the list, merely increment the count
  173.                         // this happens if 1 list entry has the same ingredient twice (example 2 swords = 1 dual)
  174.                         if ((ex.getItemId() == e.getItemId()) && (ex.getEnchantLevel() == e.getEnchantLevel()))
  175.                         {
  176.                             if (ex.getItemCount() + e.getItemCount() > Integer.MAX_VALUE)
  177.                             {
  178.                                 player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED));
  179.                                 return;
  180.                             }
  181.                             // two same ingredients, merge into one and replace old
  182.                             final Ingredient ing = ex.clone();
  183.                             ing.setItemCount(ex.getItemCount() + e.getItemCount());
  184.                             ingredientsList.set(i, ing);
  185.                             newIng = false;
  186.                             break;
  187.                         }
  188.                     }
  189.                     if (newIng)
  190.                     {
  191.                         // if it's a new ingredient, just store its info directly (item id, count, enchantment)
  192.                         ingredientsList.add(e);
  193.                     }
  194.                 }
  195.                
  196.                 // now check if the player has sufficient items in the inventory to cover the ingredients' expences
  197.                 for (Ingredient e : ingredientsList)
  198.                 {
  199.                     if (e.getItemCount() * _amount > Integer.MAX_VALUE)
  200.                     {
  201.                         player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED));
  202.                         return;
  203.                     }
  204.                     if (e.getItemId() < 0)
  205.                     {
  206.                         if (!MultiSell.checkSpecialIngredient(e.getItemId(), e.getItemCount() * _amount, player))
  207.                             return;
  208.                     }
  209.                     else
  210.                     {
  211.                         // if this is not a list that maintains enchantment, check the count of all items that have the given id.
  212.                         // otherwise, check only the count of items with exactly the needed enchantment level
  213.                         final long required = ((Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient()) ? (e.getItemCount() * _amount) : e.getItemCount());
  214.                         if (inv.getInventoryItemCount(e.getItemId(), list.getMaintainEnchantment() ? e.getEnchantLevel() : -1, false) < required)
  215.                         {
  216.                             SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_UNIT_OF_THE_ITEM_S1_REQUIRED);
  217.                             sm.addItemName(e.getTemplate());
  218.                             sm.addNumber((int)required);
  219.                             player.sendPacket(sm);
  220.                             return;
  221.                         }
  222.                     }
  223.                 }
  224.                
  225.                 FastList<L2Augmentation> augmentation = FastList.newInstance();
  226.                 Elementals[] elemental = null;
  227.                 /** All ok, remove items and add final product */
  228.                
  229.                 try
  230.                 {
  231.                     for (Ingredient e : entry.getIngredients())
  232.                     {
  233.                         if (e.getItemId() < 0)
  234.                         {
  235.                             if (!MultiSell.getSpecialIngredient(e.getItemId(), e.getItemCount() * _amount, player))
  236.                                 return;
  237.                         }
  238.                         else
  239.                         {
  240.                             L2ItemInstance itemToTake = inv.getItemByItemId(e.getItemId()); // initialize and initial guess for the item to take.
  241.                             if (itemToTake == null)
  242.                             { //this is a cheat, transaction will be aborted and if any items already taken will not be returned back to inventory!
  243.                                 _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, id:" + _listId + ":" + _entryId);
  244.                                 player.setMultiSell(null);
  245.                                 return;
  246.                             }
  247.                            
  248.                             /*if (itemToTake.isEquipped())
  249.                             { //this is a cheat, transaction will be aborted and if any items already taken will not be returned back to inventory!
  250.                                 _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, exchanging equipped item, merchatnt id:" + merchant.getNpcId());
  251.                                 player.setMultiSell(null);
  252.                                 return;
  253.                             }*/
  254.                            
  255.                             if (Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient())
  256.                             {
  257.                                 // if it's a stackable item, just reduce the amount from the first (only) instance that is found in the inventory
  258.                                 if (itemToTake.isStackable())
  259.                                 {
  260.                                     if (!player.destroyItem("Multisell", itemToTake.getObjectId(), (e.getItemCount() * _amount), player.getTarget(), true))
  261.                                     {
  262.                                         player.setMultiSell(null);
  263.                                         return;
  264.                                     }
  265.                                 }
  266.                                 else
  267.                                 {
  268.                                     // for non-stackable items, one of two scenaria are possible:
  269.                                     // a) list maintains enchantment: get the instances that exactly match the requested enchantment level
  270.                                     // b) list does not maintain enchantment: get the instances with the LOWEST enchantment level
  271.                                    
  272.                                     // a) if enchantment is maintained, then get a list of items that exactly match this enchantment
  273.                                     if (list.getMaintainEnchantment())
  274.                                     {
  275.                                         // loop through this list and remove (one by one) each item until the required amount is taken.
  276.                                         L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), e.getEnchantLevel(), false);
  277.                                         for (int i = 0; i < (e.getItemCount() * _amount); i++)
  278.                                         {
  279.                                             if (inventoryContents[i].isAugmented())
  280.                                                 augmentation.add(inventoryContents[i].getAugmentation());
  281.                                             if(inventoryContents[i].getElementals() != null)
  282.                                                 elemental = inventoryContents[i].getElementals();
  283.                                             if (!player.destroyItem("Multisell", inventoryContents[i].getObjectId(), 1, player.getTarget(), true))
  284.                                             {
  285.                                                 player.setMultiSell(null);
  286.                                                 return;
  287.                                             }
  288.                                         }
  289.                                     }
  290.                                     else
  291.                                         // b) enchantment is not maintained.  Get the instances with the LOWEST enchantment level
  292.                                     {
  293.                                         /* NOTE: There are 2 ways to achieve the above goal.
  294.                                          * 1) Get all items that have the correct itemId, loop through them until the lowest enchantment
  295.                                          *      level is found.  Repeat all this for the next item until proper count of items is reached.
  296.                                          * 2) Get all items that have the correct itemId, sort them once based on enchantment level,
  297.                                          *      and get the range of items that is necessary.
  298.                                          * Method 1 is faster for a small number of items to be exchanged.
  299.                                          * Method 2 is faster for large amounts.
  300.                                          *
  301.                                          * EXPLANATION:
  302.                                          *   Worst case scenario for algorithm 1 will make it run in a number of cycles given by:
  303.                                          * m*(2n-m+1)/2 where m is the number of items to be exchanged and n is the total
  304.                                          * number of inventory items that have a matching id.
  305.                                          *   With algorithm 2 (sort), sorting takes n*log(n) time and the choice is done in a single cycle
  306.                                          * for case b (just grab the m first items) or in linear time for case a (find the beginning of items
  307.                                          * with correct enchantment, index x, and take all items from x to x+m).
  308.                                          * Basically, whenever m > log(n) we have: m*(2n-m+1)/2 = (2nm-m*m+m)/2 >
  309.                                          * (2nlogn-logn*logn+logn)/2 = nlog(n) - log(n*n) + log(n) = nlog(n) + log(n/n*n) =
  310.                                          * nlog(n) + log(1/n) = nlog(n) - log(n) = (n-1)log(n)
  311.                                          * So for m < log(n) then m*(2n-m+1)/2 > (n-1)log(n) and m*(2n-m+1)/2 > nlog(n)
  312.                                          *
  313.                                          * IDEALLY:
  314.                                          * In order to best optimize the performance, choose which algorithm to run, based on whether 2^m > n
  315.                                          * if ( (2<<(e.getItemCount() * _amount)) < inventoryContents.length )
  316.                                          *   // do Algorithm 1, no sorting
  317.                                          * else
  318.                                          *   // do Algorithm 2, sorting
  319.                                          *
  320.                                          * CURRENT IMPLEMENTATION:
  321.                                          * In general, it is going to be very rare for a person to do a massive exchange of non-stackable items
  322.                                          * For this reason, we assume that algorithm 1 will always suffice and we keep things simple.
  323.                                          * If, in the future, it becomes necessary that we optimize, the above discussion should make it clear
  324.                                          * what optimization exactly is necessary (based on the comments under "IDEALLY").
  325.                                          */
  326.                                        
  327.                                         // choice 1.  Small number of items exchanged.  No sorting.
  328.                                         for (int i = 1; i <= (e.getItemCount() * _amount); i++)
  329.                                         {
  330.                                             L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), false);
  331.                                            
  332.                                             itemToTake = inventoryContents[0];
  333.                                             // get item with the LOWEST enchantment level  from the inventory...
  334.                                             // +0 is lowest by default...
  335.                                             if (itemToTake.getEnchantLevel() > 0)
  336.                                             {
  337.                                                 for (L2ItemInstance item : inventoryContents)
  338.                                                 {
  339.                                                     if (item.getEnchantLevel() < itemToTake.getEnchantLevel())
  340.                                                     {
  341.                                                         itemToTake = item;
  342.                                                         // nothing will have enchantment less than 0. If a zero-enchanted
  343.                                                         // item is found, just take it
  344.                                                         if (itemToTake.getEnchantLevel() == 0)
  345.                                                             break;
  346.                                                     }
  347.                                                 }
  348.                                             }
  349.                                             if (!player.destroyItem("Multisell", itemToTake.getObjectId(), 1, player.getTarget(), true))
  350.                                             {
  351.                                                 player.setMultiSell(null);
  352.                                                 return;
  353.                                             }
  354.                                         }
  355.                                     }
  356.                                 }
  357.                             }
  358.                         }
  359.                     }
  360.                    
  361.                     // Generate the appropriate items
  362.                     for (Ingredient e : entry.getProducts())
  363.                     {
  364.                         if (e.getItemId() < 0)
  365.                         {
  366.                             MultiSell.addSpecialProduct(e.getItemId(), e.getItemCount() * _amount, player);
  367.                         }
  368.                         else
  369.                         {
  370.                             if (e.isStackable())
  371.                                 inv.addItem("Multisell", e.getItemId(), e.getItemCount() * _amount, player, player.getTarget());
  372.                             else
  373.                             {
  374.                                 L2ItemInstance product = null;
  375.                                 for (int i = 0; i < (e.getItemCount() * _amount); i++)
  376.                                 {
  377.                                     product = inv.addItem("Multisell", e.getItemId(), 1, player, player.getTarget());
  378.                                     if (list.getMaintainEnchantment())
  379.                                     {
  380.                                         if (i < augmentation.size())
  381.                                             product.setAugmentation(new L2Augmentation(augmentation.get(i).getAugmentationId(), augmentation.get(i).getSkill()));
  382.                                         if (elemental != null)
  383.                                             for (Elementals elm : elemental)
  384.                                                 product.setElementAttr(elm.getElement(), elm.getValue());
  385.                                         product.setEnchantLevel(e.getEnchantLevel());
  386.                                         product.updateDatabase();
  387.                                     }
  388.                                 }
  389.                             }
  390.                             // msg part
  391.                             SystemMessage sm;
  392.                            
  393.                             if (e.getItemCount() * _amount > 1)
  394.                             {
  395.                                 sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
  396.                                 sm.addItemName(e.getItemId());
  397.                                 sm.addItemNumber(e.getItemCount() * _amount);
  398.                                 player.sendPacket(sm);
  399.                                 sm = null;
  400.                             }
  401.                             else
  402.                             {
  403.                                 if (list.getMaintainEnchantment() && e.getEnchantLevel() > 0)
  404.                                 {
  405.                                     sm = SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED_S1_S2);
  406.                                     sm.addItemNumber(e.getEnchantLevel());
  407.                                     sm.addItemName(e.getItemId());
  408.                                 }
  409.                                 else
  410.                                 {
  411.                                     sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
  412.                                     sm.addItemName(e.getItemId());
  413.                                 }
  414.                                 player.sendPacket(sm);
  415.                                 sm = null;
  416.                             }
  417.                         }
  418.                     }
  419.                     player.sendPacket(new ItemList(player, false));
  420.                    
  421.                     StatusUpdate su = new StatusUpdate(player);
  422.                     su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
  423.                     player.sendPacket(su);
  424.                     su = null;
  425.                 }
  426.                 finally
  427.                 {
  428.                     FastList.recycle(augmentation);
  429.                 }
  430.                
  431.                 // finally, give the tax to the castle...
  432.                 if (target!=null && entry.getTaxAmount() > 0)
  433.                     target.getCastle().addToTreasury(entry.getTaxAmount() * _amount);
  434.                
  435.                 break;
  436.             }
  437.         }
  438.     }
  439.    
  440.     @Override
  441.     public String getType()
  442.     {
  443.         return _C__B0_MULTISELLCHOOSE;
  444.     }
  445. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement