package handling.channel.handler; import client.inventory.Equip; import client.inventory.Item; import client.inventory.MapleInventoryType; import client.MapleClient; import client.MapleCharacter; import constants.GameConstants; import client.MapleQuestStatus; import client.RockPaperScissors; import client.inventory.ItemFlag; import constants.ItemConstants; import constants.QuickMove; import handling.SendPacketOpcode; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import server.shops.MapleShop; import server.MapleInventoryManipulator; import server.MapleStorage; import server.life.MapleNPC; import server.quest.MapleQuest; import scripting.NPCScriptManager; import scripting.NPCConversationManager; import scripting.ScriptType; import server.MapleItemInformationProvider; import server.life.MapleLifeFactory; import scripting.MapScriptMethods; import tools.packet.CField; import tools.Pair; import tools.data.LittleEndianAccessor; import tools.data.MaplePacketLittleEndianWriter; import tools.packet.CWvsContext; public class NPCHandler { public static void NPCAnimation(LittleEndianAccessor slea, MapleClient c) { MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendPacketOpcode.NPC_ACTION.getValue()); int length = (int) slea.available(); if (length == 10) { mplew.writeInt(slea.readInt()); mplew.writeShort(slea.readShort()); mplew.writeInt(slea.readInt()); } else if (length > 6) { mplew.write(slea.read(length - 9)); } else { return; } c.getSession().write(mplew.getPacket()); } public static final void NPCShop(LittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { byte bmode = slea.readByte(); if (chr == null) { return; } switch (bmode) { case 0: {//購買 MapleShop shop = chr.getShop(); if (shop == null) { return; } short slot = slea.readShort(); int itemId = slea.readInt(); short quantity = slea.readShort(); // int unitprice = slea.readInt(); shop.buy(c, slot, itemId, quantity); break; } case 1: {//出售 MapleShop shop = chr.getShop(); if (shop == null) { return; } byte slot = (byte) slea.readShort(); int itemId = slea.readInt(); short quantity = slea.readShort(); shop.sell(c, GameConstants.getInventoryType(itemId), slot, quantity); break; } case 2: {//充值 MapleShop shop = chr.getShop(); if (shop == null) { return; } byte slot = (byte) slea.readShort(); shop.recharge(c, slot); break; } default: chr.setConversation(0); } } public static final void NPCTalk(final LittleEndianAccessor slea, final MapleClient c, final MapleCharacter chr) { if (chr == null || chr.getMap() == null) { return; } final MapleNPC npc = chr.getMap().getNPCByOid(slea.readInt()); if (npc == null) { if (c.getPlayer().isShowErr()) { c.getPlayer().showInfo("NPC對話", true, "當前地圖不存在此NPC"); } return; } if (chr.hasBlockedInventory()) { if (c.getPlayer().isShowErr()) { c.getPlayer().showInfo("NPC對話", true, "無法進行對話,hasBlockedInventory-" + chr.hasBlockedInventory()); } c.getPlayer().dropMessage(-1, "你當前已經和1個NPC對話了. 如果不是請輸入 @解卡 指令進行解卡。"); return; } if (npc.hasShop()) { chr.setConversation(1); npc.sendShop(c); } else { NPCScriptManager.getInstance().start(c, npc.getId(), null); } } public static final void QuestAction(final LittleEndianAccessor slea, final MapleClient c, final MapleCharacter chr) { final byte action = slea.readByte(); int quest = slea.readUShort(); if (quest == 20734) { c.getSession().write(CWvsContext.ultimateExplorer()); return; } if (chr == null) { return; } boolean 冰原雪域的長老任務; switch (quest) { case 1430: case 1434: case 1438: case 1441: case 1444: 冰原雪域的長老任務 = true; break; default: 冰原雪域的長老任務 = false; } if (冰原雪域的長老任務 && c.getPlayer().getQuestStatus(quest) != 1 && c.getPlayer().getMapId() != 211000001) {//冒險家3轉傳送 final server.maps.MapleMap mapz = handling.channel.ChannelServer.getInstance(c.getChannel()).getMapFactory().getMap(211000001); c.getPlayer().changeMap(mapz, mapz.getPortal(0)); } final MapleQuest q = MapleQuest.getInstance(quest); switch (action) { case 0: { // Restore lost item //chr.updateTick(slea.readInt()); slea.readInt(); final int itemid = slea.readInt(); q.RestoreLostItem(chr, itemid); break; } case 1: { // Start Quest final int npc = slea.readInt(); if (npc == 0 && quest > 0) { q.forceStart(chr, npc, null); } else if (!q.hasStartScript()) { q.start(chr, npc); } break; } case 2: { // Complete Quest final int npc = slea.readInt(); //chr.updateTick(slea.readInt()); slea.readInt(); if (q.hasEndScript()) { return; } if (slea.available() >= 4) { q.complete(chr, npc, slea.readInt()); } else { q.complete(chr, npc); } // c.getSession().write(CField.completeQuest(c.getPlayer(), quest)); //c.getSession().write(CField.updateQuestInfo(c.getPlayer(), quest, npc, (byte)14)); // 6 = start quest // 7 = unknown error // 8 = equip is full // 9 = not enough mesos // 11 = due to the equipment currently being worn wtf o.o // 12 = you may not posess more than one of this item break; } case 3: { // Forfeit Quest if (GameConstants.canForfeit(q.getId())) { q.forfeit(chr); } else { chr.dropMessage(1, "You may not forfeit this quest."); } break; } case 4: { // Scripted Start Quest final int npc = slea.readInt(); if (chr.hasBlockedInventory()) { if (c.getPlayer().isShowErr()) { c.getPlayer().showInfo("NPC對話", true, "無法進行對話,hasBlockedInventory-" + chr.hasBlockedInventory()); } c.getPlayer().dropMessage(-1, "你當前已經和1個NPC對話了. 如果不是請輸入 @解卡 指令進行解卡。"); return; } //c.getPlayer().updateTick(slea.readInt()); NPCScriptManager.getInstance().startQuest(c, npc, quest); break; } case 5: { // Scripted End Quest final int npc = slea.readInt(); if (chr.hasBlockedInventory()) { if (c.getPlayer().isShowErr()) { c.getPlayer().showInfo("NPC對話", true, "無法進行對話,hasBlockedInventory-" + chr.hasBlockedInventory()); } c.getPlayer().dropMessage(-1, "你當前已經和1個NPC對話了. 如果不是請輸入 @解卡 指令進行解卡。"); return; } //c.getPlayer().updateTick(slea.readInt()); NPCScriptManager.getInstance().endQuest(c, npc, quest, false); // c.getSession().write(EffectPacket.showQuetCompleteEffect()); // chr.getMap().broadcastMessage(chr, EffectPacket.showQuetCompleteEffect(chr.getId()), false); break; } } } @SuppressWarnings("empty-statement") public static final void Storage(LittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { byte mode = slea.readByte(); if (chr == null) { return; } MapleStorage storage = chr.getStorage(); switch (mode) { case 3: {//二次密碼驗證(未完成) /* String secondpw = slea.readMapleAsciiString(); if (c.CheckSecondPassword(secondpw)) { c.getPlayer().setConversation(4); c.getPlayer().getStorage().sendStorage(c, 0); }*/ } case 4: {//取出 byte type = slea.readByte(); byte slot = storage.getSlot(MapleInventoryType.getByType(type), slea.readByte()); Item item = storage.takeOut(slot); if (item != null) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); short flag = item.getFlag(); if (ii.isDropRestricted(item.getItemId())) { if (ItemFlag.KARMA_EQ.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_EQ.getValue())); } else if (ItemFlag.KARMA_USE.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_USE.getValue())); } else if (ItemFlag.KARMA_ACC.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_ACC.getValue())); } else if (ItemFlag.KARMA_ACC_USE.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_ACC_USE.getValue())); } else { c.getSession().write(CWvsContext.enableActions()); return; } } if (ItemFlag.UNTRADABLE.check(flag)) { if (ItemFlag.KARMA_EQ.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_EQ.getValue())); } else if (ItemFlag.KARMA_USE.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_USE.getValue())); } else { c.getSession().write(CWvsContext.enableActions()); return; } } if (ii.isAccountShared(item.getItemId())) { if (ItemFlag.KARMA_ACC.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_ACC.getValue())); } else if (ItemFlag.KARMA_ACC_USE.check(flag)) { item.setFlag((short) (flag - ItemFlag.KARMA_ACC_USE.getValue())); } else { c.getSession().write(CWvsContext.enableActions()); return; } } if (!MapleInventoryManipulator.checkSpace(c, item.getItemId(), item.getQuantity(), item.getOwner())) { storage.store(item); chr.dropMessage(1, "道具欄空間不足。"); } else { MapleInventoryManipulator.addFromDrop(c, item, false); storage.sendTakenOut(c, GameConstants.getInventoryType(item.getItemId())); } } else { c.getSession().write(CWvsContext.enableActions()); } break; } case 5: {//放入倉庫 byte slot = (byte) slea.readShort(); int itemId = slea.readInt(); MapleInventoryType type = GameConstants.getInventoryType(itemId); short quantity = slea.readShort(); MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if (quantity < 1) { return; } if (storage.isFull()) { c.getSession().write(CField.NPCPacket.getStorageFull()); return; } if (chr.getInventory(type).getItem((short) slot) == null) { c.getSession().write(CWvsContext.enableActions()); return; } if (chr.getMeso() < 100L) { chr.dropMessage(1, "You don't have enough mesos to store the item"); } else { Item item = chr.getInventory(type).getItem((short) slot).copy(); if (ItemConstants.類型.寵物(item.getItemId())) { c.getSession().write(CWvsContext.enableActions()); return; } short flag = item.getFlag(); if ((ii.isPickupRestricted(item.getItemId())) && (storage.findById(item.getItemId()) != null)) { c.getSession().write(CWvsContext.enableActions()); return; } if ((item.getItemId() == itemId) && ((item.getQuantity() >= quantity) || ItemConstants.類型.可充值道具(itemId))) { if (ii.isDropRestricted(item.getItemId()) && !ItemFlag.KARMA_EQ.check(flag) && !ItemFlag.KARMA_USE.check(flag) && !ItemFlag.KARMA_ACC.check(flag) && !ItemFlag.KARMA_ACC_USE.check(flag)) { c.getSession().write(CWvsContext.enableActions()); return; } if (ItemFlag.UNTRADABLE.check(flag) && !ItemFlag.KARMA_EQ.check(flag) && !ItemFlag.KARMA_USE.check(flag)) { c.getSession().write(CWvsContext.enableActions()); return; } if (ii.isAccountShared(item.getItemId()) && !ItemFlag.KARMA_ACC.check(flag) && !ItemFlag.KARMA_ACC_USE.check(flag)) { c.getSession().write(CWvsContext.enableActions()); return; } if (ItemConstants.類型.可充值道具(itemId)) { quantity = item.getQuantity(); } chr.gainMeso(-100L, false, false); MapleInventoryManipulator.removeFromSlot(c, type, (short) slot, quantity, false); item.setQuantity(quantity); storage.store(item); } else { return; } } storage.sendStored(c, GameConstants.getInventoryType(itemId)); break; } case 6: storage.arrange(); storage.update(c); break; case 7: {//楓幣存取操作 long meso = slea.readLong(); long storageMesos = storage.getMeso(); long playerMesos = chr.getMeso(); if ((meso > 0L && storageMesos >= meso) || (meso < 0L && playerMesos >= -meso)) { if (meso < 0L && storageMesos - meso > 9999999999999L) {//保管 meso = -(9999999999999L - storageMesos); if (-meso > playerMesos) { return; } } else if (meso > 0L && playerMesos + meso > 99999999999L) {//取出 meso = 99999999999L - playerMesos; if (meso > storageMesos) { return; } } storage.setMeso(storageMesos - meso); chr.gainMeso(meso, false, false); } else { return; } storage.sendMeso(c); break; } case 8: storage.close(); chr.setConversation(0); break; default: System.out.println("未處理的倉庫操作碼 : " + mode); } } public static void NPCMoreTalk(final LittleEndianAccessor slea, final MapleClient c) { final byte lastMsg = slea.readByte(); // 00 (last msg type I think) if (lastMsg == 0x12 && c.getPlayer().hasMapScript()) { byte action = slea.readByte(); if (action != 1) { return; } byte lastbyte = slea.readByte(); // 00 = end chat, 01 == follow if (lastbyte == 0) { c.getSession().write(CWvsContext.enableActions()); } else { switch (c.getPlayer().getMapScript().getLeft()) { case directionInfo: MapScriptMethods.startDirectionInfo(c.getPlayer(), true); break; case onFirstUserEnter: MapScriptMethods.startScript_FirstUser(c, c.getPlayer().getMapScript().getRight()); break; case onUserEnter: MapScriptMethods.startScript_User(c, c.getPlayer().getMapScript().getRight()); break; } // MapScriptMethods.startDirectionInfo(c.getPlayer(), lastMsg == 0x13); // c.getSession().write(CWvsContext.enableActions()); } return; } if (lastMsg == 9 && slea.available() >= 4) { slea.readShort(); } final byte action = slea.readByte(); // 00 = end chat, 01 == follow final NPCConversationManager cm = NPCScriptManager.getInstance().getCM(c); /*if (cm != null && lastMsg == 0x17) { c.getPlayer().handleDemonJob(slea.readInt()); return; }*/ if (cm == null || c.getPlayer().getConversation() == 0 || cm.getLastMsg() != lastMsg) { return; } cm.setLastMsg((byte) -1); if (lastMsg == 1) { NPCScriptManager.getInstance().action(c, action, lastMsg, -1); } else if (lastMsg == 3) { if (action != 0) { cm.setGetText(slea.readMapleAsciiString()); if (cm.getType() == ScriptType.QUEST_START) { NPCScriptManager.getInstance().startQuest(c, action, lastMsg, -1); } else if (cm.getType() == ScriptType.QUEST_END) { NPCScriptManager.getInstance().endQuest(c, action, lastMsg, -1); } else { NPCScriptManager.getInstance().action(c, action, lastMsg, -1); } } else { cm.dispose(); } } else { if (lastMsg == 0x13 && action == 0) { c.getSession().write(CWvsContext.getTopMsg("影片播放失敗。")); } int selection = -1; if (slea.available() >= 4) { selection = slea.readInt(); } else if (slea.available() > 0) { selection = slea.readByte(); } if (lastMsg == 4 && selection == -1) { cm.dispose(); return;//h4x } if (selection >= -1 && action != -1) { if (cm.getType() == ScriptType.QUEST_START) { NPCScriptManager.getInstance().startQuest(c, action, lastMsg, selection); } else if (cm.getType() == ScriptType.QUEST_END) { NPCScriptManager.getInstance().endQuest(c, action, lastMsg, selection); } else { NPCScriptManager.getInstance().action(c, action, lastMsg, selection); } } else { cm.dispose(); } } } public static void DirectionComplete(final LittleEndianAccessor slea, final MapleClient c) { if (c.getPlayer().hasMapScript()) { switch (c.getPlayer().getMapScript().getLeft()) { case directionInfo: MapScriptMethods.startDirectionInfo(c.getPlayer(), true); break; case onFirstUserEnter: MapScriptMethods.startScript_FirstUser(c, c.getPlayer().getMapScript().getRight()); break; case onUserEnter: MapScriptMethods.startScript_User(c, c.getPlayer().getMapScript().getRight()); break; } return; } final NPCConversationManager cm = NPCScriptManager.getInstance().getCM(c); if (cm == null || c.getPlayer().getConversation() == 0) { return; } cm.setLastMsg((byte) -1); if (cm.getType() == ScriptType.QUEST_START) { NPCScriptManager.getInstance().startQuest(c, (byte) 1, (byte) 0, 0); } else if (cm.getType() == ScriptType.QUEST_END) { NPCScriptManager.getInstance().endQuest(c, (byte) 1, (byte) 0, 0); } else { NPCScriptManager.getInstance().action(c, (byte) 1, (byte) 0, 0); } } public static final void repairAll(final MapleClient c) { Equip eq; double rPercentage; int price = 0; Map<String, Integer> eqStats; final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); final Map<Equip, Integer> eqs = new HashMap<>(); final MapleInventoryType[] types = {MapleInventoryType.EQUIP, MapleInventoryType.EQUIPPED}; for (MapleInventoryType type : types) { for (Item item : c.getPlayer().getInventory(type).newList()) { if (item instanceof Equip) { //redundant eq = (Equip) item; if (eq.getDurability() >= 0) { eqStats = ii.getEquipStats(eq.getItemId()); if (eqStats.containsKey("durability") && eqStats.get("durability") > 0 && eq.getDurability() < eqStats.get("durability")) { rPercentage = (100.0 - Math.ceil((eq.getDurability() * 1000.0) / (eqStats.get("durability") * 10.0))); eqs.put(eq, eqStats.get("durability")); price += (int) Math.ceil(rPercentage * ii.getPrice(eq.getItemId()) / (ii.getReqLevel(eq.getItemId()) < 70 ? 100.0 : 1.0)); } } } } } if (eqs.size() <= 0 || c.getPlayer().getMeso() < price) { return; } c.getPlayer().gainMeso(-price, true); Equip ez; for (Entry<Equip, Integer> eqqz : eqs.entrySet()) { ez = eqqz.getKey(); ez.setDurability(eqqz.getValue()); c.getPlayer().forceReAddItem(ez.copy(), ez.getPosition() < 0 ? MapleInventoryType.EQUIPPED : MapleInventoryType.EQUIP); } } public static final void repair(final LittleEndianAccessor slea, final MapleClient c) { if (slea.available() < 4) { //leafre for now return; } final int position = slea.readInt(); //who knows why this is a int final MapleInventoryType type = position < 0 ? MapleInventoryType.EQUIPPED : MapleInventoryType.EQUIP; final Item item = c.getPlayer().getInventory(type).getItem((byte) position); if (item == null) { return; } final Equip eq = (Equip) item; final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); final Map<String, Integer> eqStats = ii.getEquipStats(item.getItemId()); if (eq.getDurability() < 0 || !eqStats.containsKey("durability") || eqStats.get("durability") <= 0 || eq.getDurability() >= eqStats.get("durability")) { return; } final double rPercentage = (100.0 - Math.ceil((eq.getDurability() * 1000.0) / (eqStats.get("durability") * 10.0))); //drpq level 105 weapons - ~420k per %; 2k per durability point //explorer level 30 weapons - ~10 mesos per % final int price = (int) Math.ceil(rPercentage * ii.getPrice(eq.getItemId()) / (ii.getReqLevel(eq.getItemId()) < 70 ? 100.0 : 1.0)); // / 100 for level 30? //TODO: need more data on calculating off client if (c.getPlayer().getMeso() < price) { return; } c.getPlayer().gainMeso(-price, false); eq.setDurability(eqStats.get("durability")); c.getPlayer().forceReAddItem(eq.copy(), type); } public static final void UpdateQuest(final LittleEndianAccessor slea, final MapleClient c) { final MapleQuest quest = MapleQuest.getInstance(slea.readShort()); if (quest != null) { c.getPlayer().updateQuest(c.getPlayer().getQuest(quest), true); } } public static final void UseItemQuest(final LittleEndianAccessor slea, final MapleClient c) { final short slot = slea.readShort(); final int itemId = slea.readInt(); final Item item = c.getPlayer().getInventory(MapleInventoryType.ETC).getItem(slot); final int qid = slea.readInt(); final MapleQuest quest = MapleQuest.getInstance(qid); final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); Pair<Integer, List<Integer>> questItemInfo = null; boolean found = false; for (Item i : c.getPlayer().getInventory(MapleInventoryType.ETC)) { if (i.getItemId() / 10000 == 422) { questItemInfo = ii.questItemInfo(i.getItemId()); if (questItemInfo != null && questItemInfo.getLeft() == qid && questItemInfo.getRight() != null && questItemInfo.getRight().contains(itemId)) { found = true; break; //i believe it's any order } } } if (quest != null && found && item != null && item.getQuantity() > 0 && item.getItemId() == itemId) { final int newData = slea.readInt(); final MapleQuestStatus stats = c.getPlayer().getQuestNoAdd(quest); if (stats != null && stats.getStatus() == 1) { stats.setCustomData(String.valueOf(newData)); c.getPlayer().updateQuest(stats, true); MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.ETC, slot, (short) 1, false); } } } public static final void RPSGame(LittleEndianAccessor slea, MapleClient c) { if ((slea.available() == 0L) || (c.getPlayer() == null) || (c.getPlayer().getMap() == null) || (!c.getPlayer().getMap().containsNPC(9000019))) { if ((c.getPlayer() != null) && (c.getPlayer().getRPS() != null)) { c.getPlayer().getRPS().dispose(c); } return; } byte mode = slea.readByte(); switch (mode) { case 0: case 5: if (c.getPlayer().getRPS() != null) { c.getPlayer().getRPS().reward(c); } if (c.getPlayer().getMeso() >= 1000L) { c.getPlayer().setRPS(new RockPaperScissors(c, mode)); } else { c.getSession().write(CField.getRPSMode((byte) 8, -1, -1, -1)); } break; case 1: if ((c.getPlayer().getRPS() == null) || (!c.getPlayer().getRPS().answer(c, slea.readByte()))) { c.getSession().write(CField.getRPSMode((byte) 13, -1, -1, -1)); } break; case 2: if ((c.getPlayer().getRPS() == null) || (!c.getPlayer().getRPS().timeOut(c))) { c.getSession().write(CField.getRPSMode((byte) 13, -1, -1, -1)); } break; case 3: if ((c.getPlayer().getRPS() == null) || (!c.getPlayer().getRPS().nextRound(c))) { c.getSession().write(CField.getRPSMode((byte) 13, -1, -1, -1)); } break; case 4: if (c.getPlayer().getRPS() != null) { c.getPlayer().getRPS().dispose(c); } else { c.getSession().write(CField.getRPSMode((byte) 13, -1, -1, -1)); } break; } } public static void OpenQuickMoveNpc(final LittleEndianAccessor slea, final MapleClient c) { final int npcid = slea.readInt(); if (c.getPlayer().hasBlockedInventory() || c.getPlayer().isInBlockedMap() || c.getPlayer().getLevel() < 10) { c.getPlayer().dropMessage(-1, "你當前已經和1個NPC對話了. 如果不是請輸入 @解卡 指令進行解卡。"); return; } int npcId = -1; for (QuickMove qm : QuickMove.values()) { if (qm.getMap() == c.getPlayer().getMapId()) { List<QuickMove.QuickMoveNPC> qmn = new LinkedList(); long npcs = qm.getNPCFlag(); for (QuickMove.QuickMoveNPC npc : QuickMove.QuickMoveNPC.values()) { if ((npcs & npc.getValue()) != 0 && npc.getId() == npcid) { npcId = npcid; break; } } } } if (npcId == -1 && QuickMove.GLOBAL_NPC != 0 && !GameConstants.isBossMap(c.getPlayer().getMapId()) && !GameConstants.isTutorialMap(c.getPlayer().getMapId())) { for (QuickMove.QuickMoveNPC npc : QuickMove.QuickMoveNPC.values()) { if ((QuickMove.GLOBAL_NPC & npc.getValue()) != 0 && npc.getId() == npcid) { npcId = npcid; break; } } } if (npcId == -1) { System.err.println("未找到QuickMove的NPC:" + npcId); return; } final MapleNPC npc = MapleLifeFactory.getNPC(npcId); if (npc.hasShop()) { c.getPlayer().setConversation(1); npc.sendShop(c); } else { NPCScriptManager.getInstance().start(c, npcId, null); } } public static void OpenQuickMoveSpecial(final LittleEndianAccessor slea, MapleClient c) { final int selection = slea.readInt(); if (c.getPlayer().hasBlockedInventory() || c.getPlayer().isInBlockedMap() || c.getPlayer().getLevel() < 10) { return; } QuickMove.QuickMoveNPC quickMove = null; for (QuickMove qm : QuickMove.values()) { if (qm.getMap() == c.getPlayer().getMapId()) { long npcs = qm.getNPCFlag(); int i = 0; for (QuickMove.QuickMoveNPC npc : QuickMove.QuickMoveNPC.values()) { if (!npc.show() || (npcs & npc.getValue()) == 0) { continue; } if (selection == i++) { quickMove = npc; break; } } break; } } if (quickMove == null && QuickMove.GLOBAL_NPC != 0 && !GameConstants.isBossMap(c.getPlayer().getMapId()) && !GameConstants.isTutorialMap(c.getPlayer().getMapId())) { int i = 0; for (QuickMove.QuickMoveNPC npc : QuickMove.QuickMoveNPC.values()) { if (!npc.show() || (QuickMove.GLOBAL_NPC & npc.getValue()) == 0) { continue; } if (selection == i++) { quickMove = npc; break; } } } if (quickMove == null) { System.err.println("未找到QuickMove動作, 選項:" + selection); return; } int npcId = 0; String special = null; switch (quickMove) { default: System.err.println("未處理QuickMove動作, 類型:" + quickMove.getType()); } if (npcId > 0) { final MapleNPC npc = MapleLifeFactory.getNPC(npcId); if (npc.hasShop()) { c.getPlayer().setConversation(1); npc.sendShop(c); } else { NPCScriptManager.getInstance().start(c, npcId, null); } } } }