@Override public final boolean useBypass(String command, L2PcInstance activeChar, L2Character target) { try { final L2Npc olymanager = activeChar.getLastFolkNPC(); if (command.startsWith(COMMANDS[0])) // list { if (!Olympiad.getInstance().inCompPeriod()) { activeChar.sendPacket(SystemMessageId.THE_OLYMPIAD_GAME_IS_NOT_CURRENTLY_IN_PROGRESS); return false; } activeChar.sendPacket(new ExOlympiadMatchList()); } else { if ((olymanager == null) || !(olymanager instanceof L2OlympiadManagerInstance)) { return false; } if (!activeChar.inObserverMode() && !activeChar.isInsideRadius(olymanager, 300, false, false)) { return false; } if (OlympiadManager.getInstance().isRegisteredInComp(activeChar)) { activeChar.sendPacket( SystemMessageId .WHILE_YOU_ARE_ON_THE_WAITING_LIST_YOU_ARE_NOT_ALLOWED_TO_WATCH_THE_GAME); return false; } if (!Olympiad.getInstance().inCompPeriod()) { activeChar.sendPacket(SystemMessageId.THE_OLYMPIAD_GAME_IS_NOT_CURRENTLY_IN_PROGRESS); return false; } if (activeChar.isOnEvent()) { activeChar.sendMessage("You can not observe games while registered on an event"); return false; } final int arenaId = Integer.parseInt(command.substring(12).trim()); final OlympiadGameTask nextArena = OlympiadGameManager.getInstance().getOlympiadTask(arenaId); if (nextArena != null) { activeChar.enterOlympiadObserverMode( nextArena.getZone().getSpectatorSpawns().get(0), arenaId); activeChar.setInstanceId( OlympiadGameManager.getInstance().getOlympiadTask(arenaId).getZone().getInstanceId()); } } return true; } catch (Exception e) { _log.log(Level.WARNING, "Exception in " + getClass().getSimpleName(), e); } return false; }
@Override public void runImpl() { final L2PcInstance player = getClient().getActiveChar(); if (player == null) { return; } if (!getClient().getFloodProtectors().getMultiSell().tryPerformAction("multisell choose")) { player.setMultiSell(null); return; } if ((_amount < 1) || (_amount > 5000)) { player.setMultiSell(null); return; } PreparedListContainer list = player.getMultiSell(); if ((list == null) || (list.getListId() != _listId)) { player.setMultiSell(null); return; } final L2Npc npc = player.getLastFolkNPC(); if (((npc != null) && !list.isNpcAllowed(npc.getId())) || ((npc == null) && list.isNpcOnly())) { player.setMultiSell(null); return; } if (!player.isGM() && (npc != null)) { if (!player.isInsideRadius(npc, INTERACTION_DISTANCE, true, false) || (player.getInstanceId() != npc.getInstanceId())) { player.setMultiSell(null); return; } } for (Entry entry : list.getEntries()) { if (entry.getEntryId() == _entryId) { if (!entry.isStackable() && (_amount > 1)) { _log.severe( "Character: " + player.getName() + " is trying to set amount > 1 on non-stackable multisell, id:" + _listId + ":" + _entryId); player.setMultiSell(null); return; } final PcInventory inv = player.getInventory(); int slots = 0; int weight = 0; for (Ingredient e : entry.getProducts()) { if (e.getItemId() < 0) { continue; } if (!e.isStackable()) { slots += e.getItemCount() * _amount; } else if (player.getInventory().getItemByItemId(e.getItemId()) == null) { slots++; } weight += e.getItemCount() * _amount * e.getWeight(); } if (!inv.validateWeight(weight)) { player.sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED); return; } if (!inv.validateCapacity(slots)) { player.sendPacket(SystemMessageId.SLOTS_FULL); return; } ArrayList<Ingredient> ingredientsList = new ArrayList<>(entry.getIngredients().size()); // Generate a list of distinct ingredients and counts in order to check if the correct // item-counts // are possessed by the player boolean newIng; for (Ingredient e : entry.getIngredients()) { newIng = true; // at this point, the template has already been modified so that enchantments are properly // included // whenever they need to be applied. Uniqueness of items is thus judged by item id AND // enchantment level for (int i = ingredientsList.size(); --i >= 0; ) { Ingredient ex = ingredientsList.get(i); // if the item was already added in the list, merely increment the count // this happens if 1 list entry has the same ingredient twice (example 2 swords = 1 // dual) if ((ex.getItemId() == e.getItemId()) && (ex.getEnchantLevel() == e.getEnchantLevel())) { if ((ex.getItemCount() + e.getItemCount()) > Integer.MAX_VALUE) { player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED); return; } // two same ingredients, merge into one and replace old final Ingredient ing = ex.getCopy(); ing.setItemCount(ex.getItemCount() + e.getItemCount()); ingredientsList.set(i, ing); newIng = false; break; } } if (newIng) { // if it's a new ingredient, just store its info directly (item id, count, enchantment) ingredientsList.add(e); } } // now check if the player has sufficient items in the inventory to cover the ingredients' // expences for (Ingredient e : ingredientsList) { if ((e.getItemCount() * _amount) > Integer.MAX_VALUE) { player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED); return; } if (e.getItemId() < 0) { if (!MultisellData.hasSpecialIngredient( e.getItemId(), e.getItemCount() * _amount, player)) { return; } } else { // if this is not a list that maintains enchantment, check the count of all items that // have the given id. // otherwise, check only the count of items with exactly the needed enchantment level final long required = ((Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient()) ? (e.getItemCount() * _amount) : e.getItemCount()); if (inv.getInventoryItemCount( e.getItemId(), list.getMaintainEnchantment() ? e.getEnchantLevel() : -1, false) < required) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_UNIT_OF_THE_ITEM_S1_REQUIRED); sm.addItemName(e.getTemplate()); sm.addLong(required); player.sendPacket(sm); return; } } } List<L2Augmentation> augmentation = new ArrayList<>(); Elementals[] elemental = null; /** All ok, remove items and add final product */ for (Ingredient e : entry.getIngredients()) { if (e.getItemId() < 0) { if (!MultisellData.takeSpecialIngredient( e.getItemId(), e.getItemCount() * _amount, player)) { return; } } else { L2ItemInstance itemToTake = inv.getItemByItemId( e.getItemId()); // initialize and initial guess for the item to take. if (itemToTake == null) { // this is a cheat, transaction will be aborted and if any items already // taken will not be returned back to inventory! _log.severe( "Character: " + player.getName() + " is trying to cheat in multisell, id:" + _listId + ":" + _entryId); player.setMultiSell(null); return; } // if (itemToTake.isEquipped()) // { // this is a cheat, transaction will be aborted and if any items already taken will not // be returned back to inventory! // _log.severe("Character: " + player.getName() + " is trying to cheat in multisell, // exchanging equipped item, merchatnt id:" + merchant.getNpcId()); // player.setMultiSell(null); // return; // } if (Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient()) { // if it's a stackable item, just reduce the amount from the first (only) instance // that is found in the inventory if (itemToTake.isStackable()) { if (!player.destroyItem( "Multisell", itemToTake.getObjectId(), (e.getItemCount() * _amount), player.getTarget(), true)) { player.setMultiSell(null); return; } } else { // for non-stackable items, one of two scenaria are possible: // a) list maintains enchantment: get the instances that exactly match the requested // enchantment level // b) list does not maintain enchantment: get the instances with the LOWEST // enchantment level // a) if enchantment is maintained, then get a list of items that exactly match this // enchantment if (list.getMaintainEnchantment()) { // loop through this list and remove (one by one) each item until the required // amount is taken. L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), e.getEnchantLevel(), false); for (int i = 0; i < (e.getItemCount() * _amount); i++) { if (inventoryContents[i].isAugmented()) { augmentation.add(inventoryContents[i].getAugmentation()); } if (inventoryContents[i].getElementals() != null) { elemental = inventoryContents[i].getElementals(); } if (!player.destroyItem( "Multisell", inventoryContents[i].getObjectId(), 1, player.getTarget(), true)) { player.setMultiSell(null); return; } } } else // b) enchantment is not maintained. Get the instances with the LOWEST enchantment // level { // NOTE: There are 2 ways to achieve the above goal. // 1) Get all items that have the correct itemId, loop through them until the // lowest enchantment // level is found. Repeat all this for the next item until proper count of items // is reached. // 2) Get all items that have the correct itemId, sort them once based on // enchantment level, // and get the range of items that is necessary. // Method 1 is faster for a small number of items to be exchanged. // Method 2 is faster for large amounts. // // EXPLANATION: // Worst case scenario for algorithm 1 will make it run in a number of cycles // given by: // m*(2n-m+1)/2 where m is the number of items to be exchanged and n is the total // number of inventory items that have a matching id. // With algorithm 2 (sort), sorting takes n*log(n) time and the choice is done in // a single cycle // for case b (just grab the m first items) or in linear time for case a (find the // beginning of items // with correct enchantment, index x, and take all items from x to x+m). // Basically, whenever m > log(n) we have: m*(2n-m+1)/2 = (2nm-m*m+m)/2 > // (2nlogn-logn*logn+logn)/2 = nlog(n) - log(n*n) + log(n) = nlog(n) + log(n/n*n) // = // nlog(n) + log(1/n) = nlog(n) - log(n) = (n-1)log(n) // So for m < log(n) then m*(2n-m+1)/2 > (n-1)log(n) and m*(2n-m+1)/2 > nlog(n) // // IDEALLY: // In order to best optimize the performance, choose which algorithm to run, based // on whether 2^m > n // if ( (2<<(e.getItemCount()// _amount)) < inventoryContents.length ) // // do Algorithm 1, no sorting // else // // do Algorithm 2, sorting // // CURRENT IMPLEMENTATION: // In general, it is going to be very rare for a person to do a massive exchange // of non-stackable items // For this reason, we assume that algorithm 1 will always suffice and we keep // things simple. // If, in the future, it becomes necessary that we optimize, the above discussion // should make it clear // what optimization exactly is necessary (based on the comments under "IDEALLY"). // // choice 1. Small number of items exchanged. No sorting. for (int i = 1; i <= (e.getItemCount() * _amount); i++) { L2ItemInstance[] inventoryContents = inv.getAllItemsByItemId(e.getItemId(), false); itemToTake = inventoryContents[0]; // get item with the LOWEST enchantment level from the inventory... // +0 is lowest by default... if (itemToTake.getEnchantLevel() > 0) { for (L2ItemInstance item : inventoryContents) { if (item.getEnchantLevel() < itemToTake.getEnchantLevel()) { itemToTake = item; // nothing will have enchantment less than 0. If a zero-enchanted // item is found, just take it if (itemToTake.getEnchantLevel() == 0) { break; } } } } if (!player.destroyItem( "Multisell", itemToTake.getObjectId(), 1, player.getTarget(), true)) { player.setMultiSell(null); return; } } } } } } } // Generate the appropriate items for (Ingredient e : entry.getProducts()) { if (e.getItemId() < 0) { MultisellData.giveSpecialProduct(e.getItemId(), e.getItemCount() * _amount, player); } else { if (e.isStackable()) { inv.addItem( "Multisell", e.getItemId(), e.getItemCount() * _amount, player, player.getTarget()); } else { L2ItemInstance product = null; for (int i = 0; i < (e.getItemCount() * _amount); i++) { product = inv.addItem("Multisell", e.getItemId(), 1, player, player.getTarget()); if ((product != null) && list.getMaintainEnchantment()) { if (i < augmentation.size()) { product.setAugmentation( new L2Augmentation(augmentation.get(i).getAugmentationId())); } if (elemental != null) { for (Elementals elm : elemental) { product.setElementAttr(elm.getElement(), elm.getValue()); } } product.setEnchantLevel(e.getEnchantLevel()); product.updateDatabase(); } } } // msg part SystemMessage sm; if ((e.getItemCount() * _amount) > 1) { sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S); sm.addItemName(e.getItemId()); sm.addLong(e.getItemCount() * _amount); player.sendPacket(sm); } else { if (list.getMaintainEnchantment() && (e.getEnchantLevel() > 0)) { sm = SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED_S1_S2); sm.addLong(e.getEnchantLevel()); sm.addItemName(e.getItemId()); } else { sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1); sm.addItemName(e.getItemId()); } player.sendPacket(sm); } } } player.sendPacket(new ItemList(player, false)); StatusUpdate su = new StatusUpdate(player); su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad()); player.sendPacket(su); // finally, give the tax to the castle... if ((npc != null) && (entry.getTaxAmount() > 0)) { npc.getCastle().addToTreasury(entry.getTaxAmount() * _amount); } break; } } }
@Override public boolean useBypass(String command, L2PcInstance activeChar, L2Character target) { final L2Npc manager = activeChar.getLastFolkNPC(); if (!((manager instanceof L2ManorManagerInstance))) { return false; } if (!activeChar.isInsideRadius(manager, L2Npc.INTERACTION_DISTANCE, true, false)) { return false; } try { final Castle castle = manager.getCastle(); if (CastleManorManager.getInstance().isUnderMaintenance()) { activeChar.sendPacket(ActionFailed.STATIC_PACKET); activeChar.sendPacket(SystemMessageId.THE_MANOR_SYSTEM_IS_CURRENTLY_UNDER_MAINTENANCE); return true; } final StringTokenizer st = new StringTokenizer(command, "&"); final int ask = Integer.parseInt(st.nextToken().split("=")[1]); final int state = Integer.parseInt(st.nextToken().split("=")[1]); final int time = Integer.parseInt(st.nextToken().split("=")[1]); final int castleId; if (state < 0) { castleId = castle.getResidenceId(); // info for current manor } else { castleId = state; // info for requested manor } switch (ask) { case 1: // Seed purchase if (castleId != castle.getResidenceId()) { SystemMessage sm = SystemMessage.getSystemMessage( SystemMessageId.HERE_YOU_CAN_BUY_ONLY_SEEDS_OF_S1_MANOR); sm.addString(manager.getCastle().getName()); activeChar.sendPacket(sm); } else { activeChar.sendPacket( new BuyListSeed( activeChar.getAdena(), castleId, castle.getSeedProduction(CastleManorManager.PERIOD_CURRENT))); } break; case 2: // Crop sales activeChar.sendPacket( new ExShowSellCropList( activeChar, castleId, castle.getCropProcure(CastleManorManager.PERIOD_CURRENT))); break; case 3: // Current seeds (Manor info) if ((time == 1) && !CastleManager.getInstance().getCastleById(castleId).isNextPeriodApproved()) { activeChar.sendPacket(new ExShowSeedInfo(castleId, null)); } else { activeChar.sendPacket( new ExShowSeedInfo( castleId, CastleManager.getInstance().getCastleById(castleId).getSeedProduction(time))); } break; case 4: // Current crops (Manor info) if ((time == 1) && !CastleManager.getInstance().getCastleById(castleId).isNextPeriodApproved()) { activeChar.sendPacket(new ExShowCropInfo(castleId, null)); } else { activeChar.sendPacket( new ExShowCropInfo( castleId, CastleManager.getInstance().getCastleById(castleId).getCropProcure(time))); } break; case 5: // Basic info (Manor info) activeChar.sendPacket(new ExShowManorDefaultInfo()); break; case 6: // Buy harvester ((L2MerchantInstance) manager).showBuyWindow(activeChar, 300000 + manager.getId()); break; case 9: // Edit sales (Crop sales) activeChar.sendPacket(new ExShowProcureCropDetail(state)); break; default: return false; } return true; } catch (Exception e) { _log.log(Level.WARNING, "Exception in " + getClass().getSimpleName(), e); } return false; }
@Override protected void runImpl() { if (_items == null) { return; } // Get the current player and return if null L2PcInstance activeChar = getClient().getActiveChar(); if (activeChar == null) { return; } if (!getClient().getFloodProtectors().getTransaction().tryPerformAction("buy")) { activeChar.sendMessage("You are buying too fast."); return; } // If Alternate rule Karma punishment is set to true, forbid Wear to player with Karma if (!Config.ALT_GAME_KARMA_PLAYER_CAN_SHOP && (activeChar.getKarma() > 0)) { return; } // Check current target of the player and the INTERACTION_DISTANCE L2Object target = activeChar.getTarget(); if (!activeChar.isGM() && ((target == null // No target (i.e. GM Shop) ) || !((target instanceof L2MerchantInstance)) // Target not a merchant || !activeChar.isInsideRadius( target, L2Npc.INTERACTION_DISTANCE, false, false) // Distance is too far )) { return; } if ((_count < 1) || (_listId >= 4000000)) { sendPacket(ActionFailed.STATIC_PACKET); return; } // Get the current merchant targeted by the player final L2MerchantInstance merchant = (target instanceof L2MerchantInstance) ? (L2MerchantInstance) target : null; if (merchant == null) { _log.warning(getClass().getName() + " Null merchant!"); return; } final L2BuyList buyList = BuyListData.getInstance().getBuyList(_listId); if (buyList == null) { Util.handleIllegalPlayerAction( activeChar, "Warning!! Character " + activeChar.getName() + " of account " + activeChar.getAccountName() + " sent a false BuyList list_id " + _listId, Config.DEFAULT_PUNISH); return; } long totalPrice = 0; Map<Integer, Integer> itemList = new HashMap<>(); for (int i = 0; i < _count; i++) { int itemId = _items[i]; final Product product = buyList.getProductByItemId(itemId); if (product == null) { Util.handleIllegalPlayerAction( activeChar, "Warning!! Character " + activeChar.getName() + " of account " + activeChar.getAccountName() + " sent a false BuyList list_id " + _listId + " and item_id " + itemId, Config.DEFAULT_PUNISH); return; } L2Item template = product.getItem(); if (template == null) { continue; } int slot = Inventory.getPaperdollIndex(template.getBodyPart()); if (slot < 0) { continue; } if (template instanceof L2Weapon) { if (activeChar.getRace().ordinal() == 5) { if (template.getItemType() == WeaponType.NONE) { continue; } else if ((template.getItemType() == WeaponType.RAPIER) || (template.getItemType() == WeaponType.CROSSBOW) || (template.getItemType() == WeaponType.ANCIENTSWORD)) { continue; } } } else if (template instanceof L2Armor) { if (activeChar.getRace().ordinal() == 5) { if ((template.getItemType() == ArmorType.HEAVY) || (template.getItemType() == ArmorType.MAGIC)) { continue; } } } if (itemList.containsKey(slot)) { activeChar.sendPacket(SystemMessageId.YOU_CAN_NOT_TRY_THOSE_ITEMS_ON_AT_THE_SAME_TIME); return; } itemList.put(slot, itemId); totalPrice += Config.WEAR_PRICE; if (totalPrice > Inventory.MAX_ADENA) { Util.handleIllegalPlayerAction( activeChar, "Warning!! Character " + activeChar.getName() + " of account " + activeChar.getAccountName() + " tried to purchase over " + Inventory.MAX_ADENA + " adena worth of goods.", Config.DEFAULT_PUNISH); return; } } // Charge buyer and add tax to castle treasury if not owned by npc clan because a Try On is not // Free if ((totalPrice < 0) || !activeChar.reduceAdena("Wear", totalPrice, activeChar.getLastFolkNPC(), true)) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA); return; } if (!itemList.isEmpty()) { activeChar.sendPacket(new ShopPreviewInfo(itemList)); // Schedule task ThreadPoolManager.getInstance() .scheduleGeneral(new RemoveWearItemsTask(activeChar), Config.WEAR_DELAY * 1000); } }