Package l2p.gameserver.model

Source Code of l2p.gameserver.model.L2DropGroup

package l2p.gameserver.model;

import java.util.AbstractMap.SimpleEntry;
import java.util.Collection;
import java.util.Map.Entry;

import l2p.Config;
import l2p.gameserver.model.base.Experience;
import l2p.gameserver.model.base.ItemToDrop;
import l2p.gameserver.model.instances.L2MonsterInstance;
import l2p.gameserver.model.instances.L2ReflectionBossInstance;
import l2p.util.GArray;
import l2p.util.Rnd;

public class L2DropGroup implements Cloneable
{
  private int _id;
  private double _chance;
  private boolean _isAdena = false; // Шанс фиксирован, растет только количество
  private boolean _fixedQty = false; // Вместо увеличения количества используется увеличение количества роллов группы
  private boolean _notRate = false; // Рейты вообще не применяются
  private GArray<L2DropData> _items = new GArray<L2DropData>();

  public L2DropGroup(int id)
  {
    _id = id;
  }

  public int getId()
  {
    return _id;
  }

  public boolean fixedQty()
  {
    return _fixedQty;
  }

  public boolean notRate()
  {
    return _notRate;
  }

  public void addDropItem(L2DropData item)
  {
    if(item.getItem().isAdena())
    {
      _isAdena = true;
    }
    if(item.getItem().isRaidAccessory() || item.getItem().isArrow() || item.getItem().isHerb())
    {
      _notRate = true;
    }
    if(item.getItem().isEquipment() || item.getItem().isKeyMatherial())
    {
      _fixedQty = true;
    }
    item.setChanceInGroup(_chance);
    _chance += item.getChance();
    _items.add(item);
  }

  /**
   * Возвращает список вещей или копию списка
   */
  public GArray<L2DropData> getDropItems(boolean copy)
  {
    if(!copy)
    {
      return _items;
    }
    GArray<L2DropData> temp = new GArray<L2DropData>();
    temp.addAll(_items);
    return temp;
  }

  /**
   * Возвращает полностью независимую копию группы
   */
  @Override
  public L2DropGroup clone()
  {
    L2DropGroup ret = new L2DropGroup(_id);
    for(L2DropData i : _items)
    {
      ret.addDropItem(i.clone());
    }
    return ret;
  }

  /**
   * Возвращает оригинальный список вещей если рейты не нужны или клон с примененными рейтами
   */
  public GArray<L2DropData> getRatedItems(double mod)
  {
    if(mod == 1 || _notRate)
    {
      return _items;
    }
    GArray<L2DropData> ret = new GArray<L2DropData>();
    for(L2DropData i : _items)
    {
      ret.add(i.clone());
    } // создаем копию группы
    double perItemChance = 1000000. / ret.size();
    double gChance = 0;
    for(L2DropData i : ret)
    {
      double avgQty = (i.getMinDrop() + i.getMaxDrop()) / 2.; // среднее количество дропа
      double newChance = mod * i.getChance() * avgQty; // новый шанс группы плюс количество дропа, например 1-4 с шансом 43% при рейте 3х дадут ((1+4)/2)*0.43*3=3.225
      long avgCount = (long) Math.ceil(newChance / perItemChance); // новое количество дропа, допустим при количестве групп 3 пример выше даст 3.225/(1/3)=ceil(9.675)=10
      long min = avgCount, max = avgCount; // создаем некоторый разброс количества
      long shift = Math.min(Math.round(avgCount * 1. / 3.), avgCount - 1);
      if(shift > 0)
      {
        min -= shift;
        max += shift;
      }
      i.setMinDrop(min);
      i.setMaxDrop(max);
      i.setChance(newChance / avgCount); // новый шанс считается как полный новый шанс деленный на среднее количество, для примера выше 32.25%
      i.setChanceInGroup(gChance);
      gChance += i.getChance();
    }
    return ret;
  }

  /**
   * Эта функция выбирает одну вещь из группы
   * Используется в основном механизме расчета дропа
   */
  public Collection<ItemToDrop> roll(int diff, boolean isSpoil, L2MonsterInstance monster, L2Player player, double mod)
  {
    if(_isAdena)
    {
      return rollAdena(diff, player, mod);
    }
    if(isSpoil)
    {
      return rollSpoil(diff, player, mod);
    }
    if(monster.isRaid() || _notRate || _fixedQty)
    {
      return rollFixedQty(diff, monster, player, mod);
    }
    // если множитель дропа большой разбивать дроп на кучки
    // количество итераций не более L2Drop.MAX_DROP_ITERATIONS
    double cmod = mod * ((monster.isRaid() || monster instanceof L2ReflectionBossInstance) ? Config.RATE_DROP_RAIDBOSS : Config.RATE_DROP_ITEMS * player.getRateItems());
    if(cmod > Config.RATE_BREAKPOINT)
    {
      long iters = Math.min((long) Math.ceil(cmod / Config.RATE_BREAKPOINT), Config.MAX_DROP_ITERATIONS);
      GArray<ItemToDrop> ret = new GArray<ItemToDrop>();
      for(int i = 0; i < iters; i++)
      {
        ret.addAll(rollNormal(diff, monster, player, mod / iters));
      }
      return ret;
    }
    return rollNormal(diff, monster, player, mod);
  }

  public Collection<ItemToDrop> rollNormal(int diff, L2MonsterInstance monster, L2Player player, double mod)
  {
    // Поправка на глубоко синих мобов
    if(Config.DEEPBLUE_DROP_RULES && diff > 0)
    {
      mod *= Experience.penaltyModifier(diff, 9);
    }
    if(mod <= 0)
    {
      return null;
    }
    float rate;
    if(monster.isRaid() || monster instanceof L2ReflectionBossInstance)
    {
      rate = Config.RATE_DROP_RAIDBOSS * player.getRateItems();
    }
    else
    {
      rate = Config.RATE_DROP_ITEMS * player.getRateItems();
    }
    double calcChance = 0;
    double rollChance;
    GArray<L2DropData> items;
    double mult = 1;
    items = getRatedItems(rate * mod);
    // Считаем шанс группы
    for(L2DropData i : items)
    {
      calcChance += i.getChance();
    }
    rollChance = calcChance;
    if(Rnd.get(1, L2Drop.MAX_CHANCE) > calcChance)
    {
      return null;
    }
    GArray<ItemToDrop> ret = new GArray<ItemToDrop>();
    rollFinal(items, ret, mult, rollChance);
    return ret;
  }

  public Collection<ItemToDrop> rollFixedQty(int diff, L2MonsterInstance monster, L2Player player, double mod)
  {
    // Поправка на глубоко синих мобов
    if(Config.DEEPBLUE_DROP_RULES && diff > 0)
    {
      mod *= Experience.penaltyModifier(diff, 9);
    }
    if(mod <= 0)
    {
      return null;
    }
    double rate;
    if(_notRate)
    {
      rate = Math.min(mod, 1);
    }
    else if(monster.isRaid() || monster instanceof L2ReflectionBossInstance)
    {
      rate = Config.RATE_DROP_RAIDBOSS * mod;
    }
    else
    {
      rate = Config.RATE_DROP_ITEMS * player.getRateItems() * mod;
    }
    // Считаем шанс группы
    double calcChance = _chance * rate;
    Entry<Double, Integer> e = balanceChanceAndMult(calcChance);
    calcChance = e.getKey();
    int dropmult = e.getValue();
    GArray<ItemToDrop> ret = new GArray<ItemToDrop>();
    for(int n = 0; n < dropmult; n++)
    {
      if(Rnd.get(1, L2Drop.MAX_CHANCE) < calcChance)
      {
        rollFinal(_items, ret, 1, _chance);
      }
    }
    return ret;
  }

  private Collection<ItemToDrop> rollSpoil(int diff, L2Player player, double mod)
  {
    float rate = Config.RATE_DROP_SPOIL * player.getRateSpoil();
    // Поправка на глубоко синих мобов
    if(Config.DEEPBLUE_DROP_RULES && diff > 0)
    {
      mod *= Experience.penaltyModifier(diff, 9);
    }
    if(mod <= 0)
    {
      return null;
    }
    // Считаем шанс группы
    double calcChance = _chance * rate * mod;
    Entry<Double, Integer> e = balanceChanceAndMult(calcChance);
    calcChance = e.getKey();
    int dropmult = e.getValue();
    if(Rnd.get(1, L2Drop.MAX_CHANCE) > calcChance)
    {
      return null;
    }
    GArray<ItemToDrop> ret = new GArray<ItemToDrop>(1);
    rollFinal(_items, ret, dropmult, _chance);
    return ret;
  }

  private Collection<ItemToDrop> rollAdena(int diff, L2Player player, double mod)
  {
    float rate = Config.getRateAdena(player);
    if(Config.DEEPBLUE_DROP_RULES && diff > 0)
    {
      mod *= Experience.penaltyModifier(diff, 9);
    }
    double chance = _chance;
    if(mod > 10)
    {
      mod *= _chance / L2Drop.MAX_CHANCE;
      chance = L2Drop.MAX_CHANCE;
    }
    if(mod <= 0 || Rnd.get(1, L2Drop.MAX_CHANCE) > chance)
    {
      return null;
    }
    double mult = rate * mod;
    GArray<ItemToDrop> ret = new GArray<ItemToDrop>(1);
    rollFinal(_items, ret, mult, _chance);
    for(ItemToDrop i : ret)
    {
      i.isAdena = true;
    }
    return ret;
  }

  public static Entry<Double, Integer> balanceChanceAndMult(Double calcChance)
  {
    Integer dropmult = 1;
    if(calcChance > L2Drop.MAX_CHANCE)
    {
      if(calcChance % L2Drop.MAX_CHANCE == 0) // если кратен 100% то тупо умножаем количество
      {
        dropmult = (int) (calcChance / L2Drop.MAX_CHANCE);
      }
      else
      // иначе балансируем
      {
        dropmult = (int) Math.ceil(calcChance / L2Drop.MAX_CHANCE);
      } // множитель равен шанс / 100% округление вверх
      calcChance = calcChance / dropmult; // шанс равен шанс / множитель
      // в результате получаем увеличение количества и уменьшение шанса, при этом шанс не падает ниже 50%
    }
    return new SimpleEntry<Double, Integer>(calcChance, dropmult);
  }

  private void rollFinal(GArray<L2DropData> items, GArray<ItemToDrop> ret, double mult, double chanceSum)
  {
    // перебираем все вещи в группе и проверяем шанс
    int chance = Rnd.get(0, (int) chanceSum);
    for(L2DropData i : items)
    {
      if(chance < i.getChanceInGroup())
      {
        continue;
      }
      boolean notlast = false;
      for(L2DropData t : items)
      {
        if(t.getChanceInGroup() > i.getChanceInGroup() && chance > t.getChanceInGroup())
        {
          notlast = true;
          break;
        }
      }
      if(notlast)
      {
        continue;
      }
      ItemToDrop t = new ItemToDrop(i.getItemId());
      if(i.getMinDrop() >= i.getMaxDrop())
      {
        t.count = (int) Math.round(i.getMinDrop() * mult);
      }
      else
      {
        t.count = Rnd.get((int) Math.round(i.getMinDrop() * mult), (int) Math.round(i.getMaxDrop() * mult));
      }
      ret.add(t);
      break;
    }
  }

  public double getChance()
  {
    return _chance;
  }

  public void setChance(double chance)
  {
    _chance = chance;
  }

  public boolean isAdena()
  {
    return _isAdena;
  }
}
TOP

Related Classes of l2p.gameserver.model.L2DropGroup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.