Last active
August 29, 2015 13:57
-
-
Save Battlecruiser/9682928 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/dist/game/config/General.properties b/dist/game/config/General.properties | |
index 46b2f78..8ff2722 100644 | |
--- a/dist/game/config/General.properties | |
+++ b/dist/game/config/General.properties | |
@@ -339,7 +339,8 @@ ClearDroppedItemTable = False | |
# Default: False | |
AutoDeleteInvalidQuestData = False | |
-# Setting False can improve server performance on high rate/population servers. | |
+# If True, allows a special handling for drops when chance raises over 100% (eg. when applying chance rates). | |
+# True value causes better drop handling at higher rates. | |
# Default: True | |
PreciseDropCalculation = True | |
@@ -970,4 +971,4 @@ AltDevShowQuestsLoadInLogs = False | |
# Show scripts while loading them. | |
# Default: False | |
-AltDevShowScriptsLoadInLogs = False | |
\ No newline at end of file | |
+AltDevShowScriptsLoadInLogs = False | |
diff --git a/dist/game/config/NPC.properties b/dist/game/config/NPC.properties | |
index 6bc7483..420582d 100644 | |
--- a/dist/game/config/NPC.properties | |
+++ b/dist/game/config/NPC.properties | |
@@ -182,6 +182,15 @@ MinionChaosTime = 10 | |
# 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 | |
@@ -206,4 +215,4 @@ DropItemMaxLevelDifference=10 | |
# to allow dropping the item if level difference is bigger than DropAdenaMaxLevelDifference | |
# Note: This value is scalling from 100 to the specified value for DropAdenaMinLevelDifference to DropAdenaMaxLevelDifference limits | |
# Default: 10 | |
-DropItemMinLevelGapChance=10 | |
\ No newline at end of file | |
+DropItemMinLevelGapChance=10 | |
diff --git a/dist/game/config/Rates.properties b/dist/game/config/Rates.properties | |
index 336cc36..c6e9eed 100644 | |
--- a/dist/game/config/Rates.properties | |
+++ b/dist/game/config/Rates.properties | |
@@ -12,10 +12,12 @@ | |
DeathDropAmountMultiplier = 1 | |
CorpseDropAmountMultiplier = 1 | |
HerbDropAmountMultiplier = 1 | |
+RaidDropAmountMultiplier = 1 | |
DeathDropChanceMultiplier = 1 | |
CorpseDropChanceMultiplier = 1 | |
HerbDropChanceMultiplier = 1 | |
+RaidDropChanceMultiplier = 1 | |
# List of items affected by custom drop rate by id, used now for Adena rate too. | |
# Usage: itemId1,multiplier1;itemId2,multiplier2;... | |
diff --git a/java/com/l2jserver/Config.java b/java/com/l2jserver/Config.java | |
index c24007f..f9e0047 100644 | |
--- a/java/com/l2jserver/Config.java | |
+++ b/java/com/l2jserver/Config.java | |
@@ -1,18 +1,18 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
@@ -794,6 +794,8 @@ 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; | |
@@ -869,9 +871,11 @@ public final class Config | |
public static float RATE_DEATH_DROP_AMOUNT_MULTIPLIER; | |
public static float RATE_CORPSE_DROP_AMOUNT_MULTIPLIER; | |
public static float RATE_HERB_DROP_AMOUNT_MULTIPLIER; | |
+ public static float RATE_RAID_DROP_AMOUNT_MULTIPLIER; | |
public static float RATE_DEATH_DROP_CHANCE_MULTIPLIER; | |
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<Integer, Float> RATE_DROP_AMOUNT_MULTIPLIER; | |
public static Map<Integer, Float> RATE_DROP_CHANCE_MULTIPLIER; | |
public static float RATE_KARMA_LOST; | |
@@ -1835,6 +1839,7 @@ 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); | |
@@ -2025,6 +2030,8 @@ 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); | |
@@ -2186,9 +2193,11 @@ public final class Config | |
RATE_DEATH_DROP_AMOUNT_MULTIPLIER = RatesSettings.getFloat("DeathDropAmountMultiplier", 1); | |
RATE_CORPSE_DROP_AMOUNT_MULTIPLIER = RatesSettings.getFloat("CorpseDropAmountMultiplier", 1); | |
RATE_HERB_DROP_AMOUNT_MULTIPLIER = RatesSettings.getFloat("HerbDropAmountMultiplier", 1); | |
+ RATE_RAID_DROP_AMOUNT_MULTIPLIER = RatesSettings.getFloat("RaidDropAmountMultiplier", 1); | |
RATE_DEATH_DROP_CHANCE_MULTIPLIER = RatesSettings.getFloat("DeathDropChanceMultiplier", 1); | |
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); | |
String[] dropAmountMultiplier = RatesSettings.getString("DropAmountMultiplierByItemId", "").split(";"); | |
RATE_DROP_AMOUNT_MULTIPLIER = new HashMap<>(dropAmountMultiplier.length); | |
if (!dropAmountMultiplier[0].isEmpty()) | |
@@ -3022,6 +3031,9 @@ public final class Config | |
case "cleardroppeditemtable": | |
CLEAR_DROPPED_ITEM_TABLE = Boolean.parseBoolean(pValue); | |
break; | |
+ case "precisedropcalculation": | |
+ PRECISE_DROP_CALCULATION = Boolean.parseBoolean(pValue); | |
+ break; | |
case "multipleitemdrop": | |
MULTIPLE_ITEM_DROP = Boolean.parseBoolean(pValue); | |
break; | |
@@ -3168,6 +3180,12 @@ public final class Config | |
case "maxdriftrange": | |
MAX_DRIFT_RANGE = Integer.parseInt(pValue); | |
break; | |
+ case "usedeepbluedroprules": | |
+ DEEPBLUE_DROP_RULES = Boolean.parseBoolean(pValue); | |
+ break; | |
+ case "usedeepbluedroprulesraid": | |
+ DEEPBLUE_DROP_RULES_RAID = Boolean.parseBoolean(pValue); | |
+ break; | |
case "guardattackaggromob": | |
GUARD_ATTACK_AGGRO_MOB = Boolean.parseBoolean(pValue); | |
break; | |
diff --git a/java/com/l2jserver/gameserver/model/drops/CorpseDropItem.java b/java/com/l2jserver/gameserver/model/drops/CorpseDropItem.java | |
deleted file mode 100644 | |
index efe0486..0000000 | |
--- a/java/com/l2jserver/gameserver/model/drops/CorpseDropItem.java | |
+++ /dev/null | |
@@ -1,69 +0,0 @@ | |
-/* | |
- * Copyright (C) 2004-2014 L2J Server | |
- * | |
- * This file is part of L2J Server. | |
- * | |
- * L2J Server 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. | |
- * | |
- * L2J Server 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 <http://www.gnu.org/licenses/>. | |
- */ | |
-package com.l2jserver.gameserver.model.drops; | |
- | |
-import com.l2jserver.Config; | |
-import com.l2jserver.gameserver.model.actor.L2Character; | |
- | |
-/** | |
- * @author Nos | |
- */ | |
-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#getMin(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public long getMin(L2Character victim, L2Character killer) | |
- { | |
- return (long) (super.getMin(victim, killer) * Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getMax(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public long getMax(L2Character victim, L2Character killer) | |
- { | |
- return (long) (super.getMax(victim, killer) * Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getChance(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public double getChance(L2Character victim, L2Character killer) | |
- { | |
- return super.getChance(victim, killer) * Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER; | |
- } | |
-} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/DeathDropItem.java b/java/com/l2jserver/gameserver/model/drops/DeathDropItem.java | |
deleted file mode 100644 | |
index 43cb4a5..0000000 | |
--- a/java/com/l2jserver/gameserver/model/drops/DeathDropItem.java | |
+++ /dev/null | |
@@ -1,69 +0,0 @@ | |
-/* | |
- * Copyright (C) 2004-2014 L2J Server | |
- * | |
- * This file is part of L2J Server. | |
- * | |
- * L2J Server 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. | |
- * | |
- * L2J Server 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 <http://www.gnu.org/licenses/>. | |
- */ | |
-package com.l2jserver.gameserver.model.drops; | |
- | |
-import com.l2jserver.Config; | |
-import com.l2jserver.gameserver.model.actor.L2Character; | |
- | |
-/** | |
- * @author Nos | |
- */ | |
-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#getMin(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public long getMin(L2Character victim, L2Character killer) | |
- { | |
- return (long) (super.getMin(victim, killer) * Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getMax(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public long getMax(L2Character victim, L2Character killer) | |
- { | |
- return (long) (super.getMax(victim, killer) * Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GeneralDropItem#getChance(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public double getChance(L2Character victim, L2Character killer) | |
- { | |
- return super.getChance(victim, killer) * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER; | |
- } | |
-} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/DropListScope.java b/java/com/l2jserver/gameserver/model/drops/DropListScope.java | |
index 5e069b7..9597180 100644 | |
--- a/java/com/l2jserver/gameserver/model/drops/DropListScope.java | |
+++ b/java/com/l2jserver/gameserver/model/drops/DropListScope.java | |
@@ -1,92 +1,63 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
package com.l2jserver.gameserver.model.drops; | |
-import java.lang.reflect.Constructor; | |
-import java.lang.reflect.InvocationTargetException; | |
-import java.util.logging.Level; | |
-import java.util.logging.Logger; | |
+import com.l2jserver.gameserver.model.drops.strategy.IAmountMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IChanceMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IGroupedItemDropCalculationStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; | |
/** | |
* @author Nos | |
*/ | |
-public enum DropListScope | |
+public enum DropListScope implements IDropItemFactory, IGroupedDropItemFactory | |
{ | |
- DEATH(DeathDropItem.class, GroupedDeathDropItem.class), | |
- CORPSE(CorpseDropItem.class, GroupedCorpseDropItem.class); | |
+ 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), | |
- private static final Logger _log = Logger.getLogger(DropListScope.class.getName()); | |
+ /** | |
+ * 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 final Class<? extends GeneralDropItem> _dropItemClass; | |
- private final Class<? extends GroupedGeneralDropItem> _groupedDropItemClass; | |
+ private final IDropItemFactory _factory; | |
+ private final IGroupedDropItemFactory _groupFactory; | |
- private DropListScope(Class<? extends GeneralDropItem> dropItemClass, Class<? extends GroupedGeneralDropItem> groupedDropItemClass) | |
+ private DropListScope(IDropItemFactory factory, IGroupedDropItemFactory groupFactory) | |
{ | |
- _dropItemClass = dropItemClass; | |
- _groupedDropItemClass = groupedDropItemClass; | |
+ _factory = factory; | |
+ _groupFactory = groupFactory; | |
} | |
+ @Override | |
public IDropItem newDropItem(int itemId, long min, long max, double chance) | |
{ | |
- final Constructor<? extends GeneralDropItem> 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; | |
- } | |
+ return _factory.newDropItem(itemId, min, max, chance); | |
} | |
+ @Override | |
public GroupedGeneralDropItem newGroupedDropItem(double chance) | |
{ | |
- final Constructor<? extends GroupedGeneralDropItem> 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; | |
- } | |
+ return _groupFactory.newGroupedDropItem(chance); | |
} | |
} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/GeneralDropItem.java b/java/com/l2jserver/gameserver/model/drops/GeneralDropItem.java | |
index 467b2f3..87378bc 100644 | |
--- a/java/com/l2jserver/gameserver/model/drops/GeneralDropItem.java | |
+++ b/java/com/l2jserver/gameserver/model/drops/GeneralDropItem.java | |
@@ -1,43 +1,50 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
package com.l2jserver.gameserver.model.drops; | |
-import java.util.ArrayList; | |
import java.util.List; | |
-import com.l2jserver.Config; | |
import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.strategy.IAmountMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IChanceMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IDropCalculationStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.INonGroupedKillerChanceModifierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; | |
import com.l2jserver.gameserver.model.holders.ItemHolder; | |
-import com.l2jserver.gameserver.model.itemcontainer.Inventory; | |
-import com.l2jserver.gameserver.util.Util; | |
-import com.l2jserver.util.Rnd; | |
/** | |
* @author Nos | |
*/ | |
-public class GeneralDropItem implements IDropItem | |
+public final 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 | |
@@ -46,105 +53,155 @@ public class GeneralDropItem implements IDropItem | |
*/ | |
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() | |
+ { | |
+ return _amountStrategy; | |
+ } | |
+ | |
+ /** | |
+ * @return the _chanceStrategy | |
+ */ | |
+ public final IChanceMultiplierStrategy getChanceStrategy() | |
+ { | |
+ return _chanceStrategy; | |
+ } | |
+ | |
+ /** | |
+ * @return the _preciseStrategy | |
+ */ | |
+ public final IPreciseDeterminationStrategy getPreciseStrategy() | |
+ { | |
+ return _preciseStrategy; | |
+ } | |
+ | |
+ /** | |
+ * @return the _killerStrategy | |
+ */ | |
+ public final INonGroupedKillerChanceModifierStrategy getKillerChanceModifierStrategy() | |
+ { | |
+ return _killerStrategy; | |
+ } | |
+ | |
+ /** | |
+ * @return the _dropCalculationStrategy | |
+ */ | |
+ public final IDropCalculationStrategy getDropCalculationStrategy() | |
+ { | |
+ return _dropCalculationStrategy; | |
} | |
/** | |
* Gets the item id | |
* @return the item id | |
*/ | |
- public int getItemId() | |
+ public final int getItemId() | |
{ | |
return _itemId; | |
} | |
/** | |
- * Gets the min drop count | |
+ * Gets the base min drop count | |
* @return the min | |
*/ | |
- public long getMin() | |
+ public final long getMin() | |
{ | |
return _min; | |
} | |
/** | |
- * Gets the min drop count | |
- * @param victim the victim | |
- * @param killer the killer | |
+ * Gets the min drop count modified by server rates | |
+ * @param victim the victim who drops the item | |
* @return the min modified by any rates. | |
*/ | |
- public long getMin(L2Character victim, L2Character killer) | |
+ public final long getMin(L2Character victim) | |
{ | |
- double multiplier = 1; | |
- if (victim.isChampion()) | |
- { | |
- multiplier *= getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS : Config.L2JMOD_CHAMPION_ADENAS_REWARDS; | |
- } | |
- Float dropChanceMultiplier = Config.RATE_DROP_AMOUNT_MULTIPLIER.get(getItemId()); | |
- if (dropChanceMultiplier != null) | |
- { | |
- multiplier *= dropChanceMultiplier; | |
- } | |
- return (long) (getMin() * multiplier); | |
+ return (long) (getMin() * getAmountMultiplier(victim)); | |
} | |
/** | |
- * Gets the max drop count | |
+ * Gets the base max drop count | |
* @return the max | |
*/ | |
- public long getMax() | |
+ public final long getMax() | |
{ | |
return _max; | |
} | |
/** | |
- * Gets the max drop count | |
- * @param victim the victim | |
- * @param killer the killer | |
+ * Gets the max drop count modified by server rates | |
+ * @param victim the victim who drops the item | |
* @return the max modified by any rates. | |
*/ | |
- public long getMax(L2Character victim, L2Character killer) | |
+ public final long getMax(L2Character victim) | |
{ | |
- double multiplier = 1; | |
- if (victim.isChampion()) | |
- { | |
- multiplier *= getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS : Config.L2JMOD_CHAMPION_ADENAS_REWARDS; | |
- } | |
- Float dropChanceMultiplier = Config.RATE_DROP_AMOUNT_MULTIPLIER.get(getItemId()); | |
- if (dropChanceMultiplier != null) | |
- { | |
- multiplier *= dropChanceMultiplier; | |
- } | |
- return (long) (getMax() * multiplier); | |
+ return (long) (getMax() * getAmountMultiplier(victim)); | |
} | |
/** | |
* Gets the chance of this drop item. | |
* @return the chance | |
*/ | |
- public double getChance() | |
+ public final double getChance() | |
{ | |
return _chance; | |
} | |
/** | |
- * Gets the chance of this drop item. | |
- * @param victim the victim | |
- * @param killer the killer | |
+ * Gets the general chance to drop this item modified by rates. <br> | |
+ * This shall be used in calculating chance within drop groups. | |
+ * @param victim the victim who drops the item | |
* @return the chance modified by any rates. | |
*/ | |
- public double getChance(L2Character victim, L2Character killer) | |
+ public final double getChance(L2Character victim) | |
{ | |
- float multiplier = 1; | |
- Float dropChanceMultiplier = Config.RATE_DROP_CHANCE_MULTIPLIER.get(getItemId()); | |
- if (dropChanceMultiplier != null) | |
- { | |
- multiplier *= dropChanceMultiplier; | |
- } | |
- return getChance() * multiplier; | |
+ 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) <br> | |
+ * 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) | |
+ { | |
+ return (getKillerChanceModifier(victim, killer) * getChance(victim)); | |
} | |
/* | |
@@ -152,34 +209,47 @@ public class GeneralDropItem implements IDropItem | |
* @see com.l2jserver.gameserver.model.drop.IDropItem#calculateDrops(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
*/ | |
@Override | |
- public List<ItemHolder> calculateDrops(L2Character victim, L2Character killer) | |
- { | |
- 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; | |
- } | |
- | |
- if (getChance(victim, killer) > (Rnd.nextDouble() * 100)) | |
- { | |
- final long amount = Rnd.get(getMin(victim, killer), getMax(victim, killer)); | |
- | |
- final List<ItemHolder> items = new ArrayList<>(1); | |
- items.add(new ItemHolder(getItemId(), amount)); | |
- return items; | |
- } | |
- | |
- return null; | |
+ public final List<ItemHolder> calculateDrops(L2Character victim, L2Character killer) | |
+ { | |
+ return _dropCalculationStrategy.calculateDrops(this, victim, killer); | |
+ } | |
+ | |
+ /** | |
+ * @return <code>true</code> 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); | |
} | |
} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/GroupedCorpseDropItem.java b/java/com/l2jserver/gameserver/model/drops/GroupedCorpseDropItem.java | |
deleted file mode 100644 | |
index 6c217d3..0000000 | |
--- a/java/com/l2jserver/gameserver/model/drops/GroupedCorpseDropItem.java | |
+++ /dev/null | |
@@ -1,46 +0,0 @@ | |
-/* | |
- * Copyright (C) 2004-2014 L2J Server | |
- * | |
- * This file is part of L2J Server. | |
- * | |
- * L2J Server 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. | |
- * | |
- * L2J Server 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 <http://www.gnu.org/licenses/>. | |
- */ | |
-package com.l2jserver.gameserver.model.drops; | |
- | |
-import com.l2jserver.Config; | |
-import com.l2jserver.gameserver.model.actor.L2Character; | |
- | |
-/** | |
- * @author Nos | |
- */ | |
-public class GroupedCorpseDropItem extends GroupedGeneralDropItem | |
-{ | |
- /** | |
- * @param chance the chance of this drop item. | |
- */ | |
- public GroupedCorpseDropItem(double chance) | |
- { | |
- super(chance); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem#getChance(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public double getChance(L2Character victim, L2Character killer) | |
- { | |
- return super.getChance(victim, killer) * Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER; | |
- } | |
-} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/GroupedDeathDropItem.java b/java/com/l2jserver/gameserver/model/drops/GroupedDeathDropItem.java | |
deleted file mode 100644 | |
index 90996e2..0000000 | |
--- a/java/com/l2jserver/gameserver/model/drops/GroupedDeathDropItem.java | |
+++ /dev/null | |
@@ -1,46 +0,0 @@ | |
-/* | |
- * Copyright (C) 2004-2014 L2J Server | |
- * | |
- * This file is part of L2J Server. | |
- * | |
- * L2J Server 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. | |
- * | |
- * L2J Server 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 <http://www.gnu.org/licenses/>. | |
- */ | |
-package com.l2jserver.gameserver.model.drops; | |
- | |
-import com.l2jserver.Config; | |
-import com.l2jserver.gameserver.model.actor.L2Character; | |
- | |
-/** | |
- * @author Nos | |
- */ | |
-public class GroupedDeathDropItem extends GroupedGeneralDropItem | |
-{ | |
- /** | |
- * @param chance the chance of this drop item. | |
- */ | |
- public GroupedDeathDropItem(double chance) | |
- { | |
- super(chance); | |
- } | |
- | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem#getChance(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
- */ | |
- @Override | |
- public double getChance(L2Character victim, L2Character killer) | |
- { | |
- return super.getChance(victim, killer) * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER; | |
- } | |
-} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/GroupedGeneralDropItem.java b/java/com/l2jserver/gameserver/model/drops/GroupedGeneralDropItem.java | |
index e14fa31..590ac7d 100644 | |
--- a/java/com/l2jserver/gameserver/model/drops/GroupedGeneralDropItem.java | |
+++ b/java/com/l2jserver/gameserver/model/drops/GroupedGeneralDropItem.java | |
@@ -1,18 +1,18 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
@@ -22,110 +22,235 @@ import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
-import com.l2jserver.Config; | |
import com.l2jserver.gameserver.model.actor.L2Character; | |
-import com.l2jserver.gameserver.model.actor.instance.L2RaidBossInstance; | |
+import com.l2jserver.gameserver.model.drops.strategy.IAmountMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IChanceMultiplierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IGroupedItemDropCalculationStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IKillerChanceModifierStrategy; | |
+import com.l2jserver.gameserver.model.drops.strategy.IPreciseDeterminationStrategy; | |
import com.l2jserver.gameserver.model.holders.ItemHolder; | |
-import com.l2jserver.gameserver.util.Util; | |
-import com.l2jserver.util.Rnd; | |
/** | |
* @author Nos | |
*/ | |
-public class GroupedGeneralDropItem implements IDropItem | |
+public final class GroupedGeneralDropItem implements IDropItem | |
{ | |
+ | |
private final double _chance; | |
private List<GeneralDropItem> _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) | |
{ | |
- _chance = chance; | |
+ this(chance, IGroupedItemDropCalculationStrategy.DEFAULT_STRATEGY, IKillerChanceModifierStrategy.DEFAULT_STRATEGY, IPreciseDeterminationStrategy.DEFAULT); | |
} | |
/** | |
- * Gets the chance of this drop item. | |
- * @return the chance | |
+ * @param chance the chance of this drop item. | |
+ * @param dropStrategy to calculate drops. | |
+ * @param killerStrategy | |
+ * @param preciseStrategy | |
*/ | |
- public double getChance() | |
+ public GroupedGeneralDropItem(double chance, IGroupedItemDropCalculationStrategy dropStrategy, IKillerChanceModifierStrategy killerStrategy, IPreciseDeterminationStrategy preciseStrategy) | |
{ | |
- return _chance; | |
+ _chance = chance; | |
+ _dropCalculationStrategy = dropStrategy; | |
+ _killerChanceModifierStrategy = killerStrategy; | |
+ _preciseStrategy = preciseStrategy; | |
} | |
/** | |
* Gets the chance of this drop item. | |
- * @param victim the victim | |
- * @param killer the killer | |
- * @return the chance modified by any rates. | |
+ * @return the chance | |
*/ | |
- public double getChance(L2Character victim, L2Character killer) | |
+ public final double getChance() | |
{ | |
- return getChance(); | |
+ return _chance; | |
} | |
/** | |
* Gets the items. | |
* @return the items | |
*/ | |
- public List<GeneralDropItem> getItems() | |
+ public final List<GeneralDropItem> 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 void setItems(List<GeneralDropItem> items) | |
+ public final void setItems(List<GeneralDropItem> items) | |
{ | |
_items = Collections.unmodifiableList(items); | |
} | |
- /* | |
- * (non-Javadoc) | |
- * @see com.l2jserver.gameserver.model.drop.IDropItem#calculateDrops(com.l2jserver.gameserver.model.actor.L2Character, com.l2jserver.gameserver.model.actor.L2Character) | |
+ /** | |
+ * Returns a list of items in the group with chance multiplied by chance of the group | |
+ * @return the list of items with modified chances | |
*/ | |
- @Override | |
- public List<ItemHolder> calculateDrops(L2Character victim, L2Character killer) | |
+ public final List<GeneralDropItem> extractMe() | |
{ | |
- int levelDifference = victim.getLevel() - killer.getLevel(); | |
- double chanceModifier; | |
- if (victim instanceof L2RaidBossInstance) | |
+ List<GeneralDropItem> items = new ArrayList<>(); | |
+ for (final GeneralDropItem item : getItems()) | |
{ | |
- chanceModifier = Math.max(0, Math.min(1, (levelDifference * 0.15) + 1)); | |
+ // 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())); | |
} | |
- else | |
+ 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()) | |
{ | |
- chanceModifier = 1; | |
- | |
- double 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; | |
- } | |
+ sumchance += (item.getChance() * getChance()) / 100; | |
} | |
- | |
- if ((getChance(victim, killer) * chanceModifier) > (Rnd.nextDouble() * 100)) | |
+ final double sumchance1 = sumchance; | |
+ GroupedGeneralDropItem group = new GroupedGeneralDropItem(sumchance1, getDropCalculationStrategy(), IKillerChanceModifierStrategy.NO_RULES, getPreciseStrategy()); | |
+ List<GeneralDropItem> items = new ArrayList<>(); | |
+ for (final GeneralDropItem item : getItems()) | |
{ | |
- double random = (Rnd.nextDouble() * 100); | |
- double totalChance = 0; | |
- for (GeneralDropItem item : getItems()) | |
- { | |
- // Grouped item chance rates should not be modified. | |
- totalChance += item.getChance(); | |
- if (totalChance > random) | |
- { | |
- long amount = Rnd.get(item.getMin(victim, killer), item.getMax(victim, killer)); | |
- | |
- List<ItemHolder> items = new ArrayList<>(1); | |
- items.add(new ItemHolder(item.getItemId(), amount)); | |
- return items; | |
- } | |
- } | |
+ // 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())); | |
} | |
- return null; | |
+ 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) * getChance() * chanceModifier) / 100; | |
+ } | |
+ GroupedGeneralDropItem group = new GroupedGeneralDropItem(sumchance, getDropCalculationStrategy(), IKillerChanceModifierStrategy.NO_RULES, getPreciseStrategy()); // to discard further deep blue calculations | |
+ List<GeneralDropItem> items = new ArrayList<>(); | |
+ for (GeneralDropItem item : getItems()) | |
+ { | |
+ // the item is made almost "static" | |
+ items.add(new GeneralDropItem(item.getItemId(), item.getMin(victim), item.getMax(victim), (item.getChance(victim) * getChance() * chanceModifier) / sumchance, IAmountMultiplierStrategy.STATIC, IChanceMultiplierStrategy.STATIC, getPreciseStrategy(), IKillerChanceModifierStrategy.NO_RULES, item.getDropCalculationStrategy())); | |
+ } | |
+ group.setItems(items); | |
+ return group; | |
+ | |
+ } | |
+ | |
+ /* | |
+ * (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<ItemHolder> 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); | |
} | |
} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/IDropItem.java b/java/com/l2jserver/gameserver/model/drops/IDropItem.java | |
index 58d9b93..5f84a9c 100644 | |
--- a/java/com/l2jserver/gameserver/model/drops/IDropItem.java | |
+++ b/java/com/l2jserver/gameserver/model/drops/IDropItem.java | |
@@ -28,6 +28,7 @@ import com.l2jserver.gameserver.model.holders.ItemHolder; | |
*/ | |
public interface IDropItem | |
{ | |
+ | |
/** | |
* Calculates drops of this drop item. | |
* @param victim the victim | |
diff --git a/java/com/l2jserver/gameserver/model/drops/IDropItemFactory.java b/java/com/l2jserver/gameserver/model/drops/IDropItemFactory.java | |
new file mode 100644 | |
index 0000000..f5c0133 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/IDropItemFactory.java | |
@@ -0,0 +1,34 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IDropItemFactory | |
+{ | |
+ /** | |
+ * @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 | |
+ */ | |
+ public IDropItem newDropItem(int itemId, long min, long max, double chance); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/IGroupedDropItemFactory.java b/java/com/l2jserver/gameserver/model/drops/IGroupedDropItemFactory.java | |
new file mode 100644 | |
index 0000000..878529c | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/IGroupedDropItemFactory.java | |
@@ -0,0 +1,27 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IGroupedDropItemFactory | |
+{ | |
+ public GroupedGeneralDropItem newGroupedDropItem(double chance); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java | |
new file mode 100644 | |
index 0000000..afa261a | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IAmountMultiplierStrategy.java | |
@@ -0,0 +1,67 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import com.l2jserver.Config; | |
+import com.l2jserver.gameserver.datatables.ItemTable; | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.itemcontainer.Inventory; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IAmountMultiplierStrategy | |
+{ | |
+ public static final IAmountMultiplierStrategy DROP = DEFAULT_STRATEGY(Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER); | |
+ public static final IAmountMultiplierStrategy SPOIL = DEFAULT_STRATEGY(Config.RATE_CORPSE_DROP_AMOUNT_MULTIPLIER); | |
+ public static final IAmountMultiplierStrategy STATIC = (item, victim) -> 1; | |
+ | |
+ public static IAmountMultiplierStrategy DEFAULT_STRATEGY(final double defaultMultiplier) | |
+ { | |
+ return (item, victim) -> | |
+ { | |
+ double multiplier = 1; | |
+ if (victim.isChampion()) | |
+ { | |
+ multiplier *= item.getItemId() != Inventory.ADENA_ID ? Config.L2JMOD_CHAMPION_REWARDS : Config.L2JMOD_CHAMPION_ADENAS_REWARDS; | |
+ } | |
+ Float dropChanceMultiplier = Config.RATE_DROP_AMOUNT_MULTIPLIER.get(item.getItemId()); | |
+ if (dropChanceMultiplier != null) | |
+ { | |
+ multiplier *= dropChanceMultiplier; | |
+ } | |
+ 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; | |
+ }; | |
+ } | |
+ | |
+ public double getAmountMultiplier(GeneralDropItem item, L2Character victim); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java | |
new file mode 100644 | |
index 0000000..ccc6031 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IChanceMultiplierStrategy.java | |
@@ -0,0 +1,78 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import com.l2jserver.Config; | |
+import com.l2jserver.gameserver.datatables.ItemTable; | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.itemcontainer.Inventory; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IChanceMultiplierStrategy | |
+{ | |
+ public static final IChanceMultiplierStrategy DROP = DEFAULT_STRATEGY(Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER); | |
+ public static final IChanceMultiplierStrategy SPOIL = DEFAULT_STRATEGY(Config.RATE_CORPSE_DROP_CHANCE_MULTIPLIER); | |
+ public static final IChanceMultiplierStrategy STATIC = (item, victim) -> 1; | |
+ | |
+ public static final IChanceMultiplierStrategy QUEST = (item, victim) -> | |
+ { | |
+ double championmult; | |
+ if ((item.getItemId() == Inventory.ADENA_ID) || (item.getItemId() == Inventory.ANCIENT_ADENA_ID)) | |
+ { | |
+ championmult = Config.L2JMOD_CHAMPION_ADENAS_REWARDS; | |
+ } | |
+ else | |
+ { | |
+ championmult = Config.L2JMOD_CHAMPION_REWARDS; | |
+ } | |
+ | |
+ return (Config.L2JMOD_CHAMPION_ENABLE && (victim != null) && victim.isChampion()) ? (Config.RATE_QUEST_DROP * championmult) : Config.RATE_QUEST_DROP; | |
+ }; | |
+ | |
+ public static IChanceMultiplierStrategy DEFAULT_STRATEGY(final double defaultMultiplier) | |
+ { | |
+ return (item, victim) -> | |
+ { | |
+ float multiplier = 1; | |
+ 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; | |
+ }; | |
+ } | |
+ | |
+ public double getChanceMultiplier(GeneralDropItem item, L2Character victim); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IDropCalculationStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IDropCalculationStrategy.java | |
new file mode 100644 | |
index 0000000..34c1b35 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IDropCalculationStrategy.java | |
@@ -0,0 +1,57 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import java.util.Collections; | |
+import java.util.List; | |
+ | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.holders.ItemHolder; | |
+import com.l2jserver.util.Rnd; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IDropCalculationStrategy | |
+{ | |
+ public static final IDropCalculationStrategy DEFAULT_STRATEGY = (item, victim, killer) -> | |
+ { | |
+ if (item.getChance(victim, killer) > (Rnd.nextDouble() * 100)) | |
+ { | |
+ int amountMultiply = 1; | |
+ if (item.isPreciseCalculated() && (item.getChance(victim, killer) > 100)) | |
+ { | |
+ amountMultiply = (int) item.getChance(victim, killer) / 100; | |
+ if ((item.getChance(victim, killer) % 100) > (Rnd.nextDouble() * 100)) | |
+ { | |
+ amountMultiply++; | |
+ } | |
+ } | |
+ | |
+ long amount = Rnd.get(item.getMin(victim) * amountMultiply, item.getMax(victim) * amountMultiply); | |
+ | |
+ return Collections.singletonList(new ItemHolder(item.getItemId(), amount)); | |
+ } | |
+ | |
+ return null; | |
+ }; | |
+ | |
+ public List<ItemHolder> calculateDrops(GeneralDropItem item, L2Character victim, L2Character killer); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java | |
new file mode 100644 | |
index 0000000..20ddf53 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IGroupedItemDropCalculationStrategy.java | |
@@ -0,0 +1,121 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import java.util.ArrayList; | |
+import java.util.Collections; | |
+import java.util.List; | |
+ | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem; | |
+import com.l2jserver.gameserver.model.drops.IDropItem; | |
+import com.l2jserver.gameserver.model.holders.ItemHolder; | |
+import com.l2jserver.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. | |
+ */ | |
+ public static final IGroupedItemDropCalculationStrategy DEFAULT_STRATEGY = (dropItem, victim, killer) -> | |
+ { | |
+ if (dropItem.getItems().size() == 1) | |
+ { | |
+ | |
+ final GeneralDropItem item1 = dropItem.getItems().iterator().next(); | |
+ return new GeneralDropItem(item1.getItemId(), item1.getMin(), item1.getMax(), (item1.getChance() * dropItem.getChance()) / 100, item1.getAmountStrategy(), item1.getChanceStrategy(), dropItem.getPreciseStrategy(), dropItem.getKillerChanceModifierStrategy(), item1.getDropCalculationStrategy()).calculateDrops(victim, killer); | |
+ } | |
+ | |
+ GroupedGeneralDropItem normalized = dropItem.normalizeMe(victim, killer); | |
+ if (normalized.getChance() > (Rnd.nextDouble() * 100)) | |
+ { | |
+ 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 += 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++; | |
+ } | |
+ } | |
+ | |
+ long amount = Rnd.get(item2.getMin(victim) * amountMultiply, item2.getMax(victim) * amountMultiply); | |
+ | |
+ return Collections.singletonList(new ItemHolder(item2.getItemId(), amount)); | |
+ } | |
+ } | |
+ } | |
+ return null; | |
+ }; | |
+ | |
+ /** | |
+ * This strategy calculates a group's drop by calculating drops of its individual items and merging its results. | |
+ */ | |
+ public static final IGroupedItemDropCalculationStrategy DISBAND_GROUP = (item, victim, killer) -> | |
+ { | |
+ List<ItemHolder> 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. | |
+ */ | |
+ public static final 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); | |
+ } | |
+ GroupedGeneralDropItem newItem = new GroupedGeneralDropItem(item.getChance(), DEFAULT_STRATEGY, item.getKillerChanceModifierStrategy(), IPreciseDeterminationStrategy.NEVER); | |
+ newItem.setItems(item.getItems()); | |
+ 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++; | |
+ } | |
+ List<ItemHolder> dropped = new ArrayList<>(); | |
+ for (; rolls > 0; rolls--) | |
+ { | |
+ // 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; | |
+ }; | |
+ | |
+ public List<ItemHolder> calculateDrops(GroupedGeneralDropItem item, L2Character victim, L2Character killer); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java | |
new file mode 100644 | |
index 0000000..023e462 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IKillerChanceModifierStrategy.java | |
@@ -0,0 +1,72 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import com.l2jserver.Config; | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.drops.IDropItem; | |
+import com.l2jserver.gameserver.model.itemcontainer.Inventory; | |
+import com.l2jserver.gameserver.util.Util; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IKillerChanceModifierStrategy extends INonGroupedKillerChanceModifierStrategy | |
+{ | |
+ public static final IKillerChanceModifierStrategy DEFAULT_STRATEGY = (item, victim, killer) -> | |
+ { | |
+ 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; | |
+ }; | |
+ public static final INonGroupedKillerChanceModifierStrategy DEFAULT_NONGROUP_STRATEGY = (item, victim, killer) -> | |
+ { | |
+ if (((!(victim.isRaid())) && Config.DEEPBLUE_DROP_RULES) || ((victim.isRaid()) && Config.DEEPBLUE_DROP_RULES_RAID)) | |
+ { | |
+ 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; | |
+ | |
+ public double getKillerChanceModifier(IDropItem item, L2Character victim, L2Character killer); | |
+ | |
+ @Override | |
+ public default double getKillerChanceModifier(GeneralDropItem item, L2Character victim, L2Character killer) | |
+ { | |
+ return getKillerChanceModifier((IDropItem) item, victim, killer); | |
+ } | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java | |
new file mode 100644 | |
index 0000000..a84fd5a | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/INonGroupedKillerChanceModifierStrategy.java | |
@@ -0,0 +1,30 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import com.l2jserver.gameserver.model.actor.L2Character; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface INonGroupedKillerChanceModifierStrategy | |
+{ | |
+ public double getKillerChanceModifier(GeneralDropItem item, L2Character victim, L2Character killer); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java b/java/com/l2jserver/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java | |
new file mode 100644 | |
index 0000000..57599c9 | |
--- /dev/null | |
+++ b/java/com/l2jserver/gameserver/model/drops/strategy/IPreciseDeterminationStrategy.java | |
@@ -0,0 +1,40 @@ | |
+/* | |
+ * Copyright (C) 2004-2014 L2J Server | |
+ * | |
+ * This file is part of L2J Server. | |
+ * | |
+ * L2J Server 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. | |
+ * | |
+ * L2J Server 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 <http://www.gnu.org/licenses/>. | |
+ */ | |
+package com.l2jserver.gameserver.model.drops.strategy; | |
+ | |
+import com.l2jserver.Config; | |
+import com.l2jserver.gameserver.model.drops.IDropItem; | |
+ | |
+/** | |
+ * @author Battlecruiser | |
+ */ | |
+public interface IPreciseDeterminationStrategy | |
+{ | |
+ public static final IPreciseDeterminationStrategy ALWAYS = dropItem -> true; | |
+ | |
+ public static final IPreciseDeterminationStrategy DEFAULT = dropItem -> Config.PRECISE_DROP_CALCULATION; | |
+ | |
+ public static final IPreciseDeterminationStrategy NEVER = dropItem -> false; | |
+ | |
+ /** | |
+ * @param dropItem | |
+ * @return <code>true</code> if drop calculation strategy should use precise rules | |
+ */ | |
+ public boolean isPreciseCalculated(IDropItem dropItem); | |
+} | |
diff --git a/java/com/l2jserver/gameserver/model/event/LongTimeEvent.java b/java/com/l2jserver/gameserver/model/event/LongTimeEvent.java | |
index 4ae519c..1244d30 100644 | |
--- a/java/com/l2jserver/gameserver/model/event/LongTimeEvent.java | |
+++ b/java/com/l2jserver/gameserver/model/event/LongTimeEvent.java | |
@@ -1,18 +1,18 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
@@ -38,6 +38,7 @@ import com.l2jserver.gameserver.datatables.EventDroplist; | |
import com.l2jserver.gameserver.datatables.ItemTable; | |
import com.l2jserver.gameserver.datatables.NpcData; | |
import com.l2jserver.gameserver.model.Location; | |
+import com.l2jserver.gameserver.model.drops.DropListScope; | |
import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
import com.l2jserver.gameserver.model.quest.Quest; | |
import com.l2jserver.gameserver.script.DateRange; | |
@@ -50,38 +51,38 @@ import com.l2jserver.gameserver.script.DateRange; | |
public class LongTimeEvent extends Quest | |
{ | |
private String _eventName; | |
- | |
+ | |
// Messages | |
private String _onEnterMsg = "Event is in process"; | |
protected String _endMsg = "Event ends!"; | |
- | |
+ | |
private DateRange _eventPeriod = null; | |
private DateRange _dropPeriod; | |
- | |
+ | |
// NPC's to spawm and their spawn points | |
private final List<NpcSpawn> _spawnList = new ArrayList<>(); | |
- | |
+ | |
// Drop data for event | |
private final List<GeneralDropItem> _dropList = new ArrayList<>(); | |
- | |
+ | |
private class NpcSpawn | |
{ | |
protected final Location loc; | |
protected final int npcId; | |
- | |
+ | |
protected NpcSpawn(int pNpcId, Location spawnLoc) | |
{ | |
loc = spawnLoc; | |
npcId = pNpcId; | |
} | |
} | |
- | |
+ | |
public LongTimeEvent(String name, String descr) | |
{ | |
super(-1, name, descr); | |
- | |
+ | |
loadConfig(); | |
- | |
+ | |
if (_eventPeriod != null) | |
{ | |
if (_eventPeriod.isWithinRange(new Date())) | |
@@ -101,7 +102,7 @@ public class LongTimeEvent extends Quest | |
} | |
} | |
} | |
- | |
+ | |
/** | |
* Load event configuration file | |
*/ | |
@@ -120,7 +121,7 @@ public class LongTimeEvent extends Quest | |
_eventName = doc.getDocumentElement().getAttributes().getNamedItem("name").getNodeValue(); | |
String period = doc.getDocumentElement().getAttributes().getNamedItem("active").getNodeValue(); | |
_eventPeriod = DateRange.parse(period, new SimpleDateFormat("dd MM yyyy", Locale.US)); | |
- | |
+ | |
if (doc.getDocumentElement().getAttributes().getNamedItem("dropPeriod") != null) | |
{ | |
String dropPeriod = doc.getDocumentElement().getAttributes().getNamedItem("dropPeriod").getNodeValue(); | |
@@ -135,14 +136,14 @@ public class LongTimeEvent extends Quest | |
{ | |
_dropPeriod = _eventPeriod; // Drop period, if not specified, assumes all event period. | |
} | |
- | |
+ | |
if (_eventPeriod == null) | |
{ | |
throw new NullPointerException("WARNING!!! " + getScriptName() + " event: illegal event period"); | |
} | |
- | |
+ | |
Date today = new Date(); | |
- | |
+ | |
if (_eventPeriod.getStartDate().after(today) || _eventPeriod.isWithinRange(today)) | |
{ | |
Node first = doc.getDocumentElement().getFirstChild(); | |
@@ -162,31 +163,31 @@ public class LongTimeEvent extends Quest | |
int maxCount = Integer.parseInt(d.getAttributes().getNamedItem("max").getNodeValue()); | |
String chance = d.getAttributes().getNamedItem("chance").getNodeValue(); | |
int finalChance = 0; | |
- | |
+ | |
if (!chance.isEmpty() && chance.endsWith("%")) | |
{ | |
finalChance = Integer.parseInt(chance.substring(0, chance.length() - 1)) * 10000; | |
} | |
- | |
+ | |
if (ItemTable.getInstance().getTemplate(itemId) == null) | |
{ | |
_log.warning(getScriptName() + " event: " + itemId + " is wrong item id, item was not added in droplist"); | |
continue; | |
} | |
- | |
+ | |
if (minCount > maxCount) | |
{ | |
_log.warning(getScriptName() + " event: item " + itemId + " - min greater than max, item was not added in droplist"); | |
continue; | |
} | |
- | |
+ | |
if ((finalChance < 10000) || (finalChance > 1000000)) | |
{ | |
_log.warning(getScriptName() + " event: item " + itemId + " - incorrect drop chance, item was not added in droplist"); | |
continue; | |
} | |
- | |
- _dropList.add(new GeneralDropItem(itemId, minCount, maxCount, finalChance)); | |
+ | |
+ _dropList.add((GeneralDropItem) DropListScope.STATIC.newDropItem(itemId, minCount, maxCount, finalChance)); | |
} | |
catch (NumberFormatException nfe) | |
{ | |
@@ -209,13 +210,13 @@ public class LongTimeEvent extends Quest | |
int yPos = Integer.parseInt(d.getAttributes().getNamedItem("y").getNodeValue()); | |
int zPos = Integer.parseInt(d.getAttributes().getNamedItem("z").getNodeValue()); | |
int heading = d.getAttributes().getNamedItem("heading").getNodeValue() != null ? Integer.parseInt(d.getAttributes().getNamedItem("heading").getNodeValue()) : 0; | |
- | |
+ | |
if (NpcData.getInstance().getTemplate(npcId) == null) | |
{ | |
_log.warning(getScriptName() + " event: " + npcId + " is wrong NPC id, NPC was not added in spawnlist"); | |
continue; | |
} | |
- | |
+ | |
_spawnList.add(new NpcSpawn(npcId, new Location(xPos, yPos, zPos, heading))); | |
} | |
catch (NumberFormatException nfe) | |
@@ -256,7 +257,7 @@ public class LongTimeEvent extends Quest | |
_log.log(Level.WARNING, getScriptName() + " event: error reading " + configFile.getAbsolutePath() + " ! " + e.getMessage(), e); | |
} | |
} | |
- | |
+ | |
/** | |
* Maintenance event start - adds global drop, spawns event NPC's, shows start announcement. | |
*/ | |
@@ -270,7 +271,7 @@ public class LongTimeEvent extends Quest | |
EventDroplist.getInstance().addGlobalDrop(drop.getItemId(), drop.getMin(), drop.getMax(), (int) drop.getChance(), _dropPeriod); | |
} | |
} | |
- | |
+ | |
// Add spawns | |
Long millisToEventEnd = _eventPeriod.getEndDate().getTime() - System.currentTimeMillis(); | |
if (_spawnList != null) | |
@@ -280,17 +281,17 @@ public class LongTimeEvent extends Quest | |
addSpawn(spawn.npcId, spawn.loc.getX(), spawn.loc.getY(), spawn.loc.getZ(), spawn.loc.getHeading(), false, millisToEventEnd, false); | |
} | |
} | |
- | |
+ | |
// Send message on begin | |
Announcements.getInstance().announceToAll(_onEnterMsg); | |
- | |
+ | |
// Add announce for entering players | |
Announcements.getInstance().addEventAnnouncement(_eventPeriod, _onEnterMsg); | |
- | |
+ | |
// Schedule event end (now only for message sending) | |
ThreadPoolManager.getInstance().scheduleGeneral(new ScheduleEnd(), millisToEventEnd); | |
} | |
- | |
+ | |
/** | |
* @return event period | |
*/ | |
@@ -298,7 +299,7 @@ public class LongTimeEvent extends Quest | |
{ | |
return _eventPeriod; | |
} | |
- | |
+ | |
/** | |
* @return {@code true} if now is event period | |
*/ | |
@@ -306,7 +307,7 @@ public class LongTimeEvent extends Quest | |
{ | |
return _eventPeriod.isWithinRange(new Date()); | |
} | |
- | |
+ | |
/** | |
* @return {@code true} if now is drop period | |
*/ | |
@@ -314,7 +315,7 @@ public class LongTimeEvent extends Quest | |
{ | |
return _dropPeriod.isWithinRange(new Date()); | |
} | |
- | |
+ | |
protected class ScheduleStart implements Runnable | |
{ | |
@Override | |
@@ -323,7 +324,7 @@ public class LongTimeEvent extends Quest | |
startEvent(); | |
} | |
} | |
- | |
+ | |
protected class ScheduleEnd implements Runnable | |
{ | |
@Override | |
diff --git a/java/com/l2jserver/gameserver/model/events/AbstractScript.java b/java/com/l2jserver/gameserver/model/events/AbstractScript.java | |
index aebe92e..8191a1d 100644 | |
--- a/java/com/l2jserver/gameserver/model/events/AbstractScript.java | |
+++ b/java/com/l2jserver/gameserver/model/events/AbstractScript.java | |
@@ -24,8 +24,12 @@ 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.function.Consumer; | |
@@ -57,6 +61,9 @@ import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance; | |
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; | |
import com.l2jserver.gameserver.model.actor.instance.L2TrapInstance; | |
import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate; | |
+import com.l2jserver.gameserver.model.drops.GeneralDropItem; | |
+import com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem; | |
+import com.l2jserver.gameserver.model.drops.IDropItem; | |
import com.l2jserver.gameserver.model.entity.Castle; | |
import com.l2jserver.gameserver.model.entity.Fort; | |
import com.l2jserver.gameserver.model.entity.Instance; | |
@@ -128,12 +135,14 @@ import com.l2jserver.gameserver.network.serverpackets.SystemMessage; | |
import com.l2jserver.gameserver.scripting.ManagedScript; | |
import com.l2jserver.gameserver.util.MinionList; | |
import com.l2jserver.util.Rnd; | |
+import com.l2jserver.util.Util; | |
/** | |
* @author UnAfraid | |
*/ | |
public abstract class AbstractScript extends ManagedScript | |
{ | |
+ | |
protected static final Logger _log = Logger.getLogger(AbstractScript.class.getName()); | |
private final Map<ListenerRegisterType, Set<Integer>> _registeredIds = new ConcurrentHashMap<>(); | |
private final List<AbstractEventListener> _listeners = new FastList<AbstractEventListener>().shared(); | |
@@ -2193,6 +2202,496 @@ public abstract class AbstractScript extends ManagedScript | |
} | |
/** | |
+ * Gives an item to the player | |
+ * @param player | |
+ * @param item | |
+ * @param victim the character that "dropped" the item | |
+ * @return <code>true</code> if at least one item was given, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim) | |
+ { | |
+ List<ItemHolder> 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<ItemHolder> 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, ItemHolder item, long limit) | |
+ { | |
+ 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) | |
+ { | |
+ 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, List<ItemHolder> items, long limit) | |
+ { | |
+ boolean b = false; | |
+ for (ItemHolder item : items) | |
+ { | |
+ b |= giveItems(player, item, limit); | |
+ } | |
+ return b; | |
+ } | |
+ | |
+ protected static boolean giveItems(L2PcInstance player, List<ItemHolder> items, long limit, boolean playSound) | |
+ { | |
+ 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, List<ItemHolder> items, Map<Integer, Long> 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, List<ItemHolder> items, Function<Integer, Long> limit) | |
+ { | |
+ boolean b = false; | |
+ for (ItemHolder item : items) | |
+ { | |
+ if (limit != null) | |
+ { | |
+ 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<ItemHolder> items, Function<Integer, Long> limit, boolean playSound) | |
+ { | |
+ boolean drop = giveItems(player, items, limit); | |
+ if (drop && playSound) | |
+ { | |
+ playSound(player, QuestSound.ITEMSOUND_QUEST_ITEMGET); | |
+ } | |
+ return drop; | |
+ } | |
+ | |
+ protected static boolean giveItems(L2PcInstance player, List<ItemHolder> items, Map<Integer, Long> 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 <code>true</code> if at least one item was given to the player, <code>false</code> 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) | |
+ { | |
+ 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Map<Integer, Long> 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 <code>true</code> if at least one item was given to the player, <code>false</code> otherwise | |
+ */ | |
+ protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Function<Integer, Long> limit) | |
+ { | |
+ return giveItems(player, item.calculateDrops(victim, player), limit); | |
+ } | |
+ | |
+ protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Map<Integer, Long> limit, boolean playSound) | |
+ { | |
+ return giveItems(player, item, victim, Util.mapToFunction(limit), playSound); | |
+ } | |
+ | |
+ protected static boolean giveItems(L2PcInstance player, IDropItem item, L2Character victim, Function<Integer, Long> limit, boolean playSound) | |
+ { | |
+ 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, Collection<ItemHolder> items, Function<Integer, Long> limit, boolean playSound) | |
+ { | |
+ Map<L2PcInstance, Map<Integer, Long>> 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, Collection<ItemHolder> items, Map<Integer, Long> 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, Collection<ItemHolder> 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<L2PcInstance, Long> distributeItems(Collection<L2PcInstance> players, ItemHolder item, long limit, boolean playSound) | |
+ { | |
+ Map<L2PcInstance, Map<Integer, Long>> distribution = distributeItems(players, Collections.singletonList(item), limit, playSound); | |
+ Map<L2PcInstance, Long> returnMap = new HashMap<>(); | |
+ for (Entry<L2PcInstance, Map<Integer, Long>> entry : distribution.entrySet()) | |
+ { | |
+ for (Entry<Integer, Long> 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, IDropItem items, L2Character killer, L2Character victim, Function<Integer, 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 | |
+ * @return the counts of each items given to each player | |
+ */ | |
+ protected static Map<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, IDropItem items, L2Character killer, L2Character victim, Map<Integer, 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 | |
+ * @return the counts of each items given to each player | |
+ */ | |
+ protected static Map<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, final GroupedGeneralDropItem items, L2Character killer, L2Character victim, Function<Integer, Long> limit, boolean playSound, boolean smartDrop) | |
+ { | |
+ GroupedGeneralDropItem toDrop; | |
+ if (smartDrop) | |
+ { | |
+ toDrop = new GroupedGeneralDropItem(items.getChance(), items.getDropCalculationStrategy(), items.getKillerChanceModifierStrategy(), items.getPreciseStrategy()); | |
+ List<GeneralDropItem> dropItems = new LinkedList<>(items.getItems()); | |
+ itemLoop: for (Iterator<GeneralDropItem> it = dropItems.iterator(); it.hasNext();) | |
+ { | |
+ GeneralDropItem item = it.next(); | |
+ for (L2PcInstance player : players) | |
+ { | |
+ int itemId = item.getItemId(); | |
+ if (player.getInventory().getInventoryItemCount(itemId, -1, true) < avoidNull(limit, itemId)) | |
+ { | |
+ // we can give this item to this player | |
+ continue itemLoop; | |
+ } | |
+ } | |
+ // 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, final GroupedGeneralDropItem items, L2Character killer, L2Character victim, Map<Integer, Long> 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<L2PcInstance, Map<Integer, Long>> distributeItems(Collection<L2PcInstance> players, final 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<L2PcInstance, Map<Integer, Long>> calculateDistribution(Collection<L2PcInstance> players, Collection<ItemHolder> items, Function<Integer, Long> limit) | |
+ { | |
+ Map<L2PcInstance, Map<Integer, Long>> rewardedCounts = new HashMap<>(); | |
+ for (L2PcInstance player : players) | |
+ { | |
+ rewardedCounts.put(player, new HashMap<Integer, Long>()); | |
+ } | |
+ for (ItemHolder item : items) | |
+ { | |
+ long equaldist = item.getCount() / players.size(); | |
+ long randomdist = item.getCount() % players.size(); | |
+ List<L2PcInstance> 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<L2PcInstance> it = toDist.iterator(); it.hasNext();) | |
+ { | |
+ L2PcInstance player = it.next(); | |
+ if (!rewardedCounts.get(player).containsKey(item.getId())) | |
+ { | |
+ rewardedCounts.get(player).put(item.getId(), 0L); | |
+ } | |
+ 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); | |
+ } | |
+ 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 | |
+ break; | |
+ } | |
+ L2PcInstance player = toDist.get(getRandom(toDist.size())); | |
+ // avoid null return | |
+ 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 <T> 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 <T> long avoidNull(Function<T, Long> function, T arg) | |
+ { | |
+ 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<player Map<itemId, count>>) | |
+ * @param playSound if to play sound if a player gets at least one item | |
+ */ | |
+ private static void giveItems(Map<L2PcInstance, Map<Integer, Long>> rewardedCounts, boolean playSound) | |
+ { | |
+ for (Entry<L2PcInstance, Map<Integer, Long>> entry : rewardedCounts.entrySet()) | |
+ { | |
+ L2PcInstance player = entry.getKey(); | |
+ boolean playPlayerSound = false; | |
+ for (Entry<Integer, Long> 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 | |
* @param itemId the ID of the item to take | |
diff --git a/java/com/l2jserver/gameserver/model/quest/Quest.java b/java/com/l2jserver/gameserver/model/quest/Quest.java | |
index 284f3e4..8981721 100644 | |
--- a/java/com/l2jserver/gameserver/model/quest/Quest.java | |
+++ b/java/com/l2jserver/gameserver/model/quest/Quest.java | |
@@ -1,18 +1,18 @@ | |
/* | |
* Copyright (C) 2004-2014 L2J Server | |
- * | |
+ * | |
* This file is part of L2J Server. | |
- * | |
+ * | |
* L2J Server 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. | |
- * | |
+ * | |
* L2J Server 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 <http://www.gnu.org/licenses/>. | |
*/ | |
diff --git a/java/com/l2jserver/util/Util.java b/java/com/l2jserver/util/Util.java | |
index 5993703..f3fcd81 100644 | |
--- a/java/com/l2jserver/util/Util.java | |
+++ b/java/com/l2jserver/util/Util.java | |
@@ -31,6 +31,8 @@ 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,4 +225,16 @@ public final class Util | |
.orElse(dateNowWithDifferentTime.with(TemporalAdjusters.next(daysOfWeek.get(0)))); | |
// @formatter:on | |
} | |
+ | |
+ /** | |
+ * This method translates map to function | |
+ * @param <K> key type of the map and argument of the function | |
+ * @param <V> 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 <K, V> Function<K, V> mapToFunction(Map<K, V> map) | |
+ { | |
+ return key -> map.get(key); | |
+ } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment