/** * Calculates quantity of items for specific drop acording to current situation
* * @param drop The L2DropData count is being calculated for * @param lastAttacker The L2PcInstance that has killed the L2Attackable * @param deepBlueDrop Factor to divide the drop chance * @param levelModifier level modifier in %'s (will be subtracted from drop chance) */ private int calculateDropCount(L2DropData drop, L2PcInstance lastAttacker, int levelModifier) { // Roll the dice.. between 0 and MAX_CHANCE (=1000000) int roll = Rnd.get(1, L2DropData.MAX_CHANCE); float rate = (drop.isSweep()? Config.RATE_DROP_SPOIL:Config.RATE_DROP_ITEMS); // Get default drop chance float dropChance = drop.getChance() * rate; int deepBlueDrop = 1; if (Config.DEEPBLUE_DROP_RULES) { if (levelModifier > 0) { // We should multiply by the server's drop rate, so we always get a low chance of drop for deep blue mobs. // NOTE: This is valid only for adena drops! Others drops will still obey server's rate deepBlueDrop = 3; if (drop.getItemId() == 57) deepBlueDrop *= (int)Config.RATE_DROP_ITEMS; } } // Check if we should apply our maths so deep blue mobs will not drop that easy if (Config.DEEPBLUE_DROP_RULES) dropChance = ((drop.getChance() - ((drop.getChance() * levelModifier)/100)) * rate / deepBlueDrop); // Round drop chance dropChance = Math.round(dropChance); // Set our limits for chance of drop if (dropChance < 1) dropChance = 1; if (drop.getItemId() == 57 && dropChance > L2DropData.MAX_CHANCE) dropChance = L2DropData.MAX_CHANCE; // If item is adena, dont drop multiple time int itemCount = 0; // Check if the Item must be dropped while (roll < dropChance) { // Get min and max Item quantity that can be dropped in one time int min = drop.getMinDrop(); int max = drop.getMaxDrop(); // Get the item quantity dropped if (min < max) itemCount += Rnd.get(min, max); else if (min == max) itemCount += min; else itemCount++; // Calculate the Adena reward with the RATE_DROP_ADENA if (drop.getItemId() == 57) itemCount *= Config.RATE_DROP_ADENA; // Prepare for next iteration if dropChance > L2DropData.MAX_CHANCE dropChance -= L2DropData.MAX_CHANCE; } if (itemCount == 0 && Config.DEBUG) _log.fine("Roll produced 0 items to drop..."); return itemCount; } /** * Calculates the level modifier for drop
* * @param lastAttacker The L2PcInstance that has killed the L2Attackable */ private int calculateLevelModifierForDrop(L2PcInstance lastAttacker) { if (Config.DEEPBLUE_DROP_RULES) { int highestLevel = lastAttacker.getLevel(); // Check to prevent very high level player to nearly kill mob and let low level player do the last hit. if (getAttackByList() != null && getAttackByList().size() > 0) { for (L2Character atkChar: getAttackByList()) if (atkChar != null && atkChar.getLevel() > highestLevel) highestLevel = atkChar.getLevel(); } // According to official data (Prima), deep blue mobs are 9 or more levels below players if (highestLevel - 9 >= getLevel()) return ((highestLevel - (getLevel() + 8)) * 9); } return 0; } private void dropItem(L2PcInstance player, int itemId, int itemCount) { L2ItemInstance dropit; int z; for (int i = 1; i <= itemCount; i++) { dropit = ItemTable.getInstance().createItem(itemId); // Set the Item quantity dropped if L2ItemInstance is stackable if (dropit.isStackable()) { i = itemCount; // Set so loop won't happent again dropit.setCount(itemCount); // Set item count } if (Config.DEBUG) _log.fine("Item id to drop: " + itemId + " amount: " + dropit.getCount()); if(this instanceof L2RaidBossInstance) { SystemMessage sm = new SystemMessage(SystemMessage.S1_DIED_DROPPED_S3_S2); sm.addString(getName()); sm.addNumber(dropit.getCount()); sm.addItemName(itemId); broadcastPacket(sm); } // Check if the autoLoot mode is active if (Config.AUTO_LOOT) player.doAutoLoot(dropit); // Give this or these Item(s) to the L2PcInstance that has killed the L2Attackable else { // Get the current Z position of the L2Character that has killed the L2Attackable z = getZ(); if (player.getZ() > z) z = player.getZ(); // Init the dropped L2ItemInstance and add it in the world as a visible object at the position where mob was last dropit.dropMe(this, getX(), getY(), z + 200); // Add drop to auto destroy item task if (Config.AUTODESTROY_ITEM_AFTER > 0) ItemsAutoDestroy.getInstance().addItem(dropit); } } } /** * Manage Sweep drops of L2Attackable.

* * Actions :

*
  • Get all possible drops of this L2Attackable from L2NpcTemplate
  • *
  • For each possible drops (base including sweep), calculate which one can is spoiled (random)
  • *
  • Get each Item spoiled quantity (random)
  • *
  • Create this or these L2ItemInstance corresponding to each Item Identifier spoiled
  • *
  • Add each of those L2ItemInstance to the table _sweepItems of this L2Attackable containing all Items that can be spoiled


  • * * @param lastAttacker The L2Character that has killed the L2Attackable */ public void doSweepDrop(L2Character lastAttacker) { L2PcInstance player = null; if (lastAttacker instanceof L2PcInstance) player = (L2PcInstance)lastAttacker; else if (lastAttacker instanceof L2Summon) player = ((L2Summon)lastAttacker).getOwner(); if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance int levelModifier = calculateLevelModifierForDrop(player);; // level modifier in %'s (will be subtracted from drop chance) // Create a table containing all possible drops of this L2Attackable from L2NpcTemplate List drops = getTemplate().getDropData(); if (Config.DEBUG) _log.finer("this npc has "+drops.size()+" drops defined"); // Create a table that will contain all Items that can be spoiled List spoiled = new FastList(); // Go Throw all possible drops (base including sweep) of this L2Attackable L2ItemInstance dropit; int itemCount; for (L2DropData drop: drops) { if (drop == null) continue; // If it's not a sweep drop, it will not appear on the ground only drop adena if seeded with low-grade seed if (!drop.isSweep() || (isSeeded() && !isSeededHigh() && drop.getItemId() != 57)) continue; // Calculates Item drop count with current rates... itemCount = calculateDropCount(drop, player, levelModifier); for (int i = 1; i <= itemCount; i++) { dropit = ItemTable.getInstance().createItem(drop.getItemId()); // Set the Item quantity dropped if L2ItemInstance is stackable if (dropit.isStackable()) { i = itemCount; // Set so loop won't happent again dropit.setCount(itemCount); // Set item count } spoiled.add(dropit); if (Config.DEBUG) _log.fine("Item id to spoil: " + drop.getItemId() + " amount: " + dropit.getCount()); } } // Set the table _sweepItems of this L2Attackable if (spoiled.size() > 0) _sweepItems = spoiled.toArray(new L2ItemInstance[spoiled.size()]); } /** * Manage Special Events drops created by GM for a defined period.

    * * Concept :

    * During a Special Event all L2Attackable can drop extra Items. * Those extra Items are defined in the table allNpcDateDrops of the EventDroplist. * Each Special Event has a start and end date to stop to drop extra Items automaticaly.

    * * Actions : If an extra drop must be generated

    *
  • Get an Item Identifier (random) from the DateDrop Item table of this Event
  • *
  • Get the Item quantity dropped (random)
  • *
  • Create this or these L2ItemInstance corresponding to this Item Identifier
  • *
  • If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  • *
  • If the autoLoot mode isn't actif or if the L2Character that has killed the L2Attackable is not a L2PcInstance, add this or these Item(s) in the world as a visible object at the position where mob was last


  • * * @param lastAttacker The L2Character that has killed the L2Attackable */ public void doEventDrop(L2Character lastAttacker) { L2PcInstance player = null; if (lastAttacker instanceof L2PcInstance) player = (L2PcInstance)lastAttacker; else if (lastAttacker instanceof L2Summon) player = ((L2Summon)lastAttacker).getOwner(); if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance if (player.getLevel() - getLevel() > 9) return; // Go through DateDrop of EventDroplist allNpcDateDrops within the date range int itemCount; int max; int min; for (DateDrop drop : EventDroplist.getInstance().getAllDrops()) { if (Rnd.get(1, L2DropData.MAX_CHANCE) < drop.chance) { // Get min and max Item quantity that can be dropped in one time max = drop.max; min = drop.min; // Get the item quantity dropped itemCount = 0; if (min < max) itemCount += Rnd.get(min, max); else if (min == max) itemCount += min; else itemCount++; dropItem(player, drop.items[Rnd.get(0, drop.items.length - 1)], itemCount); } } } /** * Manage Base, Quests and Special Events drops of L2Attackable (called by calculateRewards).

    * * Concept :

    * During a Special Event all L2Attackable can drop extra Items. * Those extra Items are defined in the table allNpcDateDrops of the EventDroplist. * Each Special Event has a start and end date to stop to drop extra Items automaticaly.

    * * Actions :

    *
  • Manage drop of Special Events created by GM for a defined period
  • *
  • Get all possible drops of this L2Attackable from L2NpcTemplate and add it Quest drops
  • *
  • For each possible drops (base + quests), calculate which one must be dropped (random)
  • *
  • Get each Item quantity dropped (random)
  • *
  • Create this or these L2ItemInstance corresponding to each Item Identifier dropped
  • *
  • If the autoLoot mode is actif and if the L2Character that has killed the L2Attackable is a L2PcInstance, give this or these Item(s) to the L2PcInstance that has killed the L2Attackable
  • *
  • If the autoLoot mode isn't actif or if the L2Character that has killed the L2Attackable is not a L2PcInstance, add this or these Item(s) in the world as a visible object at the position where mob was last


  • * * @param lastAttacker The L2Character that has killed the L2Attackable */ public void doItemDrop(L2Character lastAttacker) { L2PcInstance player = null; if (lastAttacker instanceof L2PcInstance) player = (L2PcInstance)lastAttacker; else if (lastAttacker instanceof L2Summon) player = ((L2Summon)lastAttacker).getOwner(); if (player == null) return; // Don't drop anything if the last attacker or ownere isn't L2PcInstance int levelModifier = calculateLevelModifierForDrop(player);; // level modifier in %'s (will be subtracted from drop chance) // Manage drop of Special Events created by GM for a defined period doEventDrop(lastAttacker); // Create a table containing all possible drops of this L2Attackable from L2NpcTemplate List drops = new FastList(); drops.addAll(getTemplate().getDropData()); if (Config.DEBUG) _log.finer("this npc has "+drops.size()+" drops defined"); // Add Quest drops to the table containing all possible drops of this L2Attackable player.fillQuestDrops(this, drops); // Go Throw all possible drops (base + quests) of this L2Attackable for (L2DropData drop : drops) { if (drop == null) continue; // If it's a sweep drop, it will not appear on the ground if (drop.isSweep()) continue; dropItem(player, drop.getItemId(), calculateDropCount(drop, player, calculateDropCount(drop, player, levelModifier))); } }