Esempio n. 1
0
  @Override
  public final boolean addLevel(byte value) {
    if ((getLevel() + value) > (getMaxLevel() - 1)) {
      return false;
    }

    boolean levelIncreased = super.addLevel(value);

    // Sync up exp with current level
    // if (getExp() > getExpForLevel(getLevel() + 1) || getExp() < getExpForLevel(getLevel()))
    // setExp(Experience.LEVEL[getLevel()]);

    StatusUpdate su = new StatusUpdate(getActiveChar());
    su.addAttribute(StatusUpdate.LEVEL, getLevel());
    su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
    su.addAttribute(StatusUpdate.MAX_MP, getMaxMp());
    getActiveChar().broadcastPacket(su);
    if (levelIncreased) {
      getActiveChar()
          .broadcastPacket(new SocialAction(getActiveChar().getObjectId(), SocialAction.LEVEL_UP));
    }
    // Send a Server->Client packet PetInfo to the L2PcInstance
    getActiveChar().updateAndBroadcastStatus(1);

    if (getActiveChar().getControlItem() != null) {
      getActiveChar().getControlItem().setEnchantLevel(getLevel());
    }

    return levelIncreased;
  }
  @Override
  public void onAction(L2PcInstance player, boolean interact) {
    if (player == null || !canTarget(player)) return;

    // Check if the L2PcInstance already target the L2NpcInstance
    if (this != player.getTarget()) {
      // Set the target of the L2PcInstance player
      player.setTarget(this);

      // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
      MyTargetSelected my = new MyTargetSelected(getObjectId(), player.getLevel() - getLevel());
      player.sendPacket(my);

      // Send a Server->Client packet StatusUpdate of the L2NpcInstance to the L2PcInstance to
      // update its HP bar
      StatusUpdate su = new StatusUpdate(this);
      su.addAttribute(StatusUpdate.CUR_HP, (int) getStatus().getCurrentHp());
      su.addAttribute(StatusUpdate.MAX_HP, getMaxHp());
      player.sendPacket(su);

      // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and
      // heading on the client
      player.sendPacket(new ValidateLocation(this));
    } else if (interact) {
      if (isAutoAttackable(player) && Math.abs(player.getZ() - getZ()) < 100)
        player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
      else {
        // Send a Server->Client ActionFailed to the L2PcInstance in order to avoid that the client
        // wait another packet
        player.sendPacket(ActionFailed.STATIC_PACKET);
      }
    }
  }
Esempio n. 3
0
  public void useCubicSkill(L2CubicInstance activeCubic, L2Object[] targets) {
    if (Config.DEBUG) {
      _log.info("L2SkillDrain: useCubicSkill()");
    }

    for (L2Character target : (L2Character[]) targets) {
      if (target.isAlikeDead() && (getTargetType() != L2TargetType.CORPSE_MOB)) {
        continue;
      }

      boolean mcrit = Formulas.calcMCrit(activeCubic.getMCriticalHit(target, this));
      byte shld = Formulas.calcShldUse(activeCubic.getOwner(), target, this);

      int damage = (int) Formulas.calcMagicDam(activeCubic, target, this, mcrit, shld);
      if (Config.DEBUG) {
        _log.info("L2SkillDrain: useCubicSkill() -> damage = " + damage);
      }

      double hpAdd = _absorbAbs + (_absorbPart * damage);
      L2PcInstance owner = activeCubic.getOwner();
      double hp =
          ((owner.getCurrentHp() + hpAdd) > owner.getMaxHp()
              ? owner.getMaxHp()
              : (owner.getCurrentHp() + hpAdd));

      owner.setCurrentHp(hp);

      StatusUpdate suhp = new StatusUpdate(owner);
      suhp.addAttribute(StatusUpdate.CUR_HP, (int) hp);
      owner.sendPacket(suhp);

      // Check to see if we should damage the target
      if ((damage > 0) && (!target.isDead() || (getTargetType() != L2TargetType.CORPSE_MOB))) {
        target.reduceCurrentHp(damage, activeCubic.getOwner(), this);

        // Manage attack or cast break of the target (calculating rate, sending message...)
        if (!target.isRaid() && Formulas.calcAtkBreak(target, damage)) {
          target.breakAttack();
          target.breakCast();
        }
        owner.sendDamageMessage(target, damage, mcrit, false, false);
      }
    }
  }
Esempio n. 4
0
  @Override
  public void useSkill(L2Character activeChar, L2Object[] targets) {
    if (activeChar.isAlikeDead()) {
      return;
    }

    boolean ss = useSoulShot() && activeChar.isChargedShot(ShotType.SOULSHOTS);
    boolean sps = useSpiritShot() && activeChar.isChargedShot(ShotType.SPIRITSHOTS);
    boolean bss = useSpiritShot() && activeChar.isChargedShot(ShotType.BLESSED_SPIRITSHOTS);

    for (L2Character target : (L2Character[]) targets) {
      if (target.isAlikeDead() && (getTargetType() != L2TargetType.CORPSE_MOB)) {
        continue;
      }

      if ((activeChar != target) && target.isInvul()) {
        continue; // No effect on invulnerable chars unless they cast it themselves.
      }

      boolean mcrit = Formulas.calcMCrit(activeChar.getMCriticalHit(target, this));
      byte shld = Formulas.calcShldUse(activeChar, target, this);
      int damage =
          isStaticDamage()
              ? (int) getPower()
              : (int) Formulas.calcMagicDam(activeChar, target, this, shld, sps, bss, mcrit);

      int _drain = 0;
      int _cp = (int) target.getCurrentCp();
      int _hp = (int) target.getCurrentHp();

      if (_cp > 0) {
        if (damage < _cp) {
          _drain = 0;
        } else {
          _drain = damage - _cp;
        }
      } else if (damage > _hp) {
        _drain = _hp;
      } else {
        _drain = damage;
      }

      double hpAdd = _absorbAbs + (_absorbPart * _drain);
      double hp =
          ((activeChar.getCurrentHp() + hpAdd) > activeChar.getMaxHp()
              ? activeChar.getMaxHp()
              : (activeChar.getCurrentHp() + hpAdd));

      activeChar.setCurrentHp(hp);

      StatusUpdate suhp = new StatusUpdate(activeChar);
      suhp.addAttribute(StatusUpdate.CUR_HP, (int) hp);
      activeChar.sendPacket(suhp);

      // Check to see if we should damage the target
      if ((damage > 0) && (!target.isDead() || (getTargetType() != L2TargetType.CORPSE_MOB))) {
        // Manage attack or cast break of the target (calculating rate, sending message...)
        if (!target.isRaid() && Formulas.calcAtkBreak(target, damage)) {
          target.breakAttack();
          target.breakCast();
        }

        activeChar.sendDamageMessage(target, damage, mcrit, false, false);

        if (Config.LOG_GAME_DAMAGE
            && activeChar.isPlayable()
            && (damage > Config.LOG_GAME_DAMAGE_THRESHOLD)) {
          LogRecord record = new LogRecord(Level.INFO, "");
          record.setParameters(
              new Object[] {activeChar, " did damage ", damage, this, " to ", target});
          record.setLoggerName("mdam");
          _logDamage.log(record);
        }

        if (hasEffects() && (getTargetType() != L2TargetType.CORPSE_MOB)) {
          // ignoring vengance-like reflections
          if ((Formulas.calcSkillReflect(target, this) & Formulas.SKILL_REFLECT_SUCCEED) > 0) {
            activeChar.stopSkillEffects(getId());
            getEffects(target, activeChar);
            SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_FEEL_S1_EFFECT);
            sm.addSkillName(getId());
            activeChar.sendPacket(sm);
          } else {
            // activate attacked effects, if any
            target.stopSkillEffects(getId());
            if (Formulas.calcSkillSuccess(activeChar, target, this, shld, ss, sps, bss)) {
              getEffects(activeChar, target);
            } else {
              SystemMessage sm =
                  SystemMessage.getSystemMessage(SystemMessageId.C1_RESISTED_YOUR_S2);
              sm.addCharName(target);
              sm.addSkillName(this);
              activeChar.sendPacket(sm);
            }
          }
        }

        target.reduceCurrentHp(damage, activeChar, this);
      }

      // Check to see if we should do the decay right after the cast
      if (target.isDead() && (getTargetType() == L2TargetType.CORPSE_MOB) && target.isNpc()) {
        ((L2Npc) target).endDecayTask();
      }
    }
    // effect self :]
    L2Effect effect = activeChar.getFirstEffect(getId());
    if ((effect != null) && effect.isSelfEffect()) {
      // Replace old effect with new one.
      effect.exit();
    }
    // cast self effect if any
    getEffectsSelf(activeChar);
    // Consume shot
    activeChar.setChargedShot(bss ? ShotType.BLESSED_SPIRITSHOTS : ShotType.SPIRITSHOTS, false);
  }
Esempio n. 5
0
  @Override
  public void runImpl() {
    final L2PcInstance player = getClient().getActiveChar();
    if (player == null) {
      return;
    }

    if (!getClient().getFloodProtectors().getMultiSell().tryPerformAction("multisell choose")) {
      player.setMultiSell(null);
      return;
    }

    if ((_amount < 1) || (_amount > 5000)) {
      player.setMultiSell(null);
      return;
    }

    PreparedListContainer list = player.getMultiSell();
    if ((list == null) || (list.getListId() != _listId)) {
      player.setMultiSell(null);
      return;
    }

    final L2Npc npc = player.getLastFolkNPC();
    if (((npc != null) && !list.isNpcAllowed(npc.getId())) || ((npc == null) && list.isNpcOnly())) {
      player.setMultiSell(null);
      return;
    }

    if (!player.isGM() && (npc != null)) {
      if (!player.isInsideRadius(npc, INTERACTION_DISTANCE, true, false)
          || (player.getInstanceId() != npc.getInstanceId())) {
        player.setMultiSell(null);
        return;
      }
    }

    for (Entry entry : list.getEntries()) {
      if (entry.getEntryId() == _entryId) {
        if (!entry.isStackable() && (_amount > 1)) {
          _log.severe(
              "Character: "
                  + player.getName()
                  + " is trying to set amount > 1 on non-stackable multisell, id:"
                  + _listId
                  + ":"
                  + _entryId);
          player.setMultiSell(null);
          return;
        }

        final PcInventory inv = player.getInventory();

        int slots = 0;
        int weight = 0;
        for (Ingredient e : entry.getProducts()) {
          if (e.getItemId() < 0) {
            continue;
          }

          if (!e.isStackable()) {
            slots += e.getItemCount() * _amount;
          } else if (player.getInventory().getItemByItemId(e.getItemId()) == null) {
            slots++;
          }
          weight += e.getItemCount() * _amount * e.getWeight();
        }

        if (!inv.validateWeight(weight)) {
          player.sendPacket(SystemMessageId.WEIGHT_LIMIT_EXCEEDED);
          return;
        }

        if (!inv.validateCapacity(slots)) {
          player.sendPacket(SystemMessageId.SLOTS_FULL);
          return;
        }

        ArrayList<Ingredient> ingredientsList = new ArrayList<>(entry.getIngredients().size());
        // Generate a list of distinct ingredients and counts in order to check if the correct
        // item-counts
        // are possessed by the player
        boolean newIng;
        for (Ingredient e : entry.getIngredients()) {
          newIng = true;
          // at this point, the template has already been modified so that enchantments are properly
          // included
          // whenever they need to be applied. Uniqueness of items is thus judged by item id AND
          // enchantment level
          for (int i = ingredientsList.size(); --i >= 0; ) {
            Ingredient ex = ingredientsList.get(i);
            // if the item was already added in the list, merely increment the count
            // this happens if 1 list entry has the same ingredient twice (example 2 swords = 1
            // dual)
            if ((ex.getItemId() == e.getItemId())
                && (ex.getEnchantLevel() == e.getEnchantLevel())) {
              if ((ex.getItemCount() + e.getItemCount()) > Integer.MAX_VALUE) {
                player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED);
                return;
              }
              // two same ingredients, merge into one and replace old
              final Ingredient ing = ex.getCopy();
              ing.setItemCount(ex.getItemCount() + e.getItemCount());
              ingredientsList.set(i, ing);
              newIng = false;
              break;
            }
          }
          if (newIng) {
            // if it's a new ingredient, just store its info directly (item id, count, enchantment)
            ingredientsList.add(e);
          }
        }

        // now check if the player has sufficient items in the inventory to cover the ingredients'
        // expences
        for (Ingredient e : ingredientsList) {
          if ((e.getItemCount() * _amount) > Integer.MAX_VALUE) {
            player.sendPacket(SystemMessageId.YOU_HAVE_EXCEEDED_QUANTITY_THAT_CAN_BE_INPUTTED);
            return;
          }
          if (e.getItemId() < 0) {
            if (!MultisellData.hasSpecialIngredient(
                e.getItemId(), e.getItemCount() * _amount, player)) {
              return;
            }
          } else {
            // if this is not a list that maintains enchantment, check the count of all items that
            // have the given id.
            // otherwise, check only the count of items with exactly the needed enchantment level
            final long required =
                ((Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient())
                    ? (e.getItemCount() * _amount)
                    : e.getItemCount());
            if (inv.getInventoryItemCount(
                    e.getItemId(), list.getMaintainEnchantment() ? e.getEnchantLevel() : -1, false)
                < required) {
              SystemMessage sm =
                  SystemMessage.getSystemMessage(SystemMessageId.S2_UNIT_OF_THE_ITEM_S1_REQUIRED);
              sm.addItemName(e.getTemplate());
              sm.addLong(required);
              player.sendPacket(sm);
              return;
            }
          }
        }

        List<L2Augmentation> augmentation = new ArrayList<>();
        Elementals[] elemental = null;
        /** All ok, remove items and add final product */
        for (Ingredient e : entry.getIngredients()) {
          if (e.getItemId() < 0) {
            if (!MultisellData.takeSpecialIngredient(
                e.getItemId(), e.getItemCount() * _amount, player)) {
              return;
            }
          } else {
            L2ItemInstance itemToTake =
                inv.getItemByItemId(
                    e.getItemId()); // initialize and initial guess for the item to take.
            if (itemToTake
                == null) { // this is a cheat, transaction will be aborted and if any items already
                           // taken will not be returned back to inventory!
              _log.severe(
                  "Character: "
                      + player.getName()
                      + " is trying to cheat in multisell, id:"
                      + _listId
                      + ":"
                      + _entryId);
              player.setMultiSell(null);
              return;
            }

            // if (itemToTake.isEquipped())
            // {
            // this is a cheat, transaction will be aborted and if any items already taken will not
            // be returned back to inventory!
            // _log.severe("Character: " + player.getName() + " is trying to cheat in multisell,
            // exchanging equipped item, merchatnt id:" + merchant.getNpcId());
            // player.setMultiSell(null);
            // return;
            // }

            if (Config.ALT_BLACKSMITH_USE_RECIPES || !e.getMaintainIngredient()) {
              // if it's a stackable item, just reduce the amount from the first (only) instance
              // that is found in the inventory
              if (itemToTake.isStackable()) {
                if (!player.destroyItem(
                    "Multisell",
                    itemToTake.getObjectId(),
                    (e.getItemCount() * _amount),
                    player.getTarget(),
                    true)) {
                  player.setMultiSell(null);
                  return;
                }
              } else {
                // for non-stackable items, one of two scenaria are possible:
                // a) list maintains enchantment: get the instances that exactly match the requested
                // enchantment level
                // b) list does not maintain enchantment: get the instances with the LOWEST
                // enchantment level

                // a) if enchantment is maintained, then get a list of items that exactly match this
                // enchantment
                if (list.getMaintainEnchantment()) {
                  // loop through this list and remove (one by one) each item until the required
                  // amount is taken.
                  L2ItemInstance[] inventoryContents =
                      inv.getAllItemsByItemId(e.getItemId(), e.getEnchantLevel(), false);
                  for (int i = 0; i < (e.getItemCount() * _amount); i++) {
                    if (inventoryContents[i].isAugmented()) {
                      augmentation.add(inventoryContents[i].getAugmentation());
                    }
                    if (inventoryContents[i].getElementals() != null) {
                      elemental = inventoryContents[i].getElementals();
                    }
                    if (!player.destroyItem(
                        "Multisell",
                        inventoryContents[i].getObjectId(),
                        1,
                        player.getTarget(),
                        true)) {
                      player.setMultiSell(null);
                      return;
                    }
                  }
                } else
                // b) enchantment is not maintained. Get the instances with the LOWEST enchantment
                // level
                {
                  // NOTE: There are 2 ways to achieve the above goal.
                  // 1) Get all items that have the correct itemId, loop through them until the
                  // lowest enchantment
                  // level is found. Repeat all this for the next item until proper count of items
                  // is reached.
                  // 2) Get all items that have the correct itemId, sort them once based on
                  // enchantment level,
                  // and get the range of items that is necessary.
                  // Method 1 is faster for a small number of items to be exchanged.
                  // Method 2 is faster for large amounts.
                  //
                  // EXPLANATION:
                  // Worst case scenario for algorithm 1 will make it run in a number of cycles
                  // given by:
                  // m*(2n-m+1)/2 where m is the number of items to be exchanged and n is the total
                  // number of inventory items that have a matching id.
                  // With algorithm 2 (sort), sorting takes n*log(n) time and the choice is done in
                  // a single cycle
                  // for case b (just grab the m first items) or in linear time for case a (find the
                  // beginning of items
                  // with correct enchantment, index x, and take all items from x to x+m).
                  // Basically, whenever m > log(n) we have: m*(2n-m+1)/2 = (2nm-m*m+m)/2 >
                  // (2nlogn-logn*logn+logn)/2 = nlog(n) - log(n*n) + log(n) = nlog(n) + log(n/n*n)
                  // =
                  // nlog(n) + log(1/n) = nlog(n) - log(n) = (n-1)log(n)
                  // So for m < log(n) then m*(2n-m+1)/2 > (n-1)log(n) and m*(2n-m+1)/2 > nlog(n)
                  //
                  // IDEALLY:
                  // In order to best optimize the performance, choose which algorithm to run, based
                  // on whether 2^m > n
                  // if ( (2<<(e.getItemCount()// _amount)) < inventoryContents.length )
                  // // do Algorithm 1, no sorting
                  // else
                  // // do Algorithm 2, sorting
                  //
                  // CURRENT IMPLEMENTATION:
                  // In general, it is going to be very rare for a person to do a massive exchange
                  // of non-stackable items
                  // For this reason, we assume that algorithm 1 will always suffice and we keep
                  // things simple.
                  // If, in the future, it becomes necessary that we optimize, the above discussion
                  // should make it clear
                  // what optimization exactly is necessary (based on the comments under "IDEALLY").
                  //

                  // choice 1. Small number of items exchanged. No sorting.
                  for (int i = 1; i <= (e.getItemCount() * _amount); i++) {
                    L2ItemInstance[] inventoryContents =
                        inv.getAllItemsByItemId(e.getItemId(), false);

                    itemToTake = inventoryContents[0];
                    // get item with the LOWEST enchantment level from the inventory...
                    // +0 is lowest by default...
                    if (itemToTake.getEnchantLevel() > 0) {
                      for (L2ItemInstance item : inventoryContents) {
                        if (item.getEnchantLevel() < itemToTake.getEnchantLevel()) {
                          itemToTake = item;
                          // nothing will have enchantment less than 0. If a zero-enchanted
                          // item is found, just take it
                          if (itemToTake.getEnchantLevel() == 0) {
                            break;
                          }
                        }
                      }
                    }
                    if (!player.destroyItem(
                        "Multisell", itemToTake.getObjectId(), 1, player.getTarget(), true)) {
                      player.setMultiSell(null);
                      return;
                    }
                  }
                }
              }
            }
          }
        }

        // Generate the appropriate items
        for (Ingredient e : entry.getProducts()) {
          if (e.getItemId() < 0) {
            MultisellData.giveSpecialProduct(e.getItemId(), e.getItemCount() * _amount, player);
          } else {
            if (e.isStackable()) {
              inv.addItem(
                  "Multisell",
                  e.getItemId(),
                  e.getItemCount() * _amount,
                  player,
                  player.getTarget());
            } else {
              L2ItemInstance product = null;
              for (int i = 0; i < (e.getItemCount() * _amount); i++) {
                product = inv.addItem("Multisell", e.getItemId(), 1, player, player.getTarget());
                if ((product != null) && list.getMaintainEnchantment()) {
                  if (i < augmentation.size()) {
                    product.setAugmentation(
                        new L2Augmentation(augmentation.get(i).getAugmentationId()));
                  }
                  if (elemental != null) {
                    for (Elementals elm : elemental) {
                      product.setElementAttr(elm.getElement(), elm.getValue());
                    }
                  }
                  product.setEnchantLevel(e.getEnchantLevel());
                  product.updateDatabase();
                }
              }
            }
            // msg part
            SystemMessage sm;

            if ((e.getItemCount() * _amount) > 1) {
              sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S2_S1_S);
              sm.addItemName(e.getItemId());
              sm.addLong(e.getItemCount() * _amount);
              player.sendPacket(sm);
            } else {
              if (list.getMaintainEnchantment() && (e.getEnchantLevel() > 0)) {
                sm = SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED_S1_S2);
                sm.addLong(e.getEnchantLevel());
                sm.addItemName(e.getItemId());
              } else {
                sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_ITEM_S1);
                sm.addItemName(e.getItemId());
              }
              player.sendPacket(sm);
            }
          }
        }
        player.sendPacket(new ItemList(player, false));

        StatusUpdate su = new StatusUpdate(player);
        su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
        player.sendPacket(su);

        // finally, give the tax to the castle...
        if ((npc != null) && (entry.getTaxAmount() > 0)) {
          npc.getCastle().addToTreasury(entry.getTaxAmount() * _amount);
        }
        break;
      }
    }
  }