123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- /*
- * Copyright © 2004-2021 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.commons.util.Rnd;
- 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 org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import static com.l2jserver.gameserver.config.Configuration.general;
- /**
- * @author Battlecruiser
- */
- public interface IGroupedItemDropCalculationStrategy {
- Logger LOG = LoggerFactory.getLogger(IGroupedItemDropCalculationStrategy.class);
- /**
- * The default strategy used in L2J to calculate drops. When the group's chance raises over 100% and group has precise calculation, the dropped item's amount increases.
- */
- IGroupedItemDropCalculationStrategy DEFAULT_STRATEGY = new IGroupedItemDropCalculationStrategy() {
- private final Map<GroupedGeneralDropItem, GeneralDropItem> singleItemCache = new ConcurrentHashMap<>();
-
- private GeneralDropItem getSingleItem(GroupedGeneralDropItem dropItem) {
- final GeneralDropItem item1 = dropItem.getItems().iterator().next();
- singleItemCache.putIfAbsent(dropItem, new GeneralDropItem(item1.getItemId(), item1.getMin(), item1.getMax(), (item1.getChance() * dropItem.getChance()) / 100, //
- item1.getAmountStrategy(), item1.getChanceStrategy(), dropItem.getPreciseStrategy(), dropItem.getKillerChanceModifierStrategy(), item1.getDropCalculationStrategy()));
- return singleItemCache.get(dropItem);
- }
-
- @Override
- public List<ItemHolder> calculateDrops(GroupedGeneralDropItem dropItem, L2Character victim, L2Character killer) {
- if (dropItem.getItems().size() == 1) {
- return getSingleItem(dropItem).calculateDrops(victim, killer);
- }
-
- GroupedGeneralDropItem normalized = dropItem.normalizeMe(victim, killer);
- if (normalized.getChance() > (Rnd.nextDouble() * 100)) {
- final double random = (Rnd.nextDouble() * 100);
- double totalChance = 0;
- for (GeneralDropItem item2 : normalized.getItems()) {
- // Grouped item chance rates should not be modified (the whole magic was already done by normalizing thus the items' chance sum is always 100%).
- totalChance += item2.getChance();
- if (totalChance > random) {
- int amountMultiply = 1;
- if (dropItem.isPreciseCalculated() && (normalized.getChance() >= 100)) {
- amountMultiply = (int) (normalized.getChance()) / 100;
- if ((normalized.getChance() % 100) > (Rnd.nextDouble() * 100)) {
- amountMultiply++;
- }
- }
-
- return Collections.singletonList(new ItemHolder(item2.getItemId(), Rnd.get(item2.getMin(victim), item2.getMax(victim)) * amountMultiply));
- }
- }
- }
- return null;
- }
- };
-
- /**
- * This strategy calculates a group's drop by calculating drops of its individual items and merging its results.
- */
- IGroupedItemDropCalculationStrategy DISBAND_GROUP = (item, victim, killer) -> {
- 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.
- */
- 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<>(rolls);
- for (int i = 0; i < rolls; i++) {
- // As further normalizing on already normalized drop group does nothing, we can just pass the calculation to DEFAULT_STRATEGY with precise calculation disabled as we handle it.
- List<ItemHolder> drops = normalized.calculateDrops(victim, killer);
- if (drops != null) {
- dropped.addAll(drops);
- }
- }
- if (general().preciseDropMultipleRollsAggregateDrops()) {
- Map<Integer, Long> countByItemId = new HashMap<>();
- for (ItemHolder drop : dropped) {
- Long currentCount = countByItemId.getOrDefault(drop.getId(), 0L);
- countByItemId.put(drop.getId(), currentCount + drop.getCount());
- }
- dropped.clear();
- for (Map.Entry<Integer, Long> entry : countByItemId.entrySet()) {
- dropped.add(new ItemHolder(entry.getKey(), entry.getValue()));
- }
- }
- return dropped.isEmpty() ? null : dropped;
- };
-
- List<ItemHolder> calculateDrops(GroupedGeneralDropItem item, L2Character victim, L2Character killer);
- }
|