/* * Copyright (C) 2004-2015 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.network.clientpackets; import java.util.List; import com.l2jserver.Config; import com.l2jserver.gameserver.data.xml.impl.SkillTreesData; import com.l2jserver.gameserver.datatables.SkillData; import com.l2jserver.gameserver.enums.CategoryType; import com.l2jserver.gameserver.enums.IllegalActionPunishmentType; import com.l2jserver.gameserver.enums.Race; import com.l2jserver.gameserver.enums.UserInfoType; import com.l2jserver.gameserver.model.ClanPrivilege; import com.l2jserver.gameserver.model.L2Clan; import com.l2jserver.gameserver.model.L2SkillLearn; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.instance.L2FishermanInstance; import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.actor.instance.L2VillageMasterInstance; import com.l2jserver.gameserver.model.base.AcquireSkillType; import com.l2jserver.gameserver.model.events.EventDispatcher; import com.l2jserver.gameserver.model.events.impl.character.player.OnPlayerSkillLearn; import com.l2jserver.gameserver.model.holders.ItemHolder; import com.l2jserver.gameserver.model.holders.SkillHolder; import com.l2jserver.gameserver.model.quest.QuestState; import com.l2jserver.gameserver.model.skills.CommonSkill; import com.l2jserver.gameserver.model.skills.Skill; import com.l2jserver.gameserver.model.variables.PlayerVariables; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.serverpackets.AcquireSkillDone; import com.l2jserver.gameserver.network.serverpackets.AcquireSkillList; import com.l2jserver.gameserver.network.serverpackets.ExAcquirableSkillListByClass; import com.l2jserver.gameserver.network.serverpackets.ExAlchemySkillList; import com.l2jserver.gameserver.network.serverpackets.ExBasicActionList; import com.l2jserver.gameserver.network.serverpackets.ExStorageMaxCount; import com.l2jserver.gameserver.network.serverpackets.ItemList; import com.l2jserver.gameserver.network.serverpackets.PledgeSkillList; import com.l2jserver.gameserver.network.serverpackets.ShortCutInit; import com.l2jserver.gameserver.network.serverpackets.SystemMessage; import com.l2jserver.gameserver.network.serverpackets.UserInfo; import com.l2jserver.gameserver.util.Util; /** * Request Acquire Skill client packet implementation. * @author Zoey76 */ public final class RequestAcquireSkill extends L2GameClientPacket { private static final String _C__7C_REQUESTACQUIRESKILL = "[C] 7C RequestAcquireSkill"; private static final String[] REVELATION_VAR_NAMES = { "RevelationSkill1", "RevelationSkill2" }; private static final String[] DUALCLASS_REVELATION_VAR_NAMES = { "DualclassRevelationSkill1", "DualclassRevelationSkill2" }; private int _id; private int _level; private AcquireSkillType _skillType; private int _subType; @Override protected void readImpl() { _id = readD(); _level = readD(); _skillType = AcquireSkillType.getAcquireSkillType(readD()); if (_skillType == AcquireSkillType.SUBPLEDGE) { _subType = readD(); } } @Override protected void runImpl() { final L2PcInstance activeChar = getClient().getActiveChar(); if (activeChar == null) { return; } if ((_level < 1) || (_level > 1000) || (_id < 1) || (_id > 32000)) { Util.handleIllegalPlayerAction(activeChar, "Wrong Packet Data in Aquired Skill", Config.DEFAULT_PUNISH); _log.warning("Recived Wrong Packet Data in Aquired Skill - id: " + _id + " level: " + _level + " for " + activeChar); return; } final L2Npc trainer = activeChar.getLastFolkNPC(); if (!(trainer instanceof L2NpcInstance) && (_skillType != AcquireSkillType.CLASS)) { return; } if ((_skillType != AcquireSkillType.CLASS) && !trainer.canInteract(activeChar) && !activeChar.isGM()) { return; } final Skill skill = SkillData.getInstance().getSkill(_id, _level); if (skill == null) { _log.warning(RequestAcquireSkill.class.getSimpleName() + ": Player " + activeChar.getName() + " is trying to learn a null skill Id: " + _id + " level: " + _level + "!"); return; } // Hack check. Doesn't apply to all Skill Types final int prevSkillLevel = activeChar.getSkillLevel(_id); if ((_skillType != AcquireSkillType.TRANSFER) && (_skillType != AcquireSkillType.SUBPLEDGE)) { if (prevSkillLevel == _level) { _log.warning("Player " + activeChar.getName() + " is trying to learn a skill that already knows, Id: " + _id + " level: " + _level + "!"); return; } final int tmpLv = (prevSkillLevel == -1) ? 0 : prevSkillLevel; if (tmpLv != (_level - 1)) { // The previous level skill has not been learned. activeChar.sendPacket(SystemMessageId.THE_PREVIOUS_LEVEL_SKILL_HAS_NOT_BEEN_LEARNED); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " without knowing it's previous level!", IllegalActionPunishmentType.NONE); return; } } final L2SkillLearn s = SkillTreesData.getInstance().getSkillLearn(_skillType, _id, _level, activeChar); if (s == null) { return; } switch (_skillType) { case CLASS: { if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); } break; } case TRANSFORM: { // Hack check. if (!canTransform(activeChar)) { activeChar.sendPacket(SystemMessageId.YOU_HAVE_NOT_COMPLETED_THE_NECESSARY_QUEST_FOR_SKILL_ACQUISITION); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " without required quests!", IllegalActionPunishmentType.NONE); return; } if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); } break; } case FISHING: { if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); } break; } case PLEDGE: { if (!activeChar.isClanLeader()) { return; } final L2Clan clan = activeChar.getClan(); int repCost = s.getLevelUpSp(); if (clan.getReputationScore() >= repCost) { if (Config.LIFE_CRYSTAL_NEEDED) { for (ItemHolder item : s.getRequiredItems()) { if (!activeChar.destroyItemByItemId("Consume", item.getId(), item.getCount(), trainer, false)) { // Doesn't have required item. activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); L2VillageMasterInstance.showPledgeSkillList(activeChar); return; } final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_S_DISAPPEARED); sm.addItemName(item.getId()); sm.addLong(item.getCount()); activeChar.sendPacket(sm); } } clan.takeReputationScore(repCost, true); final SystemMessage cr = SystemMessage.getSystemMessage(SystemMessageId.S1_POINT_S_HAVE_BEEN_DEDUCTED_FROM_THE_CLAN_S_REPUTATION); cr.addInt(repCost); activeChar.sendPacket(cr); clan.addNewSkill(skill); clan.broadcastToOnlineMembers(new PledgeSkillList(clan)); activeChar.sendPacket(new AcquireSkillDone()); L2VillageMasterInstance.showPledgeSkillList(activeChar); } else { activeChar.sendPacket(SystemMessageId.THE_ATTEMPT_TO_ACQUIRE_THE_SKILL_HAS_FAILED_BECAUSE_OF_AN_INSUFFICIENT_CLAN_REPUTATION); L2VillageMasterInstance.showPledgeSkillList(activeChar); } break; } case SUBPLEDGE: { if (!activeChar.isClanLeader() || !activeChar.hasClanPrivilege(ClanPrivilege.CL_TROOPS_FAME)) { return; } final L2Clan clan = activeChar.getClan(); if ((clan.getFortId() == 0) && (clan.getCastleId() == 0)) { return; } // Hack check. Check if SubPledge can accept the new skill: if (!clan.isLearnableSubPledgeSkill(skill, _subType)) { activeChar.sendPacket(SystemMessageId.THIS_SQUAD_SKILL_HAS_ALREADY_BEEN_LEARNED); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " without knowing it's previous level!", IllegalActionPunishmentType.NONE); return; } final int repCost = s.getLevelUpSp(); if (clan.getReputationScore() < repCost) { activeChar.sendPacket(SystemMessageId.THE_ATTEMPT_TO_ACQUIRE_THE_SKILL_HAS_FAILED_BECAUSE_OF_AN_INSUFFICIENT_CLAN_REPUTATION); return; } for (ItemHolder item : s.getRequiredItems()) { if (!activeChar.destroyItemByItemId("SubSkills", item.getId(), item.getCount(), trainer, false)) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); return; } final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_S1_S_DISAPPEARED); sm.addItemName(item.getId()); sm.addLong(item.getCount()); activeChar.sendPacket(sm); } if (repCost > 0) { clan.takeReputationScore(repCost, true); final SystemMessage cr = SystemMessage.getSystemMessage(SystemMessageId.S1_POINT_S_HAVE_BEEN_DEDUCTED_FROM_THE_CLAN_S_REPUTATION); cr.addInt(repCost); activeChar.sendPacket(cr); } clan.addNewSkill(skill, _subType); clan.broadcastToOnlineMembers(new PledgeSkillList(clan)); activeChar.sendPacket(new AcquireSkillDone()); showSubUnitSkillList(activeChar); break; } case TRANSFER: { if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); } final List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableTransferSkills(activeChar); if (skills.isEmpty()) { activeChar.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN); } else { activeChar.sendPacket(new ExAcquirableSkillListByClass(skills, AcquireSkillType.TRANSFER)); } break; } case SUBCLASS: { if (activeChar.isSubClassActive()) { activeChar.sendPacket(SystemMessageId.THIS_SKILL_CANNOT_BE_LEARNED_WHILE_IN_THE_SUBCLASS_STATE_PLEASE_TRY_AGAIN_AFTER_CHANGING_TO_THE_MAIN_CLASS); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while Sub-Class is active!", IllegalActionPunishmentType.NONE); return; } if (checkPlayerSkill(activeChar, trainer, s)) { final PlayerVariables vars = activeChar.getVariables(); String list = vars.getString("SubSkillList", ""); if ((prevSkillLevel > 0) && list.contains(_id + "-" + prevSkillLevel)) { list = list.replace(_id + "-" + prevSkillLevel, _id + "-" + _level); } else { if (!list.isEmpty()) { list += ";"; } list += _id + "-" + _level; } vars.set("SubSkillList", list); giveSkill(activeChar, trainer, skill, false); } break; } case DUALCLASS: { if (activeChar.isSubClassActive()) { activeChar.sendPacket(SystemMessageId.THIS_SKILL_CANNOT_BE_LEARNED_WHILE_IN_THE_SUBCLASS_STATE_PLEASE_TRY_AGAIN_AFTER_CHANGING_TO_THE_MAIN_CLASS); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while Sub-Class is active!", IllegalActionPunishmentType.NONE); return; } if (checkPlayerSkill(activeChar, trainer, s)) { final PlayerVariables vars = activeChar.getVariables(); String list = vars.getString("DualSkillList", ""); if ((prevSkillLevel > 0) && list.contains(_id + "-" + prevSkillLevel)) { list = list.replace(_id + "-" + prevSkillLevel, _id + "-" + _level); } else { if (!list.isEmpty()) { list += ";"; } list += _id + "-" + _level; } vars.set("DualSkillList", list); giveSkill(activeChar, trainer, skill, false); } break; } case COLLECT: { if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); } break; } case ALCHEMY: { if (activeChar.getRace() != Race.ERTHEIA) { return; } if (checkPlayerSkill(activeChar, trainer, s)) { giveSkill(activeChar, trainer, skill); activeChar.sendPacket(new AcquireSkillDone()); activeChar.sendPacket(new ExAlchemySkillList(activeChar)); final List<L2SkillLearn> alchemySkills = SkillTreesData.getInstance().getAvailableAlchemySkills(activeChar); if (alchemySkills.isEmpty()) { activeChar.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN); } else { activeChar.sendPacket(new ExAcquirableSkillListByClass(alchemySkills, AcquireSkillType.ALCHEMY)); } } break; } case REVELATION: { if (activeChar.isSubClassActive()) { activeChar.sendPacket(SystemMessageId.THIS_SKILL_CANNOT_BE_LEARNED_WHILE_IN_THE_SUBCLASS_STATE_PLEASE_TRY_AGAIN_AFTER_CHANGING_TO_THE_MAIN_CLASS); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while Sub-Class is active!", IllegalActionPunishmentType.NONE); return; } if ((activeChar.getLevel() < 85) || !activeChar.isInCategory(CategoryType.AWAKEN_GROUP)) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while not being level 85 or awaken!", IllegalActionPunishmentType.NONE); return; } int count = 0; for (String varName : REVELATION_VAR_NAMES) { if (activeChar.getVariables().getInt(varName, 0) > 0) { count++; } } if (count >= 2) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while having already learned 2 skills!", IllegalActionPunishmentType.NONE); return; } if (checkPlayerSkill(activeChar, trainer, s)) { final String varName = count == 0 ? REVELATION_VAR_NAMES[0] : REVELATION_VAR_NAMES[1]; activeChar.getVariables().set(varName, skill.getId()); giveSkill(activeChar, trainer, skill); } break; } case REVELATION_DUALCLASS: { if (activeChar.isSubClassActive() && !activeChar.isDualClassActive()) { activeChar.sendPacket(SystemMessageId.THIS_SKILL_CANNOT_BE_LEARNED_WHILE_IN_THE_SUBCLASS_STATE_PLEASE_TRY_AGAIN_AFTER_CHANGING_TO_THE_MAIN_CLASS); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while Sub-Class is active!", IllegalActionPunishmentType.NONE); return; } if ((activeChar.getLevel() < 85) || !activeChar.isInCategory(CategoryType.AWAKEN_GROUP)) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while not being level 85 or awaken!", IllegalActionPunishmentType.NONE); return; } int count = 0; for (String varName : DUALCLASS_REVELATION_VAR_NAMES) { if (activeChar.getVariables().getInt(varName, 0) > 0) { count++; } } if (count >= 2) { activeChar.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); Util.handleIllegalPlayerAction(activeChar, "Player " + activeChar.getName() + " is requesting skill Id: " + _id + " level " + _level + " while having already learned 2 skills!", IllegalActionPunishmentType.NONE); return; } if (checkPlayerSkill(activeChar, trainer, s)) { final String varName = count == 0 ? DUALCLASS_REVELATION_VAR_NAMES[0] : DUALCLASS_REVELATION_VAR_NAMES[1]; activeChar.getVariables().set(varName, skill.getId()); giveSkill(activeChar, trainer, skill); } break; } default: { _log.warning("Recived Wrong Packet Data in Aquired Skill, unknown skill type:" + _skillType); break; } } } public static void showSubUnitSkillList(L2PcInstance activeChar) { final List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableSubPledgeSkills(activeChar.getClan()); if (skills.isEmpty()) { activeChar.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN); } else { activeChar.sendPacket(new ExAcquirableSkillListByClass(skills, AcquireSkillType.SUBPLEDGE)); } } public final static void showSubSkillList(L2PcInstance activeChar) { final List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableSubClassSkills(activeChar); if (!skills.isEmpty()) { activeChar.sendPacket(new ExAcquirableSkillListByClass(skills, AcquireSkillType.SUBCLASS)); } else { activeChar.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN); } } public final static void showDualSkillList(L2PcInstance activeChar) { final List<L2SkillLearn> skills = SkillTreesData.getInstance().getAvailableDualClassSkills(activeChar); if (!skills.isEmpty()) { activeChar.sendPacket(new ExAcquirableSkillListByClass(skills, AcquireSkillType.DUALCLASS)); } else { activeChar.sendPacket(SystemMessageId.THERE_ARE_NO_OTHER_SKILLS_TO_LEARN); } } /** * Perform a simple check for current player and skill.<br> * Takes the needed SP if the skill require it and all requirements are meet.<br> * Consume required items if the skill require it and all requirements are meet.<br> * @param player the skill learning player. * @param trainer the skills teaching Npc. * @param s the skill to be learn. * @return {@code true} if all requirements are meet, {@code false} otherwise. */ private boolean checkPlayerSkill(L2PcInstance player, L2Npc trainer, L2SkillLearn s) { if (s != null) { if ((s.getSkillId() == _id) && (s.getSkillLevel() == _level)) { // Hack check. if (s.getGetLevel() > player.getLevel()) { player.sendPacket(SystemMessageId.YOU_DO_NOT_MEET_THE_SKILL_LEVEL_REQUIREMENTS); Util.handleIllegalPlayerAction(player, "Player " + player.getName() + ", level " + player.getLevel() + " is requesting skill Id: " + _id + " level " + _level + " without having minimum required level, " + s.getGetLevel() + "!", IllegalActionPunishmentType.NONE); return false; } // First it checks that the skill require SP and the player has enough SP to learn it. final int levelUpSp = s.getCalculatedLevelUpSp(player.getClassId(), player.getLearningClass()); if ((levelUpSp > 0) && (levelUpSp > player.getSp())) { player.sendPacket(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 (!s.getPreReqSkills().isEmpty()) { for (SkillHolder skill : s.getPreReqSkills()) { if (player.getSkillLevel(skill.getSkillId()) != skill.getSkillLvl()) { if (skill.getSkillId() == CommonSkill.ONYX_BEAST_TRANSFORMATION.getId()) { player.sendPacket(SystemMessageId.YOU_MUST_LEARN_THE_ONYX_BEAST_SKILL_BEFORE_YOU_CAN_LEARN_FURTHER_SKILLS); } else { player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); } return false; } } } // Check for required items. if (!s.getRequiredItems().isEmpty()) { // Then checks that the player has all the items long reqItemCount = 0; for (ItemHolder item : s.getRequiredItems()) { reqItemCount = player.getInventory().getInventoryItemCount(item.getId(), -1); if (reqItemCount < item.getCount()) { // Player doesn't have required item. player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_THE_NECESSARY_MATERIALS_OR_PREREQUISITES_TO_LEARN_THIS_SKILL); showSkillList(trainer, player); return false; } } // If the player has all required items, they are consumed. for (ItemHolder itemIdCount : s.getRequiredItems()) { if (!player.destroyItemByItemId("SkillLearn", itemIdCount.getId(), itemIdCount.getCount(), trainer, true)) { Util.handleIllegalPlayerAction(player, "Somehow player " + player.getName() + ", level " + player.getLevel() + " lose required item Id: " + itemIdCount.getId() + " to learn skill while learning skill Id: " + _id + " level " + _level + "!", IllegalActionPunishmentType.NONE); } } } if (!s.getRemoveSkills().isEmpty()) { s.getRemoveSkills().forEach(skillId -> { if (player.getSkillLevel(skillId) > 0) { 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); UserInfo ui = new UserInfo(player); ui.addComponentType(UserInfoType.CURRENT_HPMPCP_EXP_SP); player.sendPacket(ui); } return true; } } return false; } /** * Add the skill to the player and makes proper updates. * @param player the player acquiring a skill. * @param trainer the Npc teaching a skill. * @param skill the skill to be learn. */ private void giveSkill(L2PcInstance player, L2Npc trainer, Skill skill) { giveSkill(player, trainer, skill, true); } /** * Add the skill to the player and makes proper updates. * @param player the player acquiring a skill. * @param trainer the Npc teaching a skill. * @param skill the skill to be learn. * @param store */ private void giveSkill(L2PcInstance player, L2Npc trainer, Skill skill, boolean store) { // Send message. final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_S12); sm.addSkillName(skill); player.sendPacket(sm); player.addSkill(skill, store); player.sendPacket(new ItemList(player, false)); player.sendPacket(new ShortCutInit(player)); player.sendPacket(new ExBasicActionList(ExBasicActionList.DEFAULT_ACTION_LIST)); player.sendSkillList(skill.getId()); player.updateShortCuts(_id, _level); showSkillList(trainer, player); // If skill is expand type then sends packet: if ((_id >= 1368) && (_id <= 1372)) { player.sendPacket(new ExStorageMaxCount(player)); } // Notify scripts of the skill learn. if (trainer != null) { EventDispatcher.getInstance().notifyEventAsync(new OnPlayerSkillLearn(trainer, player, skill, _skillType), trainer); } else { EventDispatcher.getInstance().notifyEventAsync(new OnPlayerSkillLearn(trainer, player, skill, _skillType), player); } } /** * Wrapper for returning the skill list to the player after it's done with current skill. * @param trainer the Npc which the {@code player} is interacting * @param player the active character */ private void showSkillList(L2Npc trainer, L2PcInstance player) { if ((_skillType == AcquireSkillType.TRANSFORM) || (_skillType == AcquireSkillType.TRANSFER)) { // Managed in Datapack. return; } if (_skillType == AcquireSkillType.SUBCLASS) { showSubSkillList(player); } else if (_skillType == AcquireSkillType.DUALCLASS) { showDualSkillList(player); } else if (trainer instanceof L2FishermanInstance) { L2FishermanInstance.showFishSkillList(player); } else { player.sendPacket(new AcquireSkillList(player)); } } /** * Verify if the player can transform. * @param player the player to verify * @return {@code true} if the player meets the required conditions to learn a transformation, {@code false} otherwise */ public static boolean canTransform(L2PcInstance player) { if (Config.ALLOW_TRANSFORM_WITHOUT_QUEST) { return true; } final QuestState st = player.getQuestState("Q00136_MoreThanMeetsTheEye"); return (st != null) && st.isCompleted(); } @Override public String getType() { return _C__7C_REQUESTACQUIRESKILL; } }