Package l2p.gameserver.model.quest

Source Code of l2p.gameserver.model.quest.QuestState

package l2p.gameserver.model.quest;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import javolution.util.FastMap;
import l2p.Config;
import l2p.gameserver.model.L2Object;
import l2p.gameserver.model.L2ObjectsStorage;
import l2p.gameserver.model.L2Party;
import l2p.gameserver.model.L2Playable;
import l2p.gameserver.model.L2Player;
import l2p.gameserver.model.L2Spawn;
import l2p.gameserver.model.instances.L2NpcInstance;
import l2p.gameserver.model.items.L2ItemInstance;
import l2p.gameserver.serverpackets.ExShowQuestMark;
import l2p.gameserver.serverpackets.PlaySound;
import l2p.gameserver.serverpackets.QuestList;
import l2p.gameserver.serverpackets.StatusUpdate;
import l2p.gameserver.serverpackets.SystemMessage;
import l2p.gameserver.serverpackets.TutorialEnableClientEvent;
import l2p.gameserver.serverpackets.TutorialShowHtml;
import l2p.gameserver.serverpackets.TutorialShowQuestionMark;
import l2p.gameserver.tables.ItemTable;
import l2p.gameserver.tables.SpawnTable;
import l2p.gameserver.templates.L2Item;
import l2p.util.Files;
import l2p.util.GArray;
import l2p.util.Log;
import l2p.util.Rnd;

public final class QuestState
{
  protected static Logger _log = Logger.getLogger(Quest.class.getName());
  private long ownerStoreId = 0;
  /**
   * Quest associated to the QuestState
   */
  private Quest _quest;
  /**
   * State of the quest
   */
  private int _state;
  /**
   * List of couples (variable for quest,value of the variable for quest)
   */
  private ConcurrentHashMap<String, String> _vars;

  /**
   * Constructor<?> of the QuestState : save the quest in the list of quests of the player.<BR/><BR/>
   * <p/>
   * <U><I>Actions :</U></I><BR/>
   * <LI>Save informations in the object QuestState created (Quest, Player, Completion, State)</LI>
   * <LI>Add the QuestState in the player's list of quests by using setQuestState()</LI>
   * <LI>Add drops gotten by the quest</LI>
   * <BR/>
   *
   * @param quest  : quest associated with the QuestState
   * @param player : L2Player pointing out the player
   * @param state  : state of the quest
   */
  public QuestState(Quest quest, L2Player player, int state)
  {
    _quest = quest;
    ownerStoreId = player.getStoredId();
    // Save the state of the quest for the player in the player's list of quest onwed
    player.setQuestState(this);
    // set the state of the quest
    _state = state;
    quest.notifyPlayerEnter(this);
  }

  /**
   * Add XP and SP as quest reward
   * <br><br>
   * Метод учитывает рейты!
   */
  public void addExpAndSp(long exp, long sp)
  {
    addExpAndSp(exp, sp, false);
  }

  /**
   * Add XP and SP as quest reward
   * <br><br>
   * Метод учитывает рейты!
   * 3-ий параметр true/false показывает является ли квест на профессию
   * и рейты учитываются в завимисомти от параметра RateQuestsRewardOccupationChange
   */
  public void addExpAndSp(long exp, long sp, boolean prof)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return;
    }
    if(!prof || prof && Config.RATE_QUESTS_OCCUPATION_CHANGE)
    {
      player.addExpAndSp((long) (exp * getRateQuestsReward()), (long) (sp * getRateQuestsReward()), false, false);
    }
    else
    {
      player.addExpAndSp(exp, sp, false, false);
    }
  }

  /**
   * Add player to get notification of characters death
   *
   * @param character : L2Character of the character to get notification of death
   */
  public void addNotifyOfDeath(L2Playable playable)
  {
    if(playable != null)
    {
      playable.addNotifyQuestOfDeath(this);
    }
  }

  public void addNotifyOfPlayerKill()
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.addNotifyOfPlayerKill(this);
    }
  }

  public void removeNotifyOfPlayerKill()
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.removeNotifyOfPlayerKill(this);
    }
  }

  public void addRadar(int x, int y, int z)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.radar.addMarker(x, y, z);
    }
  }

  public void clearRadar()
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.radar.removeAllMarkers();
    }
  }

  /**
   * Destroy element used by quest when quest is exited
   *
   * @param repeatable
   * @return QuestState
   */
  public QuestState exitCurrentQuest(boolean repeatable)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return this;
    }
    // Clean drops
    if(_quest.getItems() != null)
    // Go through values of class variable "drops" pointing out mobs that drop for quest
    {
      for(Integer itemId : _quest.getItems())
      {
        // Get [item from] / [presence of the item in] the inventory of the player
        L2ItemInstance item = player.getInventory().getItemByItemId(itemId);
        if(item == null || itemId == 57)
        {
          continue;
        }
        long count = item.getCount();
        // If player has the item in inventory, destroy it (if not gold)
        player.getInventory().destroyItemByItemId(itemId, count, true);
        player.getWarehouse().destroyItem(itemId, count);
      }
    }
    // If quest is repeatable, delete quest from list of quest of the player and from database (quest CAN be created again => repeatable)
    if(repeatable)
    {
      player.delQuestState(_quest.getName());
      Quest.deleteQuestInDb(this);
      _vars = null;
    }
    else
    { // Otherwise, delete variables for quest and update database (quest CANNOT be created again => not repeatable)
      if(_vars != null && !_vars.isEmpty())
      {
        for(String var : _vars.keySet())
        {
          if(var != null)
          {
            unset(var);
          }
        }
      }
      setState(Quest.COMPLETED);
      Quest.updateQuestInDb(this); // FIXME: оно вроде не нужно?
    }
    player.sendPacket(new QuestList(player));
    return this;
  }

  public void abortQuest()
  {
    _quest.onAbort(this);
    exitCurrentQuest(true);
  }

  /**
   * <font color=red>Не использовать для получения кондов!</font><br><br>
   * <p/>
   * Return the value of the variable of quest represented by "var"
   *
   * @param var : name of the variable of quest
   * @return Object
   */
  public String get(String var)
  {
    if(_vars == null)
    {
      return null;
    }
    return _vars.get(var);
  }

  public ConcurrentHashMap<String, String> getVars()
  {
    ConcurrentHashMap<String, String> result = new ConcurrentHashMap<String, String>();
    if(_vars != null)
    {
      result.putAll(_vars);
    }
    return result;
  }

  /**
   * Возвращает переменную в виде целого числа. Для кондов вызывает getCond.
   *
   * @param var : String designating the variable for the quest
   * @return int
   */
  public int getInt(String var)
  {
    if(var.equalsIgnoreCase("cond"))
    {
      return getCond();
    }
    return getRawInt(var);
  }

  /**
   * Возвращает переменную в виде целого числа.
   *
   * @param var : String designating the variable for the quest
   * @return int
   */
  public int getRawInt(String var)
  {
    int varint = 0;
    try
    {
      String val = get(var);
      if(val == null)
      {
        return 0;
      }
      varint = Integer.parseInt(val);
    }
    catch(Exception e)
    {
      _log.finer(getPlayer().getName() + ": variable " + var + " isn't an integer: " + varint + e);
      e.printStackTrace();
    }
    return varint;
  }

  /**
   * Return item number which is equipped in selected slot
   *
   * @return int
   */
  public int getItemEquipped(int loc)
  {
    return getPlayer().getInventory().getPaperdollItemId(loc);
  }

  /**
   * @return L2Player
   */
  public L2Player getPlayer()
  {
    return L2ObjectsStorage.getAsPlayer(ownerStoreId);
  }

  /**
   * Return the quest
   *
   * @return Quest
   */
  public Quest getQuest()
  {
    return _quest;
  }

  public boolean checkQuestItemsCount(int... itemIds)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return false;
    }
    for(int itemId : itemIds)
    {
      if(player.getInventory().getCountOf(itemId) <= 0)
      {
        return false;
      }
    }
    return true;
  }

  public long getSumQuestItemsCount(int... itemIds)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return 0;
    }
    long count = 0;
    for(int itemId : itemIds)
    {
      count += player.getInventory().getCountOf(itemId);
    }
    return count;
  }

  /**
   * Return the quantity of one sort of item hold by the player
   *
   * @param itemId : ID of the item wanted to be count
   * @return int
   */
  public long getQuestItemsCount(int itemId)
  {
    L2Player player = getPlayer();
    return player == null ? 0 : player.getInventory().getCountOf(itemId);
  }

  public long getQuestItemsCount(int... itemsIds)
  {
    long result = 0;
    for(int id : itemsIds)
    {
      result += getQuestItemsCount(id);
    }
    return result;
  }

  /**
   * Return the QuestTimer object with the specified name
   *
   * @return QuestTimer<BR> Return null if name does not exist
   */
  public final QuestTimer getQuestTimer(String name)
  {
    return Quest.getQuestTimer(getQuest(), name, getPlayer());
  }

  public int getState()
  {
    return _state;
  }

  public String getStateName()
  {
    return Quest.getStateName(_state);
  }

  /**
   * Добавить предмет игроку
   * By default if item is adena rates 'll be applyed, else no
   *
   * @param itemId
   * @param count
   */
  public L2ItemInstance giveItems(int itemId, long count)
  {
    if(itemId == 57)
    {
      return giveItems(itemId, count, 0, true);
    }
    else
    {
      return giveItems(itemId, count, 0, false);
    }
  }

  /**
   * Добавить предмет игроку
   *
   * @param itemId
   * @param count
   * @param rate   - учет квестовых рейтов
   */
  public L2ItemInstance giveItems(int itemId, long count, boolean rate)
  {
    return giveItems(itemId, count, 0, rate);
  }

  /**
   * Добавить предмет игроку
   *
   * @param itemId
   * @param count
   * @param enchantlevel
   * @param rate   - учет квестовых рейтов
   */
  public L2ItemInstance giveItems(int itemId, long count, int enchantlevel, boolean rate)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return null;
    }
    if(count <= 0)
    {
      count = 1;
    }
    if (Config.QUEST_DROP_MOD.containsKey(getQuest().getQuestIntId()))
    {
      FastMap<Integer, Integer> items = Config.QUEST_DROP_MOD.get(getQuest().getQuestIntId());
      if (items.containsKey(itemId))
      {
        count *= items.get(itemId);
        rate = false;       
      }
    }
    if(rate)
    {
      if(itemId == 57)
      {
        count = (long) (count * (getRateQuestsReward() * Config.RATE_DROP_ADENA_MULT_MOD + Config.RATE_DROP_ADENA_STATIC_MOD));
      }
      else
      {
        count = (long) (count * getRateQuestsReward());
      }
    }
    if(itemId == 57)
    {
      Log.add("Quest|" + getQuest().getQuestIntId() + "|" + count + "|" + player.getName(), "adena");
    }
    // Get template of item
    L2Item template = ItemTable.getInstance().getTemplate(itemId);
    if(template == null)
    {
      return null;
    }
    L2ItemInstance ret = null;
    if(template.isStackable())
    {
      L2ItemInstance item = ItemTable.getInstance().createItem(itemId);
      // Set quantity of item
      item.setCount(count);
      // Add items to player's inventory
      ret = player.getInventory().addItem(item);
      if(enchantlevel > 0)
      {
        item.setEnchantLevel(enchantlevel);
      }
      Log.LogItem(player, Log.GetQuestItem, item);
    }
    else
    {
      for(int i = 0; i < count; i++)
      {
        L2ItemInstance item = ItemTable.getInstance().createItem(itemId);
        // Add items to player's inventory
        ret = player.getInventory().addItem(item);
        if(enchantlevel > 0)
        {
          item.setEnchantLevel(enchantlevel);
        }
        Log.LogItem(player, Log.GetQuestItem, item);
      }
    }
    player.sendPacket(SystemMessage.obtainItems(template.getItemId(), count, 0));
    player.sendStatusUpdate(false, StatusUpdate.CUR_LOAD);
    return ret;
  }

  public void giveItems(int itemId, long count, byte attributeId, int attributeLevel)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return;
    }
    if(count <= 0)
    {
      count = 1;
    }
    // Get template of item
    L2Item template = ItemTable.getInstance().getTemplate(itemId);
    if(template == null)
    {
      return;
    }
    for(int i = 0; i < count; i++)
    {
      L2ItemInstance item = ItemTable.getInstance().createItem(itemId);
      if(attributeId >= 0 && attributeLevel > 0)
      {
        item.setAttributeElement(attributeId, attributeLevel, true);
      }
      // Add items to player's inventory
      player.getInventory().addItem(item);
      Log.LogItem(player, Log.GetQuestItem, item);
    }
    player.sendPacket(SystemMessage.obtainItems(template.getItemId(), count, 0));
    player.sendStatusUpdate(false, StatusUpdate.CUR_LOAD);
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param count      количество при рейтах 1х
   * @param calcChance шанс при рейтах 1х, в процентах
   * @return количество вещей для дропа, может быть 0
   */
  public int rollDrop(int count, double calcChance, boolean prof)
  {
    if(calcChance <= 0 || count <= 0)
    {
      return 0;
    }
    return rollDrop(count, count, calcChance, prof);
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param min  минимальное количество при рейтах 1х
   * @param max  максимальное количество при рейтах 1х
   * @param calcChance шанс при рейтах 1х, в процентах
   * @param prof       - учитывать дроп по параметру "рейт дропа для квестов на профу"
   * @return количество вещей для дропа, может быть 0
   */
  public int rollDrop(int min, int max, double calcChance, boolean prof)
  {
    if(calcChance <= 0 || min <= 0 || max <= 0)
    {
      return 0;
    }
    int dropmult = 1;
    calcChance *= getRateQuestsDrop(prof);
    if(getQuest().getParty() > Quest.PARTY_NONE)
    {
      L2Player player = getPlayer();
      if(player.getParty() != null)
      {
        calcChance *= Config.ALT_PARTY_BONUS[player.getParty().getMemberCountInRange(player, Config.ALT_PARTY_DISTRIBUTION_RANGE) - 1];
      }
    }
    if(calcChance > 100)
    {
      if((int) Math.ceil(calcChance / 100) <= calcChance / 100)
      {
        calcChance = Math.nextUp(calcChance);
      }
      dropmult = (int) Math.ceil(calcChance / 100);
      calcChance = calcChance / dropmult;
    }
    return Rnd.chance(calcChance) ? Rnd.get(min * dropmult, max * dropmult) : 0;
  }

  public float getRateQuestsDrop(boolean prof)
  {
    L2Player player = getPlayer();
    float Bonus = player == null ? 1 : player.getBonus().RATE_QUESTS_DROP;
    return (prof ? Config.RATE_QUESTS_DROP_PROF : Config.RATE_QUESTS_DROP) * Bonus;
  }

  public float getRateQuestsReward()
  {
    L2Player player = getPlayer();
    float Bonus = player == null ? 1 : player.getBonus().RATE_QUESTS_REWARD;
    return Config.RATE_QUESTS_REWARD * Bonus;
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * проверяет максимум, а так же проигрывает звук получения вещи.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param min  минимальное количество при рейтах 1х
   * @param max  максимальное количество при рейтах 1х
   * @param limit      максимум таких вещей
   * @param calcChance
   * @return true если после выполнения количество достигло лимита
   */
  public boolean rollAndGive(int itemId, int min, int max, int limit, double calcChance)
  {
    if(calcChance <= 0 || min <= 0 || max <= 0 || limit <= 0 || itemId <= 0)
    {
      return false;
    }
    return rollAndGive(itemId, min, max, limit, calcChance, false);
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * проверяет максимум, а так же проигрывает звук получения вещи.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param min  минимальное количество при рейтах 1х
   * @param max  максимальное количество при рейтах 1х
   * @param limit      максимум таких вещей
   * @param calcChance
   * @param QuestProf
   * @return true если после выполнения количество достигло лимита
   */
  public boolean rollAndGive(int itemId, int min, int max, int limit, double calcChance, boolean prof)
  {
    if(calcChance <= 0 || min <= 0 || max <= 0 || limit <= 0 || itemId <= 0)
    {
      return false;
    }
    long count = rollDrop(min, max, calcChance, prof);
    if(count > 0)
    {
      long alreadyCount = getQuestItemsCount(itemId);
      if(alreadyCount + count > limit)
      {
        count = limit - alreadyCount;
      }
      if(count > 0)
      {
        giveItems(itemId, count, false);
        if(count + alreadyCount < limit)
        {
          playSound(Quest.SOUND_ITEMGET);
        }
        else
        {
          playSound(Quest.SOUND_MIDDLE);
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * а так же проигрывает звук получения вещи.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param min  минимальное количество при рейтах 1х
   * @param max  максимальное количество при рейтах 1х
   * @param calcChance
   */
  public void rollAndGive(int itemId, int min, int max, double calcChance)
  {
    if(calcChance <= 0 || min <= 0 || max <= 0 || itemId <= 0)
    {
      return;
    }
    rollAndGive(itemId, min, max, calcChance, false);
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * а так же проигрывает звук получения вещи.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param min  минимальное количество при рейтах 1х
   * @param max  максимальное количество при рейтах 1х
   * @param prof       - учитывать дроп по параметру "рейт дропа для квестов на профу"
   * @param calcChance
   */
  public void rollAndGive(int itemId, int min, int max, double calcChance, boolean prof)
  {
    if(calcChance <= 0 || min <= 0 || max <= 0 || itemId <= 0)
    {
      return;
    }
    int count = rollDrop(min, max, calcChance, prof);
    if(count > 0)
    {
      giveItems(itemId, count, false);
      playSound(Quest.SOUND_ITEMGET);
    }
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * а так же проигрывает звук получения вещи.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param count      количество при рейтах 1х
   * @param calcChance
   */
  public boolean rollAndGive(int itemId, int count, double calcChance)
  {
    if(calcChance <= 0 || count <= 0 || itemId <= 0)
    {
      return false;
    }
    return rollAndGive(itemId, count, calcChance, false);
  }

  /**
   * Этот метод рассчитывает количество дропнутых вещей в зависимости от рейтов и дает их,
   * а так же проигрывает звук получения вещи.
   * <br><br>
   * Следует учесть, что контроль за верхним пределом вещей в квестах, в которых
   * нужно набить определенное количество предметов не осуществляется.
   * <br><br>
   * Ни один из передаваемых параметров не должен быть равен 0
   *
   * @param itemId     id вещи
   * @param count      количество при рейтах 1х
   * @param calcChance
   * @param prof       - учитывать дроп по параметру "рейт дропа для квестов на профу"
   */
  public boolean rollAndGive(int itemId, int count, double calcChance, boolean prof)
  {
    if(calcChance <= 0 || count <= 0 || itemId <= 0)
    {
      return false;
    }
    int countToDrop = rollDrop(count, calcChance, prof);
    if(countToDrop > 0)
    {
      giveItems(itemId, countToDrop, false);
      playSound(Quest.SOUND_ITEMGET);
      return true;
    }
    return false;
  }

  /**
   * Return true if quest completed, false otherwise
   *
   * @return boolean
   */
  public boolean isCompleted()
  {
    return getState() == Quest.COMPLETED;
  }

  /**
   * Return true if quest started, false otherwise
   *
   * @return boolean
   */
  public boolean isStarted()
  {
    return getState() != Quest.CREATED && getState() != Quest.COMPLETED;
  }

  public void killNpcByObjectId(int _objId)
  {
    L2NpcInstance npc = L2ObjectsStorage.getNpc(_objId);
    if(npc != null)
    {
      npc.doDie(null);
    }
    else
    {
      _log.warning("Attemp to kill object that is not npc in quest " + getQuest().getQuestIntId());
    }
  }

  /**
   * Аналог set с флагом true, но если получает cond проверяет нотацию (для совместимости).
   */
  public String set(String var, String val)
  {
    if(var.equalsIgnoreCase("cond"))
    {
      return setCond(Integer.parseInt(val));
    }
    return set(var, val, true);
  }

  /**
   * Аналог set с флагом true, но если получает cond проверяет нотацию (для совместимости).
   */
  public String set(String var, int intval)
  {
    if(var.equalsIgnoreCase("cond"))
    {
      return setCond(intval);
    }
    return set(var, String.valueOf(intval), true);
  }

  /**
   * <font color=red>Использовать осторожно! Служебная функция!</font><br><br>
   * <p/>
   * Устанавливает переменную и сохраняет в базу, если установлен флаг. Если получен cond обновляет список квестов игрока (только с флагом).
   *
   * @param var   : String pointing out the name of the variable for quest
   * @param val   : String pointing out the value of the variable for quest
   * @param store : Сохраняет в базу и если var это cond обновляет список квестов игрока.
   * @return String (equal to parameter "val")
   */
  public String set(String var, String val, boolean store)
  {
    if(_vars == null)
    {
      _vars = new ConcurrentHashMap<String, String>();
    }
    if(val == null)
    {
      val = "";
    }
    _vars.put(var, val);
    if(store)
    {
      L2Player player = getPlayer();
      if(player == null)
      {
        return null;
      }
      Quest.updateQuestVarInDb(this, var, val);
      if(var.equalsIgnoreCase("cond"))
      {
        player.sendPacket(new QuestList(player));
        if(!val.equals("0") && (getQuest().getQuestIntId() < 999 || getQuest().getQuestIntId() > 10000) && isStarted())
        {
          player.sendPacket(new ExShowQuestMark(getQuest().getQuestIntId()));
        }
      }
    }
    return val;
  }

  /**
   * Return state of the quest after its initialization.<BR><BR>
   * <U><I>Actions :</I></U>
   * <LI>Remove drops from previous state</LI>
   * <LI>Set new state of the quest</LI>
   * <LI>Add drop for new state</LI>
   * <LI>Update information in database</LI>
   * <LI>Send packet QuestList to client</LI>
   *
   * @param state
   * @return object
   */
  public Object setState(int state)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return null;
    }
    _state = state;
    if((getQuest().getQuestIntId() < 999 || getQuest().getQuestIntId() > 10000) && isStarted())
    {
      player.sendPacket(new ExShowQuestMark(getQuest().getQuestIntId()));
    }
    Quest.updateQuestInDb(this);
    player.sendPacket(new QuestList(player));
    return state;
  }

  public void removeRadar(int x, int y, int z)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.radar.removeMarker(x, y, z);
    }
  }

  /**
   * Send a packet in order to play sound at client terminal
   *
   * @param sound
   */
  public void playSound(String sound)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.sendPacket(new PlaySound(sound));
    }
  }

  public void playTutorialVoice(String voice)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.sendPacket(new PlaySound(2, voice, 0, 0, player.getLoc()));
    }
  }

  public void onTutorialClientEvent(int number)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.sendPacket(new TutorialEnableClientEvent(number));
    }
  }

  public void showQuestionMark(int number)
  {
    L2Player player = getPlayer();
    if(player != null)
    {
      player.sendPacket(new TutorialShowQuestionMark(number));
    }
  }

  public void showTutorialHTML(String html)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return;
    }
    String text = Files.read("data/scripts/quests/_255_Tutorial/" + html, player);
    if(text == null || text.equalsIgnoreCase(""))
    {
      text = "<html><body>File data/scripts/quests/_255_Tutorial/" + html + " not found or file is empty.</body></html>";
    }
    player.sendPacket(new TutorialShowHtml(text));
  }

  /**
   * Start a timer for quest.<BR><BR>
   *
   * @param name<BR> The name of the timer. Will also be the value for event of onEvent
   * @param time<BR> The milisecond value the timer will elapse
   */
  public void startQuestTimer(String name, long time)
  {
    getQuest().startQuestTimer(name, time, null, getPlayer());
  }

  /**
   * Удаляет указанные предметы из инвентаря игрока, и обновляет инвентарь
   *
   * @param itemId : id удаляемого предмета
   * @param count  : число удаляемых предметов<br>
   *               Если count передать -1, то будут удалены все указанные предметы.
   * @return Количество удаленных предметов
   */
  public long takeItems(int itemId, long count)
  {
    L2Player player = getPlayer();
    if(player == null)
    {
      return 0;
    }
    // Get object item from player's inventory list
    L2ItemInstance item = player.getInventory().getItemByItemId(itemId);
    if(item == null)
    {
      return 0;
    }
    // Tests on count value in order not to have negative value
    if(count < 0 || count > item.getCount())
    {
      count = item.getCount();
    }
    // Destroy the quantity of items wanted
    player.getInventory().destroyItemByItemId(itemId, count, true);
    // Send message of destruction to client
    player.sendPacket(SystemMessage.removeItems(itemId, count));
    return count;
  }

  public long takeAllItems(int itemId)
  {
    return takeItems(itemId, -1);
  }

  public long takeAllItems(int... itemsIds)
  {
    long result = 0;
    for(int id : itemsIds)
    {
      result += takeAllItems(id);
    }
    return result;
  }

  public long takeAllItems(short... itemsIds)
  {
    long result = 0;
    for(int id : itemsIds)
    {
      result += takeAllItems(id);
    }
    return result;
  }

  public long takeAllItems(Collection<Integer> itemsIds)
  {
    long result = 0;
    for(int id : itemsIds)
    {
      result += takeAllItems(id);
    }
    return result;
  }

  /**
   * Remove the variable of quest from the list of variables for the quest.<BR><BR>
   * <U><I>Concept : </I></U>
   * Remove the variable of quest represented by "var" from the class variable FastMap "vars" and from the database.
   *
   * @param var : String designating the variable for the quest to be deleted
   * @return String pointing out the previous value associated with the variable "var"
   */
  public String unset(String var)
  {
    if(_vars == null || var == null)
    {
      return null;
    }
    String old = _vars.remove(var);
    if(old != null)
    {
      Quest.deleteQuestVarInDb(this, var);
    }
    return old;
  }

  private boolean checkPartyMember(L2Player member, int state, int maxrange, L2Object rangefrom)
  {
    if(member == null)
    {
      return false;
    }
    if(rangefrom != null && maxrange > 0 && !member.isInRange(rangefrom, maxrange))
    {
      return false;
    }
    QuestState qs = member.getQuestState(getQuest().getName());
    if(qs == null || qs.getState() != state)
    {
      return false;
    }
    return true;
  }

  public GArray<L2Player> getPartyMembers(int state, int maxrange, L2Object rangefrom)
  {
    GArray<L2Player> result = new GArray<L2Player>();
    L2Party party = getPlayer().getParty();
    if(party == null)
    {
      if(checkPartyMember(getPlayer(), state, maxrange, rangefrom))
      {
        result.add(getPlayer());
      }
      return result;
    }
    for(L2Player _member : party.getPartyMembers())
    {
      if(checkPartyMember(_member, state, maxrange, rangefrom))
      {
        result.add(getPlayer());
      }
    }
    return result;
  }

  public L2Player getRandomPartyMember(int state, int maxrangefromplayer)
  {
    return getRandomPartyMember(state, maxrangefromplayer, getPlayer());
  }

  public L2Player getRandomPartyMember(int state, int maxrange, L2Object rangefrom)
  {
    GArray<L2Player> list = getPartyMembers(state, maxrange, rangefrom);
    if(list.size() == 0)
    {
      return null;
    }
    return list.get(Rnd.get(list.size()));
  }

  /**
   * Add spawn for player instance
   * Return object id of newly spawned npc
   */
  public L2NpcInstance addSpawn(int npcId)
  {
    return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, 0, 0);
  }

  public L2NpcInstance addSpawn(int npcId, int despawnDelay)
  {
    return addSpawn(npcId, getPlayer().getX(), getPlayer().getY(), getPlayer().getZ(), 0, 0, despawnDelay);
  }

  public L2NpcInstance addSpawn(int npcId, int x, int y, int z)
  {
    return addSpawn(npcId, x, y, z, 0, 0, 0);
  }

  /**
   * Add spawn for player instance
   * Will despawn after the spawn length expires
   * Return object id of newly spawned npc
   */
  public L2NpcInstance addSpawn(int npcId, int x, int y, int z, int despawnDelay)
  {
    return addSpawn(npcId, x, y, z, 0, 0, despawnDelay);
  }

  /**
   * Add spawn for player instance
   * Return object id of newly spawned npc
   */
  public L2NpcInstance addSpawn(int npcId, int x, int y, int z, int heading, int randomOffset, int despawnDelay)
  {
    return getQuest().addSpawn(npcId, x, y, z, heading, randomOffset, despawnDelay);
  }

  public L2NpcInstance findTemplate(int npcId)
  {
    for(L2Spawn spawn : SpawnTable.getInstance().getSpawnTable())
    {
      if(spawn != null && spawn.getNpcId() == npcId)
      {
        return spawn.getLastSpawn();
      }
    }
    return null;
  }

  public int calculateLevelDiffForDrop(int mobLevel, int player)
  {
    if(!Config.DEEPBLUE_DROP_RULES)
    {
      return 0;
    }
    return Math.max(player - mobLevel - Config.DEEPBLUE_DROP_MAXDIFF, 0);
  }

  /**
   * Возвращает текущий номер конда в стандартной нотации. Если не определен возвращает 0.
   */
  public int getCond()
  {
    int value = getRawInt("cond");
    if(value < 0) // новая побитовая нотация
    {
      return bitToInt(value);
    }
    return value;
  }

  private int bitToInt(int value)
  {
    // перебираем биты начиная с 30, поскольку 31 это бит знака
    for(int i = 30; i >= 0; i--)
    {
      if((value & (1 << i)) > 0) // если бит под этим номером определен
      {
        return i + 1;
      }
    } // нумерация битов начинается с 0, а кондов с 1
    return 0;
  }

  /**
   * Первый конд пропускать нельзя, Integer.MIN_VALUE флаг новой нотации
   */
  private static final int mask = 1 | Integer.MIN_VALUE;

  /**
   * Записывает номер конда с проверкой нотации и сохраняет в базу используя set(String, String, true).
   */
  public String setCond(int newCond)
  {
    int oldCond = getRawInt("cond");
    if(oldCond < 0)
    {
      // это уже новая нотация
      int oldCondStd = bitToInt(oldCond);
      if(newCond < oldCondStd)
      {
        // возвращаемся назад
        for(int i = oldCondStd - 1; i >= newCond; i--)
        {
          if((oldCond & (1 << i)) > 0)
          {
            oldCond ^= 1 << i;
          }
        }
        return set("cond", String.valueOf(oldCond), true);
      }
      // добавляем бит нового конда
      return set("cond", String.valueOf(oldCond | (1 << (newCond - 1))), true);
    }
    if(oldCond >= newCond - 1)
    // новый конд больше старого на 1 или вообще меньше старого, нет нужды в новой нотации
    {
      return set("cond", String.valueOf(newCond), true);
    }
    // это старый квест, но пропущен конд, меняем на новую нотацию
    return set("cond", String.valueOf(((1 << oldCond) - 1) | (1 << (newCond - 1)) | mask), true);
  }
}
TOP

Related Classes of l2p.gameserver.model.quest.QuestState

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.