diff --git a/trunk/dist/game/config/Custom.ini b/trunk/dist/game/config/Custom.ini index 88bb0e3dc8..4b6372af5a 100644 --- a/trunk/dist/game/config/Custom.ini +++ b/trunk/dist/game/config/Custom.ini @@ -474,6 +474,18 @@ DualboxCheckWhitelist = 127.0.0.1,0 AllowChangePassword = False +# --------------------------------------------------------------------------- +# Old Drop Behavior +# --------------------------------------------------------------------------- + +# Enables L2J old drop behavior +# The old L2J system used to add amount of items drop per 100% range of chance. +# For example, if chance is 230% when rate are applied, it will do : +# amount dropped = (2 * getRandomAmount(min,max)) + 30% chance to get ad additional getRandomAmount(min,max) +# Default : False +OldDropBehavior = False + + # --------------------------------------------------------------------------- # Allowed Player Races # --------------------------------------------------------------------------- @@ -698,10 +710,16 @@ PremiumRateDropChance = 1 # Drop amount for premium players. PremiumRateDropAmount = 2 +# Spoil chance for premium players. +PremiumRateSpoilChance = 1 + +# Spoil amount for premium players. +PremiumRateSpoilAmount = 2 + # List of items affected by custom drop rate by id, used now for Adena rate too. # Usage: itemId1,multiplier1;itemId2,multiplier2;... -PremiumDropChanceMultiplierByItemId = 57,1 -PremiumDropAmountMultiplierByItemId = 57,2 +PremiumRateDropChanceByItemId = 57,2;6656,1;6657,1;6658,1;6659,1;6660,1;6661,1;6662,1;8191,1;10170,1;10314,1 +PremiumRateDropAmountByItemId = 57,2;6656,1;6657,1;6658,1;6659,1;6660,1;6661,1;6662,1;8191,1;10170,1;10314,1 # --------------------------------------------------------------------------- diff --git a/trunk/dist/game/config/NPC.ini b/trunk/dist/game/config/NPC.ini index 99f9e2c6a7..f31ef9faf8 100644 --- a/trunk/dist/game/config/NPC.ini +++ b/trunk/dist/game/config/NPC.ini @@ -194,14 +194,6 @@ IgnoreNpcStatFormulas = True # Drops # --------------------------------------------------------------------------- -# If True, activates bellow level gap rules for standard mobs: -# Default: True -UseDeepBlueDropRules = True - -# If True, activates bellow level gap rules for raid bosses: -# Default: True -UseDeepBlueDropRulesRaid = True - # The min and max level difference used for level gap calculation # this is only for how many levels higher the player is than the monster # Default: 8 diff --git a/trunk/dist/game/config/Rates.ini b/trunk/dist/game/config/Rates.ini index f79e429429..bbe8795111 100644 --- a/trunk/dist/game/config/Rates.ini +++ b/trunk/dist/game/config/Rates.ini @@ -9,7 +9,8 @@ # --------------------------------------------------------------------------- # Item Rates # --------------------------------------------------------------------------- -# Warning: Remember if you increase both chance and amount you will have higher rates than expected +# Warning: to achieve old l2j behavior before drops rework you need to enable OldDropBehavior in Custom.ini +# and increase only chance multipliers! Remember if you increase both chance and amount you will have higher rates than expected # Example: if amount multiplier is 5 and chance multiplier is 5 you will end up with 5*5 = 25 drop rates so be careful! # Multiplies the amount of items dropped from monster on ground when it dies. diff --git a/trunk/dist/game/data/scripts/handlers/bypasshandlers/NpcViewMod.java b/trunk/dist/game/data/scripts/handlers/bypasshandlers/NpcViewMod.java index 2b2a3cdb69..fe7dc63404 100644 --- a/trunk/dist/game/data/scripts/handlers/bypasshandlers/NpcViewMod.java +++ b/trunk/dist/game/data/scripts/handlers/bypasshandlers/NpcViewMod.java @@ -77,7 +77,7 @@ public class NpcViewMod implements IBypassHandler { target = L2World.getInstance().findObject(Integer.parseInt(st.nextToken())); } - catch (NumberFormatException e) + catch (final NumberFormatException e) { return false; } @@ -116,11 +116,11 @@ public class NpcViewMod implements IBypassHandler } sendNpcDropList(activeChar, npc, dropListScope, st.hasMoreElements() ? Integer.parseInt(st.nextToken()) : 0); } - catch (NumberFormatException e) + catch (final NumberFormatException e) { return false; } - catch (IllegalArgumentException e) + catch (final IllegalArgumentException e) { _log.warning("Bypass[NpcViewMod] unknown drop list scope: " + dropListScopeString); return false; @@ -155,7 +155,7 @@ public class NpcViewMod implements IBypassHandler { TimeUnit timeUnit = TimeUnit.MILLISECONDS; long min = Long.MAX_VALUE; - for (TimeUnit tu : TimeUnit.values()) + for (final TimeUnit tu : TimeUnit.values()) { final long minTimeFromMillis = tu.convert(npcSpawn.getRespawnMinDelay(), TimeUnit.MILLISECONDS); final long maxTimeFromMillis = tu.convert(npcSpawn.getRespawnMaxDelay(), TimeUnit.MILLISECONDS); @@ -287,7 +287,34 @@ public class NpcViewMod implements IBypassHandler final IDropItem dropItem = dropList.get(i); if (dropItem instanceof GeneralDropItem) { - addGeneralDropItem(activeChar, npc, amountFormat, chanceFormat, sb, (GeneralDropItem) dropItem); + final GeneralDropItem generalDropItem = (GeneralDropItem) dropItem; + final L2Item item = ItemTable.getInstance().getTemplate(generalDropItem.getItemId()); + sb.append(""); + sb.append("
"); + sb.append(""); + sb.append(""); + sb.append(item.getName()); + sb.append("
"); + sb.append(""); + sb.append(""); + sb.append("
Amount:"); + + final long min = generalDropItem.getMin(npc, activeChar); + final long max = generalDropItem.getMax(npc, activeChar); + if (min == max) + { + sb.append(amountFormat.format(min)); + } + else + { + sb.append(amountFormat.format(min)); + sb.append(" - "); + sb.append(amountFormat.format(max)); + } + + sb.append("
Chance:"); + sb.append(chanceFormat.format(Math.min(generalDropItem.getChance(npc, activeChar), 100))); + sb.append("%
 
"); } else if (dropItem instanceof GroupedGeneralDropItem) { @@ -295,21 +322,46 @@ public class NpcViewMod implements IBypassHandler if (generalGroupedDropItem.getItems().size() == 1) { final GeneralDropItem generalDropItem = generalGroupedDropItem.getItems().get(0); - addGeneralDropItem(activeChar, npc, amountFormat, chanceFormat, sb, new GeneralDropItem(generalDropItem.getItemId(), generalDropItem.getMin(), generalDropItem.getMax(), (generalDropItem.getChance(npc, activeChar) * generalGroupedDropItem.getChance()) / 100, generalDropItem.getAmountStrategy(), generalDropItem.getChanceStrategy(), generalGroupedDropItem.getPreciseStrategy(), generalGroupedDropItem.getKillerChanceModifierStrategy(), generalDropItem.getDropCalculationStrategy())); + final L2Item item = ItemTable.getInstance().getTemplate(generalDropItem.getItemId()); + sb.append(""); + sb.append("
"); + sb.append(""); + sb.append(""); + sb.append(item.getName()); + sb.append("
"); + sb.append(""); + sb.append(""); + sb.append("
Amount:"); + + final long min = generalDropItem.getMin(npc, activeChar); + final long max = generalDropItem.getMax(npc, activeChar); + if (min == max) + { + sb.append(amountFormat.format(min)); + } + else + { + sb.append(amountFormat.format(min)); + sb.append(" - "); + sb.append(amountFormat.format(max)); + } + + sb.append("
Chance:"); + sb.append(chanceFormat.format(Math.min(generalGroupedDropItem.getChance(npc, activeChar), 100))); + sb.append("%
 
"); } else { - final GroupedGeneralDropItem normalized = generalGroupedDropItem.normalizeMe(npc, activeChar); sb.append(""); sb.append(""); sb.append("
One from group"); sb.append("
"); sb.append(""); sb.append("
Chance:"); - sb.append(chanceFormat.format(Math.min(normalized.getChance(), 100))); + sb.append(chanceFormat.format(Math.min(generalGroupedDropItem.getChance(npc, activeChar), 100))); sb.append("%

"); - for (GeneralDropItem generalDropItem : normalized.getItems()) + for (final GeneralDropItem generalDropItem : generalGroupedDropItem.getItems()) { final L2Item item = ItemTable.getInstance().getTemplate(generalDropItem.getItemId()); sb.append(""); @@ -324,9 +376,9 @@ public class NpcViewMod implements IBypassHandler sb.append(item.getName()); sb.append("
"); sb.append(""); html.append("
"); html.append("
"); + html.append("
"); + html.append("
"); html.append(""); html.append(""); html.append(""); html.append(""); html.append(""); + html.append(""); + html.append(""); html.append(""); html.append(""); html.append(""); @@ -67,6 +71,8 @@ public class Premium implements IVoicedCommandHandler html.append(""); html.append(""); html.append(""); + html.append(""); + html.append(""); html.append(""); html.append(""); html.append(""); diff --git a/trunk/dist/game/data/scripts/quests/Q10751_WindsOfFateEncounters/Q10751_WindsOfFateEncounters.java b/trunk/dist/game/data/scripts/quests/Q10751_WindsOfFateEncounters/Q10751_WindsOfFateEncounters.java index d0e5b7eaef..02197a4eba 100644 --- a/trunk/dist/game/data/scripts/quests/Q10751_WindsOfFateEncounters/Q10751_WindsOfFateEncounters.java +++ b/trunk/dist/game/data/scripts/quests/Q10751_WindsOfFateEncounters/Q10751_WindsOfFateEncounters.java @@ -222,12 +222,12 @@ public class Q10751_WindsOfFateEncounters extends Quest implements IBypassHandle if (classId == 184) { htmltext = "33943-ccf.html"; - giveItems(player, NAVARIS_SUPPORT_BOX_F, 1); + giveItems(player, NAVARIS_SUPPORT_BOX_F); } else if (classId == 185) { htmltext = "33942-ccm.html"; - giveItems(player, NAVARIS_SUPPORT_BOX_M, 1); + giveItems(player, NAVARIS_SUPPORT_BOX_M); } player.broadcastUserInfo(); qs.exitQuest(false, true); diff --git a/trunk/java/com/l2jmobius/Config.java b/trunk/java/com/l2jmobius/Config.java index c4e45c6841..0d88876a1e 100644 --- a/trunk/java/com/l2jmobius/Config.java +++ b/trunk/java/com/l2jmobius/Config.java @@ -492,7 +492,6 @@ public final class Config public static int SAVE_DROPPED_ITEM_INTERVAL; public static boolean CLEAR_DROPPED_ITEM_TABLE; public static boolean AUTODELETE_INVALID_QUEST_DATA; - public static boolean PRECISE_DROP_CALCULATION; public static boolean MULTIPLE_ITEM_DROP; public static boolean FORCE_INVENTORY_UPDATE; public static boolean LAZY_CACHE; @@ -782,6 +781,7 @@ public final class Config public static int L2JMOD_DUALBOX_CHECK_MAX_L2EVENT_PARTICIPANTS_PER_IP; public static Map L2JMOD_DUALBOX_CHECK_WHITELIST; public static boolean L2JMOD_ALLOW_CHANGE_PASSWORD; + public static boolean L2JMOD_OLD_DROP_BEHAVIOR; public static boolean ALLOW_HUMAN; public static boolean ALLOW_ELF; public static boolean ALLOW_DARKELF; @@ -828,10 +828,13 @@ public final class Config public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; public static float PREMIUM_RATE_SP; + public static Map PREMIUM_RATE_DROP_ITEMS_ID; public static float PREMIUM_RATE_DROP_CHANCE; public static float PREMIUM_RATE_DROP_AMOUNT; - public static Map PREMIUM_RATE_DROP_CHANCE_MULTIPLIER; - public static Map PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER; + public static float PREMIUM_RATE_SPOIL_CHANCE; + public static float PREMIUM_RATE_SPOIL_AMOUNT; + public static Map PREMIUM_RATE_DROP_CHANCE_BY_ID; + public static Map PREMIUM_RATE_DROP_AMOUNT_BY_ID; public static boolean PC_BANG_ENABLED; public static int PC_BANG_MAX_POINTS; public static boolean PC_BANG_ENABLE_DOUBLE_POINTS; @@ -849,8 +852,6 @@ public final class Config public static boolean ALT_ATTACKABLE_NPCS; public static boolean ALT_GAME_VIEWNPC; public static int MAX_DRIFT_RANGE; - public static boolean DEEPBLUE_DROP_RULES; - public static boolean DEEPBLUE_DROP_RULES_RAID; public static boolean SHOW_NPC_LVL; public static boolean SHOW_CREST_WITHOUT_QUEST; public static boolean ENABLE_RANDOM_ENCHANT_EFFECT; @@ -935,8 +936,8 @@ public final class Config public static float RATE_CORPSE_DROP_CHANCE_MULTIPLIER; public static float RATE_HERB_DROP_CHANCE_MULTIPLIER; public static float RATE_RAID_DROP_CHANCE_MULTIPLIER; - public static Map RATE_DROP_AMOUNT_MULTIPLIER; - public static Map RATE_DROP_CHANCE_MULTIPLIER; + public static Map RATE_DROP_AMOUNT_BY_ID; + public static Map RATE_DROP_CHANCE_BY_ID; public static float RATE_KARMA_LOST; public static float RATE_KARMA_EXP_LOST; public static float RATE_SIEGE_GUARDS_PRICE; @@ -1840,7 +1841,6 @@ public final class Config SAVE_DROPPED_ITEM_INTERVAL = General.getInt("SaveDroppedItemInterval", 60) * 60000; CLEAR_DROPPED_ITEM_TABLE = General.getBoolean("ClearDroppedItemTable", false); AUTODELETE_INVALID_QUEST_DATA = General.getBoolean("AutoDeleteInvalidQuestData", false); - PRECISE_DROP_CALCULATION = General.getBoolean("PreciseDropCalculation", true); MULTIPLE_ITEM_DROP = General.getBoolean("MultipleItemDrop", true); FORCE_INVENTORY_UPDATE = General.getBoolean("ForceInventoryUpdate", false); LAZY_CACHE = General.getBoolean("LazyCache", true); @@ -2016,8 +2016,6 @@ public final class Config ALT_ATTACKABLE_NPCS = NPC.getBoolean("AltAttackableNpcs", true); ALT_GAME_VIEWNPC = NPC.getBoolean("AltGameViewNpc", false); MAX_DRIFT_RANGE = NPC.getInt("MaxDriftRange", 300); - DEEPBLUE_DROP_RULES = NPC.getBoolean("UseDeepBlueDropRules", true); - DEEPBLUE_DROP_RULES_RAID = NPC.getBoolean("UseDeepBlueDropRulesRaid", true); SHOW_NPC_LVL = NPC.getBoolean("ShowNpcLevel", false); SHOW_CREST_WITHOUT_QUEST = NPC.getBoolean("ShowCrestWithoutQuest", false); ENABLE_RANDOM_ENCHANT_EFFECT = NPC.getBoolean("EnableRandomEnchantEffect", false); @@ -2142,8 +2140,9 @@ public final class Config RATE_CORPSE_DROP_CHANCE_MULTIPLIER = RatesSettings.getFloat("CorpseDropChanceMultiplier", 1); RATE_HERB_DROP_CHANCE_MULTIPLIER = RatesSettings.getFloat("HerbDropChanceMultiplier", 1); RATE_RAID_DROP_CHANCE_MULTIPLIER = RatesSettings.getFloat("RaidDropChanceMultiplier", 1); + final String[] dropAmountMultiplier = RatesSettings.getString("DropAmountMultiplierByItemId", "").split(";"); - RATE_DROP_AMOUNT_MULTIPLIER = new HashMap<>(dropAmountMultiplier.length); + RATE_DROP_AMOUNT_BY_ID = new HashMap<>(dropAmountMultiplier.length); if (!dropAmountMultiplier[0].isEmpty()) { for (String item : dropAmountMultiplier) @@ -2157,7 +2156,7 @@ public final class Config { try { - RATE_DROP_AMOUNT_MULTIPLIER.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); + RATE_DROP_AMOUNT_BY_ID.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); } catch (NumberFormatException nfe) { @@ -2171,7 +2170,7 @@ public final class Config } final String[] dropChanceMultiplier = RatesSettings.getString("DropChanceMultiplierByItemId", "").split(";"); - RATE_DROP_CHANCE_MULTIPLIER = new HashMap<>(dropChanceMultiplier.length); + RATE_DROP_CHANCE_BY_ID = new HashMap<>(dropChanceMultiplier.length); if (!dropChanceMultiplier[0].isEmpty()) { for (String item : dropChanceMultiplier) @@ -2185,7 +2184,7 @@ public final class Config { try { - RATE_DROP_CHANCE_MULTIPLIER.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); + RATE_DROP_CHANCE_BY_ID.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); } catch (NumberFormatException nfe) { @@ -2245,6 +2244,8 @@ public final class Config L2JMOD_ENABLE_WAREHOUSESORTING_CLAN = CustomSettings.getBoolean("EnableWarehouseSortingClan", false); L2JMOD_ENABLE_WAREHOUSESORTING_PRIVATE = CustomSettings.getBoolean("EnableWarehouseSortingPrivate", false); + L2JMOD_OLD_DROP_BEHAVIOR = CustomSettings.getBoolean("OldDropBehavior", false); + if (TVT_EVENT_PARTICIPATION_NPC_ID == 0) { TVT_EVENT_ENABLED = false; @@ -2610,57 +2611,59 @@ public final class Config PREMIUM_SYSTEM_ENABLED = CustomSettings.getBoolean("EnablePremiumSystem", false); PREMIUM_RATE_XP = CustomSettings.getFloat("PremiumRateXp", 2); PREMIUM_RATE_SP = CustomSettings.getFloat("PremiumRateSp", 2); - PREMIUM_RATE_DROP_CHANCE = CustomSettings.getFloat("PremiumRateDropChance", 1); - PREMIUM_RATE_DROP_AMOUNT = CustomSettings.getFloat("PremiumRateDropAmount", 2); - final String[] premiumDropChanceMultiplier = CustomSettings.getString("PremiumDropChanceMultiplierByItemId", "").split(";"); - PREMIUM_RATE_DROP_CHANCE_MULTIPLIER = new HashMap<>(premiumDropChanceMultiplier.length); + PREMIUM_RATE_DROP_CHANCE = CustomSettings.getFloat("PremiumRateDropChance", 2); + PREMIUM_RATE_DROP_AMOUNT = CustomSettings.getFloat("PremiumRateDropAmount", 1); + PREMIUM_RATE_SPOIL_CHANCE = CustomSettings.getFloat("PremiumRateSpoilChance", 2); + PREMIUM_RATE_SPOIL_AMOUNT = CustomSettings.getFloat("PremiumRateSpoilAmount", 1); + String[] premiumDropChanceMultiplier = CustomSettings.getString("PremiumRateDropChanceByItemId", "").split(";"); + PREMIUM_RATE_DROP_CHANCE_BY_ID = new HashMap<>(premiumDropChanceMultiplier.length); if (!premiumDropChanceMultiplier[0].isEmpty()) { for (String item : premiumDropChanceMultiplier) { - final String[] itemSplit = item.split(","); + String[] itemSplit = item.split(","); if (itemSplit.length != 2) { - _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumDropChanceMultiplierByItemId \"", item, "\"")); + _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumRateDropChanceByItemId \"", item, "\"")); } else { try { - PREMIUM_RATE_DROP_CHANCE_MULTIPLIER.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); + PREMIUM_RATE_DROP_CHANCE_BY_ID.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); } catch (NumberFormatException nfe) { if (!item.isEmpty()) { - _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumDropChanceMultiplierByItemId \"", item, "\"")); + _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumRateDropChanceByItemId \"", item, "\"")); } } } } } - final String[] premiumDropAmountMultiplier = CustomSettings.getString("PremiumDropAmountMultiplierByItemId", "").split(";"); - PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER = new HashMap<>(premiumDropAmountMultiplier.length); + String[] premiumDropAmountMultiplier = CustomSettings.getString("PremiumRateDropAmountByItemId", "").split(";"); + PREMIUM_RATE_DROP_AMOUNT_BY_ID = new HashMap<>(premiumDropAmountMultiplier.length); if (!premiumDropAmountMultiplier[0].isEmpty()) { for (String item : premiumDropAmountMultiplier) { - final String[] itemSplit = item.split(","); + String[] itemSplit = item.split(","); if (itemSplit.length != 2) { - _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumDropAmountMultiplierByItemId \"", item, "\"")); + _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumRateDropAmountByItemId \"", item, "\"")); } else { try { - PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); + PREMIUM_RATE_DROP_AMOUNT_BY_ID.put(Integer.valueOf(itemSplit[0]), Float.valueOf(itemSplit[1])); } catch (NumberFormatException nfe) { if (!item.isEmpty()) { - _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumDropAmountMultiplierByItemId \"", item, "\"")); + _log.warning(StringUtil.concat("Config.load(): invalid config property -> PremiumRateDropAmountByItemId \"", item, "\"")); } } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/CorpseDropItem.java b/trunk/java/com/l2jmobius/gameserver/model/drops/CorpseDropItem.java new file mode 100644 index 0000000000..7b5009acdc --- /dev/null +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/CorpseDropItem.java @@ -0,0 +1,56 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.drops; + +import com.l2jmobius.Config; + +/** + * @author NosBit + */ +public class CorpseDropItem extends GeneralDropItem +{ + /** + * @param itemId the item id + * @param min the min count + * @param max the max count + * @param chance the chance of this drop item + */ + public CorpseDropItem(int itemId, long min, long max, double chance) + { + super(itemId, min, max, chance); + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getGlobalAmountMultiplier() + */ + @Override + protected double getGlobalAmountMultiplier(boolean isPremium) + { + return isPremium ? Config.PREMIUM_RATE_SPOIL_AMOUNT * Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER : Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER; + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getGlobalChanceMultiplier() + */ + @Override + protected double getGlobalChanceMultiplier(boolean isPremium) + { + return isPremium ? Config.PREMIUM_RATE_SPOIL_CHANCE * Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER : Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER; + } +} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/DeathDropItem.java b/trunk/java/com/l2jmobius/gameserver/model/drops/DeathDropItem.java new file mode 100644 index 0000000000..f8dda068f3 --- /dev/null +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/DeathDropItem.java @@ -0,0 +1,56 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.drops; + +import com.l2jmobius.Config; + +/** + * @author NosBit + */ +public class DeathDropItem extends GeneralDropItem +{ + /** + * @param itemId the item id + * @param min the min count + * @param max the max count + * @param chance the chance of this drop item + */ + public DeathDropItem(int itemId, long min, long max, double chance) + { + super(itemId, min, max, chance); + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getGlobalAmountMultiplier() + */ + @Override + protected double getGlobalAmountMultiplier(boolean isPremium) + { + return isPremium ? Config.PREMIUM_RATE_DROP_AMOUNT * Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER : Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER; + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getGlobalChanceMultiplier() + */ + @Override + protected double getGlobalChanceMultiplier(boolean isPremium) + { + return isPremium ? Config.PREMIUM_RATE_DROP_CHANCE * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER : Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER; + } +} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/DropListScope.java b/trunk/java/com/l2jmobius/gameserver/model/drops/DropListScope.java index 426cef32c0..47ef304167 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/DropListScope.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/DropListScope.java @@ -16,44 +16,75 @@ */ package com.l2jmobius.gameserver.model.drops; -import com.l2jmobius.gameserver.model.drops.strategy.IAmountMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IChanceMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IGroupedItemDropCalculationStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @author NosBit */ -public enum DropListScope implements IDropItemFactory, IGroupedDropItemFactory +public enum DropListScope { - DEATH((itemId, min, max, chance) -> new GeneralDropItem(itemId, min, max, chance, IAmountMultiplierStrategy.DROP, IChanceMultiplierStrategy.DROP), chance -> new GroupedGeneralDropItem(chance)), - CORPSE((itemId, min, max, chance) -> new GeneralDropItem(itemId, min, max, chance, IAmountMultiplierStrategy.SPOIL, IChanceMultiplierStrategy.SPOIL), DEATH), + DEATH(DeathDropItem.class, GroupedDeathDropItem.class), + CORPSE(CorpseDropItem.class, GroupedCorpseDropItem.class); - /** - * This droplist scope isn't affected by ANY rates, nor Champion, etc... - */ - STATIC((itemId, min, max, chance) -> new GeneralDropItem(itemId, min, max, chance, IAmountMultiplierStrategy.STATIC, IChanceMultiplierStrategy.STATIC, IPreciseDeterminationStrategy.ALWAYS, IKillerChanceModifierStrategy.NO_RULES), chance -> new GroupedGeneralDropItem(chance, IGroupedItemDropCalculationStrategy.DEFAULT_STRATEGY, IKillerChanceModifierStrategy.NO_RULES, IPreciseDeterminationStrategy.ALWAYS)), - QUEST((itemId, min, max, chance) -> new GeneralDropItem(itemId, min, max, chance, IAmountMultiplierStrategy.STATIC, IChanceMultiplierStrategy.QUEST, IPreciseDeterminationStrategy.ALWAYS, IKillerChanceModifierStrategy.NO_RULES), STATIC); + private static final Logger _log = Logger.getLogger(DropListScope.class.getName()); - private final IDropItemFactory _factory; - private final IGroupedDropItemFactory _groupFactory; + private final Class _dropItemClass; + private final Class _groupedDropItemClass; - private DropListScope(IDropItemFactory factory, IGroupedDropItemFactory groupFactory) + private DropListScope(Class dropItemClass, Class groupedDropItemClass) { - _factory = factory; - _groupFactory = groupFactory; + _dropItemClass = dropItemClass; + _groupedDropItemClass = groupedDropItemClass; } - @Override public IDropItem newDropItem(int itemId, long min, long max, double chance) { - return _factory.newDropItem(itemId, min, max, chance); + final Constructor constructor; + try + { + constructor = _dropItemClass.getConstructor(int.class, long.class, long.class, double.class); + } + catch (NoSuchMethodException | SecurityException e) + { + _log.log(Level.SEVERE, "Constructor(int, long, long, double) not found for " + _dropItemClass.getSimpleName(), e); + return null; + } + + try + { + return constructor.newInstance(itemId, min, max, chance); + } + catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) + { + _log.log(Level.SEVERE, "", e); + return null; + } } - @Override public GroupedGeneralDropItem newGroupedDropItem(double chance) { - return _groupFactory.newGroupedDropItem(chance); + final Constructor constructor; + try + { + constructor = _groupedDropItemClass.getConstructor(double.class); + } + catch (NoSuchMethodException | SecurityException e) + { + _log.log(Level.SEVERE, "Constructor(double) not found for " + _groupedDropItemClass.getSimpleName(), e); + return null; + } + + try + { + return constructor.newInstance(chance); + } + catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) + { + _log.log(Level.SEVERE, "", e); + return null; + } } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/GeneralDropItem.java b/trunk/java/com/l2jmobius/gameserver/model/drops/GeneralDropItem.java index fe0e04f333..689fcc05cf 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/GeneralDropItem.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/GeneralDropItem.java @@ -16,34 +16,28 @@ */ package com.l2jmobius.gameserver.model.drops; -import java.util.List; +import java.util.ArrayList; +import java.util.Collection; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.strategy.IAmountMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IChanceMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IDropCalculationStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.INonGroupedKillerChanceModifierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.itemcontainer.Inventory; +import com.l2jmobius.gameserver.model.items.L2Item; +import com.l2jmobius.gameserver.util.Util; +import com.l2jmobius.util.Rnd; /** * @author NosBit */ -public final class GeneralDropItem implements IDropItem +public class GeneralDropItem implements IDropItem { private final int _itemId; private final long _min; private final long _max; private final double _chance; - protected final IAmountMultiplierStrategy _amountStrategy; - protected final IChanceMultiplierStrategy _chanceStrategy; - protected final IPreciseDeterminationStrategy _preciseStrategy; - protected final INonGroupedKillerChanceModifierStrategy _killerStrategy; - protected final IDropCalculationStrategy _dropCalculationStrategy; - /** * @param itemId the item id * @param min the min count @@ -51,225 +45,243 @@ public final class GeneralDropItem implements IDropItem * @param chance the chance of this drop item */ public GeneralDropItem(int itemId, long min, long max, double chance) - { - this(itemId, min, max, chance, 1, 1); - } - - public GeneralDropItem(int itemId, long min, long max, double chance, double defaultAmountMultiplier, double defaultChanceMultiplier) - { - this(itemId, min, max, defaultChanceMultiplier, IAmountMultiplierStrategy.DEFAULT_STRATEGY(defaultAmountMultiplier), IChanceMultiplierStrategy.DEFAULT_STRATEGY(defaultChanceMultiplier)); - } - - public GeneralDropItem(int itemId, long min, long max, double chance, IAmountMultiplierStrategy amountMultiplierStrategy, IChanceMultiplierStrategy chanceMultiplierStrategy) - { - this(itemId, min, max, chance, amountMultiplierStrategy, chanceMultiplierStrategy, IPreciseDeterminationStrategy.DEFAULT, IKillerChanceModifierStrategy.DEFAULT_NONGROUP_STRATEGY); - } - - public GeneralDropItem(int itemId, long min, long max, double chance, IAmountMultiplierStrategy amountMultiplierStrategy, IChanceMultiplierStrategy chanceMultiplierStrategy, IPreciseDeterminationStrategy preciseStrategy, INonGroupedKillerChanceModifierStrategy killerStrategy) - { - this(itemId, min, max, chance, amountMultiplierStrategy, chanceMultiplierStrategy, preciseStrategy, killerStrategy, IDropCalculationStrategy.DEFAULT_STRATEGY); - } - - public GeneralDropItem(int itemId, long min, long max, double chance, IAmountMultiplierStrategy amountMultiplierStrategy, IChanceMultiplierStrategy chanceMultiplierStrategy, IPreciseDeterminationStrategy preciseStrategy, INonGroupedKillerChanceModifierStrategy killerStrategy, IDropCalculationStrategy dropCalculationStrategy) { _itemId = itemId; _min = min; _max = max; _chance = chance; - _amountStrategy = amountMultiplierStrategy; - _chanceStrategy = chanceMultiplierStrategy; - _preciseStrategy = preciseStrategy; - _killerStrategy = killerStrategy; - _dropCalculationStrategy = dropCalculationStrategy; } - /** - * @return the _amountStrategy - */ - public final IAmountMultiplierStrategy getAmountStrategy() + protected double getGlobalChanceMultiplier(boolean isPremium) { - return _amountStrategy; + return 1.; } - /** - * @return the _chanceStrategy - */ - public final IChanceMultiplierStrategy getChanceStrategy() + protected double getGlobalAmountMultiplier(boolean isPremium) { - return _chanceStrategy; + return 1.; } - /** - * @return the _preciseStrategy - */ - public final IPreciseDeterminationStrategy getPreciseStrategy() + private final long getMinMax(L2Character victim, L2Character killer, long val) { - return _preciseStrategy; - } - - /** - * @return the _killerStrategy - */ - public final INonGroupedKillerChanceModifierStrategy getKillerChanceModifierStrategy() - { - return _killerStrategy; - } - - /** - * @return the _dropCalculationStrategy - */ - public final IDropCalculationStrategy getDropCalculationStrategy() - { - return _dropCalculationStrategy; + double multiplier = 1; + + // individual drop amount + Float individualDropAmountMultiplier = null; + if (killer.getActingPlayer().hasPremiumStatus()) + { + final Float normalMultiplier = Config.RATE_DROP_AMOUNT_BY_ID.get(getItemId()); + final Float premiumMultiplier = Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(getItemId()); + if ((normalMultiplier != null) && (premiumMultiplier != null)) + { + individualDropAmountMultiplier = normalMultiplier * premiumMultiplier; + } + else if (normalMultiplier != null) + { + individualDropAmountMultiplier = normalMultiplier; + } + else if (premiumMultiplier != null) + { + individualDropAmountMultiplier = premiumMultiplier; + } + } + else + { + individualDropAmountMultiplier = Config.RATE_DROP_AMOUNT_BY_ID.get(getItemId()); + } + + if (individualDropAmountMultiplier != null) + { + // individual amount list multiplier + multiplier *= individualDropAmountMultiplier; + } + else + { + final L2Item item = ItemTable.getInstance().getTemplate(getItemId()); + // global amount multiplier + if ((item != null) && item.hasExImmediateEffect()) + { + // global herb amount multiplier + multiplier *= Config.RATE_HERB_DROP_AMOUNT_MULTIPLIER; + } + else if (victim.isRaid()) + { + // global raid amount multiplier + multiplier *= Config.RATE_RAID_DROP_AMOUNT_MULTIPLIER; + } + else + { + // drop type specific amount multiplier + multiplier *= getGlobalAmountMultiplier(killer.getActingPlayer().hasPremiumStatus()); + } + } + + // global champions amount multiplier + if (victim.isChampion()) + { + multiplier *= getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS_AMOUNT : Config.L2JMOD_CHAMPION_ADENAS_REWARDS_AMOUNT; + } + + return (long) (val * multiplier); } /** * Gets the item id * @return the item id */ - public final int getItemId() + public int getItemId() { return _itemId; } /** - * Gets the base min drop count + * Gets the min drop count * @return the min */ - public final long getMin() + public long getMin() { return _min; } /** - * Gets the min drop count modified by server rates - * @param victim the victim who drops the item - * @param killer who kills the victim + * Gets the min drop count + * @param victim the victim + * @param killer the killer * @return the min modified by any rates. */ - public final long getMin(L2Character victim, L2Character killer) + public long getMin(L2Character victim, L2Character killer) { - if (Config.PREMIUM_SYSTEM_ENABLED && killer.isPlayer() && killer.getActingPlayer().hasPremiumStatus()) - { - if (Config.PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER.get(_itemId) != null) - { - return (long) (getMin() * getAmountMultiplier(victim) * Config.PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER.get(_itemId)); - } - return (long) (getMin() * getAmountMultiplier(victim) * Config.PREMIUM_RATE_DROP_AMOUNT); - } - return (long) (getMin() * getAmountMultiplier(victim)); + return getMinMax(victim, killer, getMin()); } /** - * Gets the base max drop count + * Gets the max drop count * @return the max */ - public final long getMax() + public long getMax() { return _max; } /** - * Gets the max drop count modified by server rates - * @param victim the victim who drops the item - * @param killer who kills the victim + * Gets the max drop count + * @param victim the victim + * @param killer the killer * @return the max modified by any rates. */ - public final long getMax(L2Character victim, L2Character killer) + public long getMax(L2Character victim, L2Character killer) { - if (Config.PREMIUM_SYSTEM_ENABLED && killer.isPlayer() && killer.getActingPlayer().hasPremiumStatus()) - { - if (Config.PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER.get(_itemId) != null) - { - return (long) (getMax() * getAmountMultiplier(victim) * Config.PREMIUM_RATE_DROP_AMOUNT_MULTIPLIER.get(_itemId)); - } - return (long) (getMax() * getAmountMultiplier(victim) * Config.PREMIUM_RATE_DROP_AMOUNT); - } - return (long) (getMax() * getAmountMultiplier(victim)); + return getMinMax(victim, killer, getMax()); } /** * Gets the chance of this drop item. * @return the chance */ - public final double getChance() + public double getChance() { return _chance; } /** - * Gets the general chance to drop this item modified by rates.
- * This shall be used in calculating chance within drop groups. - * @param victim the victim who drops the item + * Gets the chance of this drop item. + * @param victim the victim + * @param killer the killer * @return the chance modified by any rates. */ - public final double getChance(L2Character victim) + public double getChance(L2Character victim, L2Character killer) { - return getChance() * getChanceMultiplier(victim); - } - - /** - * Gets the chance of dropping this item for current killer and victim (modified by server rates and another rules based on killer)
- * This shall be used to calculate chance outside of drop groups. - * @param victim the victim who drops the item - * @param killer who kills the victim - * @return a chance to drop modified by deep blue drop rules - */ - public final double getChance(L2Character victim, L2Character killer) - { - if (Config.PREMIUM_SYSTEM_ENABLED && killer.isPlayer() && killer.getActingPlayer().hasPremiumStatus()) + double multiplier = 1; + + // individual drop chance + Float individualDropChanceMultiplier = null; + if (killer.getActingPlayer().hasPremiumStatus()) { - if (Config.PREMIUM_RATE_DROP_CHANCE_MULTIPLIER.get(_itemId) != null) + final Float normalMultiplier = Config.RATE_DROP_CHANCE_BY_ID.get(getItemId()); + final Float premiumMultiplier = Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(getItemId()); + if ((normalMultiplier != null) && (premiumMultiplier != null)) { - return getKillerChanceModifier(victim, killer) * getChance(victim) * Config.PREMIUM_RATE_DROP_CHANCE_MULTIPLIER.get(_itemId); + individualDropChanceMultiplier = normalMultiplier * premiumMultiplier; + } + else if (normalMultiplier != null) + { + individualDropChanceMultiplier = normalMultiplier; + } + else if (premiumMultiplier != null) + { + individualDropChanceMultiplier = premiumMultiplier; } - return getKillerChanceModifier(victim, killer) * getChance(victim) * Config.PREMIUM_RATE_DROP_CHANCE; } - return getKillerChanceModifier(victim, killer) * getChance(victim); + else + { + individualDropChanceMultiplier = Config.RATE_DROP_CHANCE_BY_ID.get(getItemId()); + } + + if (individualDropChanceMultiplier != null) + { + multiplier *= individualDropChanceMultiplier; + } + else + { + final L2Item item = ItemTable.getInstance().getTemplate(getItemId()); + if ((item != null) && item.hasExImmediateEffect()) + { + multiplier *= Config.RATE_HERB_DROP_CHANCE_MULTIPLIER; + } + else if (victim.isRaid()) + { + // global raid chance multiplier + multiplier *= Config.RATE_RAID_DROP_CHANCE_MULTIPLIER; + } + else + { + multiplier *= getGlobalChanceMultiplier(killer.getActingPlayer().hasPremiumStatus()); + } + } + + if (victim.isChampion()) + { + multiplier *= getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS_CHANCE : Config.L2JMOD_CHAMPION_ADENAS_REWARDS_CHANCE; + } + + return (getChance() * multiplier); } + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drop.IDropItem#calculateDrops(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) + */ @Override - public final List calculateDrops(L2Character victim, L2Character killer) + public Collection calculateDrops(L2Character victim, L2Character killer) { - return _dropCalculationStrategy.calculateDrops(this, victim, killer); - } - - /** - * @return true if chance over 100% should be handled - */ - public final boolean isPreciseCalculated() - { - return _preciseStrategy.isPreciseCalculated(this); - } - - /** - * This handles by default deep blue drop rules. It may also be used to handle another drop chance rules based on killer - * @param victim the victim who drops the item - * @param killer who kills the victim - * @return a number between 0 and 1 (usually) - */ - protected final double getKillerChanceModifier(L2Character victim, L2Character killer) - { - return _killerStrategy.getKillerChanceModifier(this, victim, killer); - } - - /** - * This gets standard server rates for this item - * @param victim who drops the item - * @return - */ - protected final double getAmountMultiplier(L2Character victim) - { - return _amountStrategy.getAmountMultiplier(this, victim); - } - - /** - * This gets standard server rates for this item - * @param victim who drops the item - * @return - */ - protected final double getChanceMultiplier(L2Character victim) - { - return _chanceStrategy.getChanceMultiplier(this, victim); + final int levelDifference = victim.getLevel() - killer.getLevel(); + final double levelGapChanceToDrop; + if (getItemId() == Inventory.ADENA_ID) + { + levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0); + } + else + { + levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0); + } + + // There is a chance of level gap that it wont drop this item + if (levelGapChanceToDrop < (Rnd.nextDouble() * 100)) + { + return null; + } + + final double chance = getChance(victim, killer); + final boolean successes = chance > (Rnd.nextDouble() * 100); + if (successes) + { + final Collection items = new ArrayList<>(1); + final long baseDropCount = Rnd.get(getMin(victim, killer), getMax(victim, killer)); + final long finaldropCount = (long) (Config.L2JMOD_OLD_DROP_BEHAVIOR ? (baseDropCount * Math.max(1, chance / 100)) + (chance > 100 ? (chance % 100) > (Rnd.nextDouble() * 100) ? baseDropCount : 0 : 0) : baseDropCount); + items.add(new ItemHolder(getItemId(), finaldropCount)); + return items; + } + + return null; } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/IGroupedDropItemFactory.java b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedCorpseDropItem.java similarity index 59% rename from trunk/java/com/l2jmobius/gameserver/model/drops/IGroupedDropItemFactory.java rename to trunk/java/com/l2jmobius/gameserver/model/drops/GroupedCorpseDropItem.java index 34e08542b6..2f737f84b8 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/IGroupedDropItemFactory.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedCorpseDropItem.java @@ -16,10 +16,28 @@ */ package com.l2jmobius.gameserver.model.drops; +import com.l2jmobius.Config; + /** - * @author Battlecruiser + * @author NosBit */ -public interface IGroupedDropItemFactory +public class GroupedCorpseDropItem extends GroupedGeneralDropItem { - GroupedGeneralDropItem newGroupedDropItem(double chance); + /** + * @param chance the chance of this drop item. + */ + public GroupedCorpseDropItem(double chance) + { + super(chance); + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem#getGlobalChanceMultiplier() + */ + @Override + protected double getGlobalChanceMultiplier() + { + return Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER; + } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItemFactory.java b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedDeathDropItem.java similarity index 60% rename from trunk/java/com/l2jmobius/gameserver/model/drops/IDropItemFactory.java rename to trunk/java/com/l2jmobius/gameserver/model/drops/GroupedDeathDropItem.java index 6c0f77962d..e1b861cec3 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItemFactory.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedDeathDropItem.java @@ -16,17 +16,28 @@ */ package com.l2jmobius.gameserver.model.drops; +import com.l2jmobius.Config; + /** - * @author Battlecruiser + * @author NosBit */ -public interface IDropItemFactory +public class GroupedDeathDropItem extends GroupedGeneralDropItem { /** - * @param itemId the item id - * @param min the min count - * @param max the max count - * @param chance the chance of this drop item - * @return the drop item created by this factory + * @param chance the chance of this drop item. */ - IDropItem newDropItem(int itemId, long min, long max, double chance); + public GroupedDeathDropItem(double chance) + { + super(chance); + } + + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem#getGlobalChanceMultiplier() + */ + @Override + protected double getGlobalChanceMultiplier() + { + return Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER; + } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedGeneralDropItem.java b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedGeneralDropItem.java index 35a515d1ce..b231a6d01d 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedGeneralDropItem.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/GroupedGeneralDropItem.java @@ -17,232 +17,131 @@ package com.l2jmobius.gameserver.model.drops; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.strategy.IAmountMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IChanceMultiplierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IGroupedItemDropCalculationStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; -import com.l2jmobius.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; +import com.l2jmobius.gameserver.model.actor.instance.L2RaidBossInstance; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.items.L2Item; +import com.l2jmobius.gameserver.util.Util; +import com.l2jmobius.util.Rnd; /** * @author NosBit */ -public final class GroupedGeneralDropItem implements IDropItem +public class GroupedGeneralDropItem implements IDropItem { private final double _chance; private List _items; - protected final IGroupedItemDropCalculationStrategy _dropCalculationStrategy; - protected final IKillerChanceModifierStrategy _killerChanceModifierStrategy; - protected final IPreciseDeterminationStrategy _preciseStrategy; /** * @param chance the chance of this drop item. */ public GroupedGeneralDropItem(double chance) { - this(chance, IGroupedItemDropCalculationStrategy.DEFAULT_STRATEGY, IKillerChanceModifierStrategy.DEFAULT_STRATEGY, IPreciseDeterminationStrategy.DEFAULT); + _chance = chance; } - /** - * @param chance the chance of this drop item. - * @param dropStrategy to calculate drops. - * @param killerStrategy - * @param preciseStrategy - */ - public GroupedGeneralDropItem(double chance, IGroupedItemDropCalculationStrategy dropStrategy, IKillerChanceModifierStrategy killerStrategy, IPreciseDeterminationStrategy preciseStrategy) + protected double getGlobalChanceMultiplier() { - _chance = chance; - _dropCalculationStrategy = dropStrategy; - _killerChanceModifierStrategy = killerStrategy; - _preciseStrategy = preciseStrategy; + return 1.; } /** * Gets the chance of this drop item. * @return the chance */ - public final double getChance() + public double getChance() { return _chance; } + /** + * Gets the chance of this drop item. + * @param victim the victim + * @param killer the killer + * @return the chance modified by any rates. + */ + public double getChance(L2Character victim, L2Character killer) + { + for (final GeneralDropItem gdi : getItems()) + { + final L2Item item = ItemTable.getInstance().getTemplate(gdi.getItemId()); + if ((item == null) || !item.hasExImmediateEffect()) + { + return getChance() * getGlobalChanceMultiplier(); + } + } + + return getChance() * Config.RATE_HERB_DROP_CHANCE_MULTIPLIER; + } + /** * Gets the items. * @return the items */ - public final List getItems() + public List getItems() { return _items; } - /** - * @return the strategy - */ - public final IGroupedItemDropCalculationStrategy getDropCalculationStrategy() - { - return _dropCalculationStrategy; - } - - /** - * @return the _killerChanceModifierStrategy - */ - public IKillerChanceModifierStrategy getKillerChanceModifierStrategy() - { - return _killerChanceModifierStrategy; - } - - /** - * @return the _preciseStrategy - */ - public final IPreciseDeterminationStrategy getPreciseStrategy() - { - return _preciseStrategy; - } - /** * Sets an item list to this drop item. * @param items the item list */ - public final void setItems(List items) + public void setItems(List items) { _items = Collections.unmodifiableList(items); } - /** - * Returns a list of items in the group with chance multiplied by chance of the group - * @return the list of items with modified chances + /* + * (non-Javadoc) + * @see com.l2jserver.gameserver.model.drop.IDropItem#calculateDrops(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) */ - public final List extractMe() - { - final List items = new ArrayList<>(); - for (GeneralDropItem item : getItems()) - { - // precise and killer strategies of the group - items.add(new GeneralDropItem(item.getItemId(), item.getMin(), item.getMax(), (item.getChance() * getChance()) / 100, item.getAmountStrategy(), item.getChanceStrategy(), getPreciseStrategy(), getKillerChanceModifierStrategy(), item.getDropCalculationStrategy())); - } - return items; - } - - /** - * statically normalizes a group, useful when need to convert legacy SQL data - * @return a new group with items, which have a sum of getChance() of 100% - */ - public final GroupedGeneralDropItem normalizeMe() - { - double sumchance = 0; - for (GeneralDropItem item : getItems()) - { - sumchance += (item.getChance() * getChance()) / 100; - } - final double sumchance1 = sumchance; - final GroupedGeneralDropItem group = new GroupedGeneralDropItem(sumchance1, getDropCalculationStrategy(), IKillerChanceModifierStrategy.NO_RULES, getPreciseStrategy()); - final List items = new ArrayList<>(); - for (GeneralDropItem item : getItems()) - { - // modify only the chance, leave all other rules intact - items.add(new GeneralDropItem(item.getItemId(), item.getMin(), item.getMax(), (item.getChance() * getChance()) / sumchance1, item.getAmountStrategy(), item.getChanceStrategy(), item.getPreciseStrategy(), item.getKillerChanceModifierStrategy(), item.getDropCalculationStrategy())); - } - group.setItems(items); - return group; - } - - /** - * Creates a normalized group taking into account all drop modifiers, needed when handling a group which has items with different chance rates - * @param victim - * @param killer - * @return a new normalized group with all drop modifiers applied - */ - public final GroupedGeneralDropItem normalizeMe(L2Character victim, L2Character killer) - { - return normalizeMe(victim, killer, true, 1); - } - - /** - * Creates a normalized group taking into account all drop modifiers, needed when handling a group which has items with different chance rates - * @param victim - * @param killer - * @param chanceModifier an additional chance modifier - * @return a new normalized group with all drop modifiers applied - */ - public final GroupedGeneralDropItem normalizeMe(L2Character victim, L2Character killer, double chanceModifier) - { - return normalizeMe(victim, killer, true, chanceModifier); - } - - /** - * Creates a normalized group taking into account all drop modifiers, needed when handling a group which has items with different chance rates - * @param victim - * @return a new normalized group with all victim modifiers applied - */ - public final GroupedGeneralDropItem normalizeMe(L2Character victim) - { - return normalizeMe(victim, null, false, 1); - } - - /** - * Creates a normalized group taking into account all drop modifiers, needed when handling a group which has items with different chance rates - * @param victim - * @param chanceModifier an additional chance modifier - * @return a new normalized group with all victim modifiers applied - */ - public final GroupedGeneralDropItem normalizeMe(L2Character victim, double chanceModifier) - { - return normalizeMe(victim, null, false, chanceModifier); - } - - /** - * Creates a normalized group taking into account all drop modifiers, needed when handling a group which has items with different chance rates - * @param victim - * @param killer - * @param applyKillerModifier if to modify chance by {@link GroupedGeneralDropItem#getKillerChanceModifier(L2Character, L2Character)} - * @param chanceModifier an additional chance modifier - * @return a new normalized group with all drop modifiers applied - */ - private final GroupedGeneralDropItem normalizeMe(L2Character victim, L2Character killer, boolean applyKillerModifier, double chanceModifier) - { - if (applyKillerModifier) - { - chanceModifier *= getKillerChanceModifier(victim, killer); - } - double sumchance = 0; - for (GeneralDropItem item : getItems()) - { - sumchance += (item.getChance(victim, killer) * getChance() * chanceModifier) / 100; - } - final GroupedGeneralDropItem group = new GroupedGeneralDropItem(sumchance, getDropCalculationStrategy(), IKillerChanceModifierStrategy.NO_RULES, getPreciseStrategy()); // to discard further deep blue calculations - final List items = new ArrayList<>(); - for (GeneralDropItem item : getItems()) - { - // the item is made almost "static" - items.add(new GeneralDropItem(item.getItemId(), item.getMin(victim, killer), item.getMax(victim, killer), (item.getChance(victim, killer) * getChance() * chanceModifier) / sumchance, IAmountMultiplierStrategy.STATIC, IChanceMultiplierStrategy.STATIC, getPreciseStrategy(), IKillerChanceModifierStrategy.NO_RULES, item.getDropCalculationStrategy())); - } - group.setItems(items); - return group; - } - @Override - public final List calculateDrops(L2Character victim, L2Character killer) + public Collection calculateDrops(L2Character victim, L2Character killer) { - return _dropCalculationStrategy.calculateDrops(this, victim, killer); - } - - /** - * This handles by default deep blue drop rules. It may also be used to handle another drop chance rules based on killer - * @param victim the victim who drops the item - * @param killer who kills the victim - * @return a number between 0 and 1 (usually) - */ - public final double getKillerChanceModifier(L2Character victim, L2Character killer) - { - return _killerChanceModifierStrategy.getKillerChanceModifier(this, victim, killer); - } - - public boolean isPreciseCalculated() - { - return _preciseStrategy.isPreciseCalculated(this); + final int levelDifference = victim.getLevel() - killer.getLevel(); + double chanceModifier; + if (victim instanceof L2RaidBossInstance) + { + chanceModifier = Math.max(0, Math.min(1, (levelDifference * 0.15) + 1)); + } + else + { + chanceModifier = 1; + if (Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0) < (Rnd.nextDouble() * 100)) + { + return null; + } + } + + final double chance = getChance(victim, killer) * chanceModifier; + final boolean successes = chance > (Rnd.nextDouble() * 100); + + if (successes) + { + double totalChance = 0; + final double random = (Rnd.nextDouble() * 100); + for (GeneralDropItem item : getItems()) + { + // Grouped item chance rates should not be modified. + totalChance += item.getChance(); + if (totalChance > random) + { + final Collection items = new ArrayList<>(1); + final long baseDropCount = Rnd.get(item.getMin(victim, killer), item.getMax(victim, killer)); + final long finaldropCount = (long) (Config.L2JMOD_OLD_DROP_BEHAVIOR ? (baseDropCount * Math.max(1, chance / 100)) + (chance > 100 && (chance % 100) > (Rnd.nextDouble() * 100) ? baseDropCount : 0) : baseDropCount); + items.add(new ItemHolder(item.getItemId(), finaldropCount)); + return items; + } + } + } + + return null; } } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItem.java b/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItem.java index c110afb8de..a740085bf4 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItem.java +++ b/trunk/java/com/l2jmobius/gameserver/model/drops/IDropItem.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.drops; -import java.util.List; +import java.util.Collection; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.holders.ItemHolder; @@ -32,5 +32,5 @@ public interface IDropItem * @param killer the killer * @return {@code null} or empty collection if there are no drops, a collection containing all items to drop otherwise */ - List calculateDrops(L2Character victim, L2Character killer); + public Collection calculateDrops(L2Character victim, L2Character killer); } diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java deleted file mode 100644 index acdfa573e0..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import com.l2jmobius.Config; -import com.l2jmobius.gameserver.datatables.ItemTable; -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.itemcontainer.Inventory; - -/** - * @author Battlecruiser - */ -public interface IAmountMultiplierStrategy -{ - IAmountMultiplierStrategy DROP = DEFAULT_STRATEGY(Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER); - IAmountMultiplierStrategy SPOIL = DEFAULT_STRATEGY(Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER); - IAmountMultiplierStrategy STATIC = (item, victim) -> 1; - - static IAmountMultiplierStrategy DEFAULT_STRATEGY(double defaultMultiplier) - { - return (item, victim) -> - { - double multiplier = 1; - if (victim.isChampion()) - { - multiplier *= item.getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS_AMOUNT : Config.L2JMOD_CHAMPION_ADENAS_REWARDS_AMOUNT; - } - final Float dropAmountMultiplier = Config.RATE_DROP_AMOUNT_MULTIPLIER.get(item.getItemId()); - if (dropAmountMultiplier != null) - { - multiplier *= dropAmountMultiplier; - } - else if (ItemTable.getInstance().getTemplate(item.getItemId()).hasExImmediateEffect()) - { - multiplier *= Config.RATE_HERB_DROP_AMOUNT_MULTIPLIER; - } - else if (victim.isRaid()) - { - multiplier *= Config.RATE_RAID_DROP_AMOUNT_MULTIPLIER; - } - else - { - multiplier *= defaultMultiplier; - } - return multiplier; - }; - } - - double getAmountMultiplier(GeneralDropItem item, L2Character victim); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java deleted file mode 100644 index 04c1f6b269..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import com.l2jmobius.Config; -import com.l2jmobius.gameserver.datatables.ItemTable; -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.itemcontainer.Inventory; - -/** - * @author Battlecruiser - */ -public interface IChanceMultiplierStrategy -{ - IChanceMultiplierStrategy DROP = DEFAULT_STRATEGY(Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER); - IChanceMultiplierStrategy SPOIL = DEFAULT_STRATEGY(Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER); - IChanceMultiplierStrategy STATIC = (item, victim) -> 1; - - IChanceMultiplierStrategy QUEST = (item, victim) -> - { - double championmult; - if ((item.getItemId() == Inventory.ADENA_ID) || (item.getItemId() == Inventory.ANCIENT_ADENA_ID)) - { - championmult = Config.L2JMOD_CHAMPION_ADENAS_REWARDS_CHANCE; - } - else - { - championmult = Config.L2JMOD_CHAMPION_REWARDS_CHANCE; - } - - return (Config.L2JMOD_CHAMPION_ENABLE && (victim != null) && victim.isChampion()) ? (Config.RATE_QUEST_DROP * championmult) : Config.RATE_QUEST_DROP; - }; - - static IChanceMultiplierStrategy DEFAULT_STRATEGY(double defaultMultiplier) - { - return (item, victim) -> - { - float multiplier = 1; - if (victim.isChampion()) - { - multiplier *= item.getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS_CHANCE : Config.L2JMOD_CHAMPION_ADENAS_REWARDS_CHANCE; - } - final Float dropChanceMultiplier = Config.RATE_DROP_CHANCE_MULTIPLIER.get(item.getItemId()); - if (dropChanceMultiplier != null) - { - multiplier *= dropChanceMultiplier; - } - else if (ItemTable.getInstance().getTemplate(item.getItemId()).hasExImmediateEffect()) - { - multiplier *= Config.RATE_HERB_DROP_CHANCE_MULTIPLIER; - } - else if (victim.isRaid()) - { - multiplier *= Config.RATE_RAID_DROP_CHANCE_MULTIPLIER; - } - else - { - multiplier *= defaultMultiplier; - } - return multiplier; - }; - } - - double getChanceMultiplier(GeneralDropItem item, L2Character victim); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IDropCalculationStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IDropCalculationStrategy.java deleted file mode 100644 index c516a86422..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IDropCalculationStrategy.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import java.util.Collections; -import java.util.List; - -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.holders.ItemHolder; -import com.l2jmobius.util.Rnd; - -/** - * @author Battlecruiser - */ -public interface IDropCalculationStrategy -{ - IDropCalculationStrategy DEFAULT_STRATEGY = (item, victim, killer) -> - { - final double chance = item.getChance(victim, killer); - if (chance > (Rnd.nextDouble() * 100)) - { - int amountMultiply = 1; - if (item.isPreciseCalculated() && (chance > 100)) - { - amountMultiply = (int) chance / 100; - if ((chance % 100) > (Rnd.nextDouble() * 100)) - { - amountMultiply++; - } - } - - return Collections.singletonList(new ItemHolder(item.getItemId(), Rnd.get(item.getMin(victim, killer), item.getMax(victim, killer)) * amountMultiply)); - } - - return null; - }; - - List calculateDrops(GeneralDropItem item, L2Character victim, L2Character killer); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java deleted file mode 100644 index 8d6648902a..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.drops.GroupedGeneralDropItem; -import com.l2jmobius.gameserver.model.drops.IDropItem; -import com.l2jmobius.gameserver.model.holders.ItemHolder; -import com.l2jmobius.util.Rnd; - -/** - * @author Battlecruiser - */ -public interface IGroupedItemDropCalculationStrategy -{ - /** - * The default strategy used in L2J to calculate drops. When the group's chance raises over 100% and group has precise calculation, the dropped item's amount increases. - */ - IGroupedItemDropCalculationStrategy DEFAULT_STRATEGY = new IGroupedItemDropCalculationStrategy() - { - private final Map singleItemCache = new ConcurrentHashMap<>(); - - private GeneralDropItem getSingleItem(GroupedGeneralDropItem dropItem) - { - final GeneralDropItem item1 = dropItem.getItems().iterator().next(); - singleItemCache.putIfAbsent(dropItem, new GeneralDropItem(item1.getItemId(), item1.getMin(), item1.getMax(), (item1.getChance() * dropItem.getChance()) / 100, item1.getAmountStrategy(), item1.getChanceStrategy(), dropItem.getPreciseStrategy(), dropItem.getKillerChanceModifierStrategy(), item1.getDropCalculationStrategy())); - return singleItemCache.get(dropItem); - } - - @Override - public List calculateDrops(GroupedGeneralDropItem dropItem, L2Character victim, L2Character killer) - { - if (dropItem.getItems().size() == 1) - { - return getSingleItem(dropItem).calculateDrops(victim, killer); - } - - final GroupedGeneralDropItem normalized = dropItem.normalizeMe(victim, killer); - if (normalized.getChance() > (Rnd.nextDouble() * 100)) - { - final double random = Rnd.nextDouble() * 100; - double totalChance = 0; - for (GeneralDropItem item2 : normalized.getItems()) - { - // Grouped item chance rates should not be modified (the whole magic was already done by normalizing thus the items' chance sum is always 100%). - totalChance += Math.sqrt(item2.getChance()); - if (totalChance > random) - { - int amountMultiply = 1; - if (dropItem.isPreciseCalculated() && (normalized.getChance() >= 100)) - { - amountMultiply = (int) normalized.getChance() / 100; - if ((normalized.getChance() % 100) > (Rnd.nextDouble() * 100)) - { - amountMultiply++; - } - } - - return Collections.singletonList(new ItemHolder(item2.getItemId(), Rnd.get(item2.getMin(victim, killer), item2.getMax(victim, killer)) * amountMultiply)); - } - } - } - return null; - } - }; - - /** - * This strategy calculates a group's drop by calculating drops of its individual items and merging its results. - */ - IGroupedItemDropCalculationStrategy DISBAND_GROUP = (item, victim, killer) -> - { - final List dropped = new ArrayList<>(); - for (IDropItem dropItem : item.extractMe()) - { - dropped.addAll(dropItem.calculateDrops(victim, killer)); - } - return dropped.isEmpty() ? null : dropped; - }; - - /** - * This strategy when group has precise calculation rolls multiple times over group to determine drops when group's chance raises over 100% instead of just multiplying the dropped item's amount. Thus it can produce different items from group at once. - */ - IGroupedItemDropCalculationStrategy PRECISE_MULTIPLE_GROUP_ROLLS = (item, victim, killer) -> - { - if (!item.isPreciseCalculated()) - { - // if item hasn't precise calculation there's no change from DEFAULT_STRATEGY - return DEFAULT_STRATEGY.calculateDrops(item, victim, victim); - } - final GroupedGeneralDropItem newItem = new GroupedGeneralDropItem(item.getChance(), DEFAULT_STRATEGY, item.getKillerChanceModifierStrategy(), IPreciseDeterminationStrategy.NEVER); - newItem.setItems(item.getItems()); - final GroupedGeneralDropItem normalized = newItem.normalizeMe(victim, killer); - // Let's determine the number of rolls. - int rolls = (int) (normalized.getChance() / 100); - if ((Rnd.nextDouble() * 100) < (normalized.getChance() % 100)) - { - rolls++; - } - final List dropped = new ArrayList<>(rolls); - for (int i = 0; i < rolls; i++) - { - // As further normalizing on already normalized drop group does nothing, we can just pass the calculation to DEFAULT_STRATEGY with precise calculation disabled as we handle it. - dropped.addAll(normalized.calculateDrops(victim, killer)); - } - return dropped.isEmpty() ? null : dropped; - }; - - List calculateDrops(GroupedGeneralDropItem item, L2Character victim, L2Character killer); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java deleted file mode 100644 index 57a4b583c9..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import com.l2jmobius.Config; -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.drops.IDropItem; -import com.l2jmobius.gameserver.model.itemcontainer.Inventory; -import com.l2jmobius.gameserver.util.Util; - -/** - * @author Battlecruiser - */ -public interface IKillerChanceModifierStrategy extends INonGroupedKillerChanceModifierStrategy -{ - IKillerChanceModifierStrategy DEFAULT_STRATEGY = (item, victim, killer) -> - { - final int levelDifference = victim.getLevel() - killer.getLevel(); - if ((victim.isRaid()) && Config.DEEPBLUE_DROP_RULES_RAID) - { - // FIXME: Config? - return Math.max(0, Math.min(1, (levelDifference * 0.15) + 1)); - } - else if (Config.DEEPBLUE_DROP_RULES) - { - return Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0) / 100; - } - return 1; - }; - INonGroupedKillerChanceModifierStrategy DEFAULT_NONGROUP_STRATEGY = (item, victim, killer) -> - { - if (((!(victim.isRaid())) && Config.DEEPBLUE_DROP_RULES) || ((victim.isRaid()) && Config.DEEPBLUE_DROP_RULES_RAID)) - { - final int levelDifference = victim.getLevel() - killer.getLevel(); - if (item.getItemId() == Inventory.ADENA_ID) - { - return Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0) / 100; - } - return Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0) / 100; - } - return 1; - }; - - IKillerChanceModifierStrategy NO_RULES = (item, victim, killer) -> 1; - - double getKillerChanceModifier(IDropItem item, L2Character victim, L2Character killer); - - @Override - default double getKillerChanceModifier(GeneralDropItem item, L2Character victim, L2Character killer) - { - return getKillerChanceModifier((IDropItem) item, victim, killer); - } -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java deleted file mode 100644 index be809ae392..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; - -/** - * @author Battlecruiser - */ -public interface INonGroupedKillerChanceModifierStrategy -{ - double getKillerChanceModifier(GeneralDropItem item, L2Character victim, L2Character killer); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java b/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java deleted file mode 100644 index 76815ff3c5..0000000000 --- a/trunk/java/com/l2jmobius/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the L2J Mobius project. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.l2jmobius.gameserver.model.drops.strategy; - -import com.l2jmobius.Config; -import com.l2jmobius.gameserver.model.drops.IDropItem; - -/** - * @author Battlecruiser - */ -public interface IPreciseDeterminationStrategy -{ - IPreciseDeterminationStrategy ALWAYS = dropItem -> true; - - IPreciseDeterminationStrategy DEFAULT = dropItem -> Config.PRECISE_DROP_CALCULATION; - - IPreciseDeterminationStrategy NEVER = dropItem -> false; - - /** - * @param dropItem - * @return true if drop calculation strategy should use precise rules - */ - boolean isPreciseCalculated(IDropItem dropItem); -} diff --git a/trunk/java/com/l2jmobius/gameserver/model/event/LongTimeEvent.java b/trunk/java/com/l2jmobius/gameserver/model/event/LongTimeEvent.java index 6d301ddfb0..d71604337d 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/event/LongTimeEvent.java +++ b/trunk/java/com/l2jmobius/gameserver/model/event/LongTimeEvent.java @@ -39,7 +39,6 @@ import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.instancemanager.EventShrineManager; import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.announce.EventAnnouncement; -import com.l2jmobius.gameserver.model.drops.DropListScope; import com.l2jmobius.gameserver.model.drops.GeneralDropItem; import com.l2jmobius.gameserver.model.quest.Quest; import com.l2jmobius.gameserver.script.DateRange; @@ -189,7 +188,7 @@ public class LongTimeEvent extends Quest continue; } - _dropList.add((GeneralDropItem) DropListScope.STATIC.newDropItem(itemId, minCount, maxCount, finalChance)); + _dropList.add(new GeneralDropItem(itemId, minCount, maxCount, finalChance)); } catch (NumberFormatException nfe) { diff --git a/trunk/java/com/l2jmobius/gameserver/model/events/AbstractScript.java b/trunk/java/com/l2jmobius/gameserver/model/events/AbstractScript.java index 7ee019a566..4e9bbfe022 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/events/AbstractScript.java +++ b/trunk/java/com/l2jmobius/gameserver/model/events/AbstractScript.java @@ -23,12 +23,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -62,9 +58,6 @@ import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2TrapInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; -import com.l2jmobius.gameserver.model.drops.GeneralDropItem; -import com.l2jmobius.gameserver.model.drops.GroupedGeneralDropItem; -import com.l2jmobius.gameserver.model.drops.IDropItem; import com.l2jmobius.gameserver.model.entity.Castle; import com.l2jmobius.gameserver.model.entity.Fort; import com.l2jmobius.gameserver.model.entity.Instance; @@ -144,7 +137,6 @@ import com.l2jmobius.gameserver.scripting.L2ScriptEngineManager; import com.l2jmobius.gameserver.scripting.ScriptManager; import com.l2jmobius.gameserver.util.MinionList; import com.l2jmobius.util.Rnd; -import com.l2jmobius.util.Util; /** * Abstract script. @@ -2349,499 +2341,6 @@ public abstract class AbstractScript implements INamable return false; } - /** - * Gives an item to the player - * @param player - * @param item - * @param victim the character that "dropped" the item - * @return true if at least one item was given, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim) - { - final List items = item.calculateDrops(victim, player); - if ((items == null) || items.isEmpty()) - { - return false; - } - giveItems(player, items); - return true; - } - - /** - * Gives an item to the player - * @param player - * @param items - */ - protected static void giveItems(L2PcInstance player, List items) - { - for (ItemHolder item : items) - { - giveItems(player, item); - } - } - - /** - * Gives an item to the player - * @param player - * @param item - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, ItemHolder item, long limit) - { - final long maxToGive = limit - player.getInventory().getInventoryItemCount(item.getId(), -1); - if (maxToGive <= 0) - { - return false; - } - giveItems(player, item.getId(), Math.min(maxToGive, item.getCount())); - return true; - } - - protected static boolean giveItems(L2PcInstance player, ItemHolder item, long limit, boolean playSound) - { - final boolean drop = giveItems(player, item, limit); - if (drop && playSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - return drop; - } - - /** - * @param player - * @param items - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, List items, long limit) - { - boolean b = false; - for (ItemHolder item : items) - { - b |= giveItems(player, item, limit); - } - return b; - } - - protected static boolean giveItems(L2PcInstance player, List items, long limit, boolean playSound) - { - final boolean drop = giveItems(player, items, limit); - if (drop && playSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - return drop; - } - - /** - * @param player - * @param items - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. If a no limit for an itemId is specified, item will always be given - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, List items, Map limit) - { - return giveItems(player, items, Util.mapToFunction(limit)); - } - - /** - * @param player - * @param items - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. If a no limit for an itemId is specified, item will always be given - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, List items, Function limit) - { - boolean b = false; - for (ItemHolder item : items) - { - if (limit != null) - { - final Long longLimit = limit.apply(item.getId()); - // null -> no limit specified for that item id. This trick is to avoid limit.apply() be called twice (once for the null check) - if (longLimit != null) - { - b |= giveItems(player, item, longLimit); - continue; // the item is given, continue with next - } - } - // da BIG else - // no limit specified here (either limit or limit.apply(item.getId()) is null) - b = true; - giveItems(player, item); - } - return b; - } - - protected static boolean giveItems(L2PcInstance player, List items, Function limit, boolean playSound) - { - final boolean drop = giveItems(player, items, limit); - if (drop && playSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - return drop; - } - - protected static boolean giveItems(L2PcInstance player, List items, Map limit, boolean playSound) - { - return giveItems(player, items, Util.mapToFunction(limit), playSound); - } - - /** - * @param player - * @param item - * @param victim the character that "dropped" the item - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, int limit) - { - return giveItems(player, item.calculateDrops(victim, player), limit); - } - - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, int limit, boolean playSound) - { - final boolean drop = giveItems(player, item, victim, limit); - if (drop && playSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - return drop; - } - - /** - * @param player - * @param item - * @param victim the character that "dropped" the item - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. If a no limit for an itemId is specified, item will always be given - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Map limit) - { - return giveItems(player, item.calculateDrops(victim, player), limit); - } - - /** - * @param player - * @param item - * @param victim the character that "dropped" the item - * @param limit the maximum amount of items the player can have. Won't give more if this limit is reached. If a no limit for an itemId is specified, item will always be given - * @return true if at least one item was given to the player, false otherwise - */ - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Function limit) - { - return giveItems(player, item.calculateDrops(victim, player), limit); - } - - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Map limit, boolean playSound) - { - return giveItems(player, item, victim, Util.mapToFunction(limit), playSound); - } - - protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Function limit, boolean playSound) - { - final boolean drop = giveItems(player, item, victim, limit); - if (drop && playSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - return drop; - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, Collection items, Function limit, boolean playSound) - { - final Map> rewardedCounts = calculateDistribution(players, items, limit); - // now give the calculated items to the players - giveItems(rewardedCounts, playSound); - return rewardedCounts; - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, Collection items, Map limit, boolean playSound) - { - return distributeItems(players, items, Util.mapToFunction(limit), playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, Collection items, long limit, boolean playSound) - { - return distributeItems(players, items, t -> limit, playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param item the items to distribute - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map distributeItems(Collection players, ItemHolder item, long limit, boolean playSound) - { - final Map> distribution = distributeItems(players, Collections.singletonList(item), limit, playSound); - final Map returnMap = new HashMap<>(); - for (Entry> entry : distribution.entrySet()) - { - for (Entry entry2 : entry.getValue().entrySet()) - { - returnMap.put(entry.getKey(), entry2.getValue()); - } - } - return returnMap; - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, IDropItem items, L2Character killer, L2Character victim, Function limit, boolean playSound) - { - return distributeItems(players, items.calculateDrops(victim, killer), limit, playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, IDropItem items, L2Character killer, L2Character victim, Map limit, boolean playSound) - { - return distributeItems(players, items.calculateDrops(victim, killer), limit, playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, IDropItem items, L2Character killer, L2Character victim, long limit, boolean playSound) - { - return distributeItems(players, items.calculateDrops(victim, killer), limit, playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @param smartDrop true if to not calculate a drop, which can't be given to any player 'cause of limits - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, GroupedGeneralDropItem items, L2Character killer, L2Character victim, Function limit, boolean playSound, boolean smartDrop) - { - GroupedGeneralDropItem toDrop; - if (smartDrop) - { - toDrop = new GroupedGeneralDropItem(items.getChance(), items.getDropCalculationStrategy(), items.getKillerChanceModifierStrategy(), items.getPreciseStrategy()); - final List dropItems = new LinkedList<>(items.getItems()); - ITEM_LOOP: for (Iterator it = dropItems.iterator(); it.hasNext();) - { - final GeneralDropItem item = it.next(); - for (L2PcInstance player : players) - { - final int itemId = item.getItemId(); - if (player.getInventory().getInventoryItemCount(itemId, -1, true) < avoidNull(limit, itemId)) - { - // we can give this item to this player - continue ITEM_LOOP; - } - } - // there's nobody to give this item to - it.remove(); - } - toDrop.setItems(dropItems); - toDrop = toDrop.normalizeMe(victim, killer); - } - else - { - toDrop = items; - } - return distributeItems(players, toDrop, killer, victim, limit, playSound); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @param smartDrop true if to not calculate a drop, which can't be given to any player - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, GroupedGeneralDropItem items, L2Character killer, L2Character victim, Map limit, boolean playSound, boolean smartDrop) - { - return distributeItems(players, items, killer, victim, Util.mapToFunction(limit), playSound, smartDrop); - } - - /** - * Distributes items to players equally - * @param players the players to whom the items will be distributed - * @param items the items to distribute - * @param killer the one who "kills" the victim - * @param victim the character that "dropped" the item - * @param limit the limit what single player can have of each item - * @param playSound if to play sound if a player gets at least one item - * @param smartDrop true if to not calculate a drop, which can't be given to any player - * @return the counts of each items given to each player - */ - protected static Map> distributeItems(Collection players, GroupedGeneralDropItem items, L2Character killer, L2Character victim, long limit, boolean playSound, boolean smartDrop) - { - return distributeItems(players, items, killer, victim, t -> limit, playSound, smartDrop); - } - - /** - * @param players - * @param items - * @param limit - * @return - */ - private static Map> calculateDistribution(Collection players, Collection items, Function limit) - { - final Map> rewardedCounts = new HashMap<>(); - for (L2PcInstance player : players) - { - rewardedCounts.put(player, new HashMap()); - } - NEXT_ITEM: for (ItemHolder item : items) - { - long equaldist = item.getCount() / players.size(); - long randomdist = item.getCount() % players.size(); - final List toDist = new ArrayList<>(players); - do // this must happen at least once in order to get away already full players (and then equaldist can become nonzero) - { - for (Iterator it = toDist.iterator(); it.hasNext();) - { - final L2PcInstance player = it.next(); - if (!rewardedCounts.get(player).containsKey(item.getId())) - { - rewardedCounts.get(player).put(item.getId(), 0L); - } - final long maxGive = avoidNull(limit, item.getId()) - player.getInventory().getInventoryItemCount(item.getId(), -1, true) - rewardedCounts.get(player).get(item.getId()); - long toGive = equaldist; - if (equaldist >= maxGive) - { - toGive = maxGive; - randomdist += equaldist - maxGive; // overflown items are available to next players - it.remove(); // this player is already full - } - rewardedCounts.get(player).put(item.getId(), rewardedCounts.get(player).get(item.getId()) + toGive); - } - if (toDist.isEmpty()) - { - // there's no one to give items anymore, all players will be full when we give the items - continue NEXT_ITEM; - } - equaldist = randomdist / toDist.size(); // the rest of items may be allowed to be equally distributed between remaining players - randomdist %= toDist.size(); - } - while (equaldist > 0); - while (randomdist > 0) - { - if (toDist.isEmpty()) - { - // we don't have any player left - continue NEXT_ITEM; - } - final L2PcInstance player = toDist.get(getRandom(toDist.size())); - // avoid null return - final long maxGive = avoidNull(limit, item.getId()) - limit.apply(item.getId()) - player.getInventory().getInventoryItemCount(item.getId(), -1, true) - rewardedCounts.get(player).get(item.getId()); - if (maxGive > 0) - { - // we can add an item to player - // so we add one item to player - rewardedCounts.get(player).put(item.getId(), rewardedCounts.get(player).get(item.getId()) + 1); - randomdist--; - } - toDist.remove(player); // Either way this player isn't allowable for next random award - } - } - return rewardedCounts; - } - - /** - * This function is for avoidance null returns in function limits - * @param the type of function arg - * @param function the function - * @param arg the argument - * @return {@link Long#MAX_VALUE} if function.apply(arg) is null, function.apply(arg) otherwise - */ - private static long avoidNull(Function function, T arg) - { - final Long longLimit = function.apply(arg); - return longLimit == null ? Long.MAX_VALUE : longLimit; - } - - /** - * Distributes items to players - * @param rewardedCounts A scheme of distribution items (the structure is: Map>) - * @param playSound if to play sound if a player gets at least one item - */ - private static void giveItems(Map> rewardedCounts, boolean playSound) - { - for (Entry> entry : rewardedCounts.entrySet()) - { - final L2PcInstance player = entry.getKey(); - boolean playPlayerSound = false; - for (Entry item : entry.getValue().entrySet()) - { - if (item.getValue() >= 0) - { - playPlayerSound = true; - giveItems(player, item.getKey(), item.getValue()); - } - } - if (playSound && playPlayerSound) - { - playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); - } - } - } - /** * Take an amount of a specified item from player's inventory. * @param player the player whose item to take diff --git a/trunk/java/com/l2jmobius/gameserver/model/itemcontainer/ItemContainer.java b/trunk/java/com/l2jmobius/gameserver/model/itemcontainer/ItemContainer.java index ad1611d36c..384c40b277 100644 --- a/trunk/java/com/l2jmobius/gameserver/model/itemcontainer/ItemContainer.java +++ b/trunk/java/com/l2jmobius/gameserver/model/itemcontainer/ItemContainer.java @@ -236,7 +236,7 @@ public abstract class ItemContainer item = olditem; // Updates database - if ((item.getId() == Inventory.ADENA_ID) && (count < (10000 * Config.RATE_DROP_AMOUNT_MULTIPLIER.getOrDefault(Inventory.ADENA_ID, 1f)))) + if ((item.getId() == Inventory.ADENA_ID) && (count < (10000 * Config.RATE_DROP_AMOUNT_BY_ID.getOrDefault(Inventory.ADENA_ID, 1f)))) { // Small adena changes won't be saved to database all the time if ((GameTimeController.getInstance().getGameTicks() % 5) == 0) @@ -287,7 +287,7 @@ public abstract class ItemContainer item.setLastChange(L2ItemInstance.MODIFIED); // Updates database // If Adena drop rate is not present it will be x1. - if ((itemId == Inventory.ADENA_ID) && (count < (10000 * Config.RATE_DROP_AMOUNT_MULTIPLIER.getOrDefault(Inventory.ADENA_ID, 1f)))) + if ((itemId == Inventory.ADENA_ID) && (count < (10000 * Config.RATE_DROP_AMOUNT_BY_ID.getOrDefault(Inventory.ADENA_ID, 1f)))) { // Small adena changes won't be saved to database all the time if ((GameTimeController.getInstance().getGameTicks() % 5) == 0) diff --git a/trunk/java/com/l2jmobius/util/Util.java b/trunk/java/com/l2jmobius/util/Util.java index c04d6a60f6..8d59ac58ca 100644 --- a/trunk/java/com/l2jmobius/util/Util.java +++ b/trunk/java/com/l2jmobius/util/Util.java @@ -29,8 +29,6 @@ import java.time.temporal.TemporalAdjusters; import java.util.Arrays; import java.util.Comparator; import java.util.List; -import java.util.Map; -import java.util.function.Function; import java.util.logging.Logger; /** @@ -223,16 +221,4 @@ public final class Util .orElse(dateNowWithDifferentTime.with(TemporalAdjusters.next(daysOfWeek.get(0)))); // @formatter:on } - - /** - * This method translates map to function - * @param key type of the map and argument of the function - * @param value type of the map and return type of the function - * @param map the input map - * @return a function which returns map.get(arg) - */ - public static Function mapToFunction(Map map) - { - return key -> map.get(key); - } }
Amount:"); - final MinMax minMax = getPreciseMinMax(normalized.getChance(), generalDropItem.getMin(npc, activeChar), generalDropItem.getMax(npc, activeChar), generalDropItem.isPreciseCalculated()); - final long min = minMax.min; - final long max = minMax.max; + + final long min = generalDropItem.getMin(npc, activeChar); + final long max = generalDropItem.getMax(npc, activeChar); sb.append(amountFormat.format(min)); if (min != max) { @@ -379,62 +431,4 @@ public class NpcViewMod implements IBypassHandler html = html.replaceAll("%items%", bodySb.toString()); Util.sendCBHtml(activeChar, html); } - - /** - * @param activeChar - * @param npc - * @param amountFormat - * @param chanceFormat - * @param sb - * @param dropItem - */ - private static void addGeneralDropItem(L2PcInstance activeChar, L2Npc npc, DecimalFormat amountFormat, DecimalFormat chanceFormat, StringBuilder sb, GeneralDropItem dropItem) - { - final L2Item item = ItemTable.getInstance().getTemplate(dropItem.getItemId()); - sb.append(""); - sb.append("
"); - sb.append(""); - sb.append(""); - sb.append(item.getName()); - sb.append("
"); - sb.append(""); - sb.append(""); - sb.append("
Amount:"); - final MinMax minMax = getPreciseMinMax(dropItem.getChance(npc, activeChar), dropItem.getMin(npc, activeChar), dropItem.getMax(npc, activeChar), dropItem.isPreciseCalculated()); - - final long min = minMax.min; - final long max = minMax.max; - sb.append(amountFormat.format(min)); - if (min != max) - { - sb.append(" - "); - sb.append(amountFormat.format(max)); - } - - sb.append("
Chance:"); - sb.append(chanceFormat.format(Math.min(dropItem.getChance(npc, activeChar), 100))); - sb.append("%
 
"); - } - - private static class MinMax - { - public final long min, max; - - public MinMax(long min, long max) - { - this.min = min; - this.max = max; - } - } - - private static MinMax getPreciseMinMax(double chance, long min, long max, boolean isPrecise) - { - if (!isPrecise || (chance <= 100)) - { - return new MinMax(min, max); - } - - final int mult = (int) chance / 100; - return new MinMax(mult * min, (chance % 100) > 0 ? (mult + 1) * max : mult * max); - } } diff --git a/trunk/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java b/trunk/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java index dbe00051dc..1089903af3 100644 --- a/trunk/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java +++ b/trunk/dist/game/data/scripts/handlers/voicedcommandhandlers/Premium.java @@ -49,11 +49,15 @@ public class Premium implements IVoicedCommandHandler html.append("
Rate SP: x" + Config.RATE_SP + "
Drop Chance: x" + Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER + "
Drop Amount: x" + Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER + "
Spoil Chance: x" + Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER + "
Spoil Amount: x" + Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER + "

Premium Info & Rules
Rate XP: x" + (Config.RATE_XP * Config.PREMIUM_RATE_XP) + "
Rate SP: x" + (Config.RATE_SP * Config.PREMIUM_RATE_SP) + "
Drop Chance: x" + (Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER * Config.PREMIUM_RATE_DROP_CHANCE) + "
Drop Amount: x" + (Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER * Config.PREMIUM_RATE_DROP_AMOUNT) + "
Spoil Chance: x" + (Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER * Config.PREMIUM_RATE_SPOIL_CHANCE) + "
Spoil Amount: x" + (Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER * Config.PREMIUM_RATE_SPOIL_AMOUNT) + "
1. Premium benefits CAN NOT BE TRANSFERED.
2. Premium does not effect party members.
3. Premium benefits effect ALL characters in same account.
Rate SP: x" + (Config.RATE_SP * Config.PREMIUM_RATE_SP) + "
Drop Chance: x" + (Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER * Config.PREMIUM_RATE_DROP_CHANCE) + "
Drop Amount: x" + (Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER * Config.PREMIUM_RATE_DROP_AMOUNT) + "
Spoil Chance: x" + (Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER * Config.PREMIUM_RATE_SPOIL_CHANCE) + "
Spoil Amount: x" + (Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER * Config.PREMIUM_RATE_SPOIL_AMOUNT) + "
Expires: " + String.valueOf(format.format(endDate)) + "
Current Date: " + String.valueOf(format.format(System.currentTimeMillis())) + "

Premium Info & Rules