Изучение умений с требованиями

mamcy

Друг форума
Местный
Старожил I степени
Участник Новогоднего Фонда 2023
Победитель в номинации 2023
Победитель в номинации 2022
Неукротимое пламя
Сообщения
241
Розыгрыши
0
Решения
4
Репутация
164
Реакции
65
Баллы
970
Хроники
  1. Prelude
Исходники
Присутствуют
Сборка
Mobius
Добрый вечер, при изучении умения с требованием (книга) или другой итем она списывается с множителем х2 то-есть 2 книги. Адену списывает как прописано. Если в инвентаре есть 1 книга, умение изучится но выскакивает надпись об ошибке что нет подходящих итемов.

Код:
private boolean checkPlayerSkill(Player player, Npc trainer, SkillLearn skillLearn)
    {
        if ((skillLearn != null) && (skillLearn.getSkillLevel() == _level))
        {
            // Hack check.
            if (skillLearn.getGetLevel() > player.getLevel())
            {
                player.sendPacket(SystemMessageId.YOU_DO_NOT_MEET_THE_SKILL_LEVEL_REQUIREMENTS);
                PunishmentManager.handleIllegalPlayerAction(player, player + ", level " + player.getLevel() + " is requesting skill Id: " + _id + " level " + _level + " without having minimum required level, " + skillLearn.getGetLevel() + "!", IllegalActionPunishmentType.NONE);
                return false;
            }
          
            if (skillLearn.getDualClassLevel() > 0)
            {
                final SubClassHolder playerDualClass = player.getDualClass();
                if ((playerDualClass == null) || (playerDualClass.getLevel() < skillLearn.getDualClassLevel()))
                {
                    return false;
                }
            }
          
            // First it checks that the skill require SP and the player has enough SP to learn it.
            final long levelUpSp = skillLearn.getLevelUpSp();
            if ((levelUpSp > 0) && (levelUpSp > player.getSp()))
            {
                player.sendPacket(new ExAcquireSkillResult(skillLearn.getSkillId(), skillLearn.getSkillLevel(), false, SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_SP_TO_LEARN_THIS_SKILL));
                showSkillList(trainer, player);
                return false;
            }
          
            if (!Config.DIVINE_SP_BOOK_NEEDED && (_id == CommonSkill.DIVINE_INSPIRATION.getId()))
            {
                return true;
            }
          
            // Check for required skills.
            if (!skillLearn.getPreReqSkills().isEmpty())
            {
                for (SkillHolder skill : skillLearn.getPreReqSkills())
                {
                    if (player.getSkillLevel(skill.getSkillId()) < skill.getSkillLevel())
                    {
                        if (skill.getSkillId() == CommonSkill.ONYX_BEAST_TRANSFORMATION.getId())
                        {
                            player.sendPacket(new ExAcquireSkillResult(skillLearn.getSkillId(), skillLearn.getSkillLevel(), false, SystemMessageId.YOU_MUST_LEARN_THE_ONYX_BEAST_SKILL_BEFORE_YOU_CAN_LEARN_FURTHER_SKILLS));
                        }
                        else
                        {
                            player.sendPacket(new ExAcquireSkillResult(skillLearn.getSkillId(), skillLearn.getSkillLevel(), false, SystemMessageId.NOT_ENOUGH_ITEMS_TO_LEARN_THE_SKILL));
                        }
                        return false;
                    }
                }
            }
          
            // Check for required items.
            if (!skillLearn.getRequiredItems().isEmpty())
            {
                // Then checks that the player has all the items
                int count = 0;
                long playerItemCount = 0;
                for (List<ItemHolder> items : skillLearn.getRequiredItems())
                {
                    count = 0;
                    SEARCH: for (ItemHolder item : items)
                    {
                        count++;
                        playerItemCount = player.getInventory().getInventoryItemCount(item.getId(), -1);
                        if (playerItemCount >= item.getCount())
                        {
                            break SEARCH;
                        }
                      
                        if (count == items.size())
                        {
                            player.sendPacket(new ExAcquireSkillResult(skillLearn.getSkillId(), skillLearn.getSkillLevel(), false, SystemMessageId.NOT_ENOUGH_ITEMS_TO_LEARN_THE_SKILL));
                            showSkillList(trainer, player);
                            return false;
                        }
                    }
                }
              
                // If the player has all required items, they are consumed.
                for (List<ItemHolder> items : skillLearn.getRequiredItems())
                {
                    count = 0;
                    SEARCH: for (ItemHolder item : items)
                    {
                        count++;
                        playerItemCount = player.getInventory().getInventoryItemCount(item.getId(), -1);
                        if ((playerItemCount >= item.getCount()) && player.destroyItemByItemId(ItemProcessType.FEE, item.getId(), item.getCount(), trainer, true))
                        {
                            break SEARCH;
                        }
                      
                        if (count == items.size())
                        {
                            PunishmentManager.handleIllegalPlayerAction(player, "Somehow " + player + ", level " + player.getLevel() + " lose required item Id: " + item.getId() + " to learn skill while learning skill Id: " + _id + " level " + _level + "!", IllegalActionPunishmentType.NONE);
                        }
                    }
                }
            }
          
            if (!skillLearn.getRemoveSkills().isEmpty())
            {
                skillLearn.getRemoveSkills().forEach(skillId ->
                {
                    final Skill skillToRemove = player.getKnownSkill(skillId);
                    if (skillToRemove != null)
                    {
                        player.removeSkill(skillToRemove, true);
                    }
                });
            }
          
            // If the player has SP and all required items then consume SP.
            if (levelUpSp > 0)
            {
                player.setSp(player.getSp() - levelUpSp);
                final UserInfo ui = new UserInfo(player);
                ui.addComponentType(UserInfoType.CURRENT_HPMPCP_EXP_SP);
                player.sendPacket(ui);
            }
            return true;
        }
        return false;
    }
Тут вроде нет двойного списания. Куда копать кто сможет подсказать?
[04/07 22:38:10] Consuming item for skill 45313: ID=93384, Count=1
в логе указывает 1 штуку
 
Решение
В общем нашел я причину почему было двойное списание, в методе destroyItemByItemId было дублирование,

Код:
public boolean destroyItemByItemId(ItemProcessType process, int itemId, long count, WorldObject reference, boolean sendMessage)
    {
        if (itemId == Inventory.ADENA_ID)
        {
        return reduceAdena(process, count, reference, sendMessage);
        }
    
        final Item item = _inventory.getItemByItemId(itemId);
        final long quantity = (count < 0) && (item != null) ? item.getCount() : count;
    
        // Проверка перед уничтожением
        if ((item == null) || (item.getCount() < quantity) || (quantity <= 0))
        {
            if (sendMessage)
            {...
Как-то очень уж коряво описан блок кода где идет удаление требуемых предметов - почему не переписать на более вменяемый код?
я вот про этот вот кусок кода
Java:
                // If the player has all required items, they are consumed.
                for (List<ItemHolder> items : skillLearn.getRequiredItems())
                {
                    count = 0;
                    SEARCH: for (ItemHolder item : items)
                    {
                        count++;
                        playerItemCount = player.getInventory().getInventoryItemCount(item.getId(), -1);
                        if ((playerItemCount >= item.getCount()) && player.destroyItemByItemId(ItemProcessType.FEE, item.getId(), item.getCount(), trainer, true))
                        {
                            break SEARCH;
                        }
                     
                        if (count == items.size())
                        {
                            PunishmentManager.handleIllegalPlayerAction(player, "Somehow " + player + ", level " + player.getLevel() + " lose required item Id: " + item.getId() + " to learn skill while learning skill Id: " + _id + " level " + _level + "!", IllegalActionPunishmentType.NONE);
                        }
                    }
                }
 
Как-то очень уж коряво описан блок кода где идет удаление требуемых предметов - почему не переписать на более вменяемый код?
я вот про этот вот кусок кода
Java:
                // If the player has all required items, they are consumed.
                for (List<ItemHolder> items : skillLearn.getRequiredItems())
                {
                    count = 0;
                    SEARCH: for (ItemHolder item : items)
                    {
                        count++;
                        playerItemCount = player.getInventory().getInventoryItemCount(item.getId(), -1);
                        if ((playerItemCount >= item.getCount()) && player.destroyItemByItemId(ItemProcessType.FEE, item.getId(), item.getCount(), trainer, true))
                        {
                            break SEARCH;
                        }
                    
                        if (count == items.size())
                        {
                            PunishmentManager.handleIllegalPlayerAction(player, "Somehow " + player + ", level " + player.getLevel() + " lose required item Id: " + item.getId() + " to learn skill while learning skill Id: " + _id + " level " + _level + "!", IllegalActionPunishmentType.NONE);
                        }
                    }
                }
А как лучше? Привидите пример.
 
Ну у меня конечно чуток по другому и все такое, но все же более понятней и логичней.
собственно проверки предметов и их удаление вынесены в отдельные методы для удобства, но это так, мелочи
Java:
    private static boolean checkItems(Player player, SkillLearn skillLearn)
    {
        return skillLearn.getItems().isEmpty() || skillLearn.getItems().stream().allMatch(item -> player.getItemCount(item.getId()) >= item.getCount());
    }

    private static boolean consumeItems(Player player, SkillLearn skillLearn)
    {
        if (!checkItems(player, skillLearn))
            return false;

        for (ItemData item : skillLearn.getItems())
            if (!player.consumeItem(item.getId(), item.getCount()))
                return false;

        return true;
    }
 
Последнее редактирование:
Ну у меня конечно чуток по другому и все такое, но все же более понятней и логичней.
собственно проверки предметов и их удаление вынесены в отдельные методы для удобства, но это так, мелочи
Java:
    private static boolean checkItems(Player player, SkillLearn skillLearn)
    {
        return skillLearn.getItems().isEmpty() || skillLearn.getItems().stream().allMatch(item -> player.getItemCount(item.getId()) >= item.getCount());
    }

    private static boolean consumeItems(Player player, SkillLearn skillLearn)
    {
        if (!checkItems(player, skillLearn))
            return false;

        for (ItemData item : skillLearn.getItems())
            if (!player.consumeItem(item.getId(), item.getCount()))
                return false;

        return true;
    }
гайка когда на твоем уже эсенс появится?)
 
В общем нашел я причину почему было двойное списание, в методе destroyItemByItemId было дублирование,

Код:
public boolean destroyItemByItemId(ItemProcessType process, int itemId, long count, WorldObject reference, boolean sendMessage)
    {
        if (itemId == Inventory.ADENA_ID)
        {
        return reduceAdena(process, count, reference, sendMessage);
        }
    
        final Item item = _inventory.getItemByItemId(itemId);
        final long quantity = (count < 0) && (item != null) ? item.getCount() : count;
    
        // Проверка перед уничтожением
        if ((item == null) || (item.getCount() < quantity) || (quantity <= 0))
        {
            if (sendMessage)
            {
                sendPacket(SystemMessageId.INCORRECT_ITEM_COUNT_2);
            }
            return false;
        }
    
        // Уничтожение предмета.
        final Item destroyedItem = _inventory.destroyItemByItemId(process, itemId, quantity, this, reference);
        if (destroyedItem == null)
        {
            if (sendMessage)
            {
                sendPacket(SystemMessageId.INCORRECT_ITEM_COUNT_2);
            }
            return false;
        }
    
        // Обновление инвентаря
        final InventoryUpdate playerIU = new InventoryUpdate();
        if (item.isStackable() && (destroyedItem.getCount() > 0))
        {
            playerIU.addModifiedItem(destroyedItem);
        }
        else
        {
            playerIU.addRemovedItem(destroyedItem);
        }
        sendInventoryUpdate(playerIU);
    
        // Уведомление игрока
        if (sendMessage)
        {
            if (quantity > 1)
            {
                final SystemMessage sm = new SystemMessage(SystemMessageId.S1_X_S2_DISAPPEARED);
                sm.addItemName(itemId);
                sm.addLong(quantity);
                sendPacket(sm);
            }
            else
            {
                final SystemMessage sm = new SystemMessage(SystemMessageId.S1_DISAPPEARED);
                sm.addItemName(itemId);
                sendPacket(sm);
            }
        }
    
        return true;
    }
Вот измененная версия, вдруг кому пригодиться.
 
Решение
Вобще странно конечно, данный метод по идее юзается очень много где в удалениях предметов, так что косяк в нем бы наверное быстро вылез.
 
Назад
Сверху