package server.quest; import client.MapleCharacter; import client.MapleQuestStatus; import client.MapleStat; import client.Skill; import client.SkillEntry; import client.SkillFactory; import client.inventory.InventoryException; import client.inventory.MapleInventoryType; import constants.GameConstants; import constants.ItemConstants; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import server.MapleInventoryManipulator; import server.MapleItemInformationProvider; import server.RandomRewards; import server.Randomizer; import tools.FileoutputUtil; import tools.MaplePacketCreator; import tools.Pair; import tools.Triple; public class MapleQuestAction implements Serializable { private static final long serialVersionUID = 9179541993413738569L; private MapleQuestActionType type; private MapleQuest quest; private int intStore = 0; private List<Integer> applicableJobs = new ArrayList(); private List<QuestItem> items = null; private List<Triple<Integer, Integer, Integer>> skill = null; private List<Pair<Integer, Integer>> state = null; public MapleQuestAction(MapleQuestActionType type, ResultSet rse, MapleQuest quest, PreparedStatement psq, PreparedStatement psi) throws SQLException { this.type = type; this.quest = quest; this.intStore = rse.getInt("intStore"); String[] jobs = rse.getString("applicableJobs").split(", "); if ((jobs.length <= 0) && (rse.getString("applicableJobs").length() > 0)) { this.applicableJobs.add(Integer.parseInt(rse.getString("applicableJobs"))); } for (String j : jobs) { if (j.length() > 0) { this.applicableJobs.add(Integer.parseInt(j)); } } ResultSet rs; switch (type) { case item: this.items = new ArrayList(); psi.setInt(1, rse.getInt("uniqueid")); rs = psi.executeQuery(); while (rs.next()) { this.items.add(new QuestItem(rs.getInt("itemid"), rs.getInt("count"), rs.getInt("period"), rs.getInt("gender"), rs.getInt("job"), rs.getInt("jobEx"), rs.getInt("prop"))); } rs.close(); break; case quest: this.state = new ArrayList(); psq.setInt(1, rse.getInt("uniqueid")); rs = psq.executeQuery(); while (rs.next()) { this.state.add(new Pair(rs.getInt("quest"), rs.getInt("state"))); } rs.close(); break; } } private static boolean canGetItem(QuestItem item, MapleCharacter chr) { if ((item.gender != 2) && (item.gender >= 0) && (item.gender != chr.getGender())) { return false; } if (item.job > 0) { List code = getJobBy5ByteEncoding(item.job); boolean jobFound = false; for (Iterator i$ = code.iterator(); i$.hasNext();) { int codec = ((Integer) i$.next()); if (codec / 100 == chr.getJob() / 100) { jobFound = true; break; } } Iterator i$; if ((!jobFound) && (item.jobEx > 0)) { List codeEx = getJobBySimpleEncoding(item.jobEx); for (i$ = codeEx.iterator(); i$.hasNext();) { int codec = ((Integer) i$.next()); if (codec / 100 % 10 == chr.getJob() / 100 % 10) { jobFound = true; break; } } } return jobFound; } return true; } public boolean RestoreLostItem(MapleCharacter chr, int itemid) { if (this.type == MapleQuestActionType.item) { for (QuestItem item : this.items) { if (item.itemid == itemid) { if (!chr.haveItem(item.itemid, item.count, true, false)) { MapleInventoryManipulator.addById(chr.getClient(), item.itemid, (short) item.count, "Obtained from quest (Restored) " + this.quest.getId() + " on " + FileoutputUtil.CurrentReadable_Date()); } return true; } } } return false; } /** * 开始执行任务 * @param chr * @param extSelection */ public void runStart(MapleCharacter chr, Integer extSelection) { MapleQuestStatus status; int selection; int extNum; switch (type) { case exp: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } chr.gainExp(this.intStore * GameConstants.getExpRate_Quest(chr.getLevel()) * chr.getStat().questBonus , true, true, true); break; case item: Map props = new HashMap(); for (QuestItem item : this.items) { if ((item.prop > 0) && (canGetItem(item, chr))) { for (int i = 0; i < item.prop; i++) { props.put(props.size(), item.itemid); } } } selection = 0; extNum = 0; if (props.size() > 0) { selection = ((Integer) props.get(Randomizer.nextInt(props.size()))); } for (QuestItem item : this.items) { if (!canGetItem(item, chr)) { continue; } int id = item.itemid; if ((item.prop != -2) && (item.prop == -1 ? (extSelection != null) || (extSelection != extNum++) : id != selection)) { continue; } short count = (short) item.count; if (count < 0) { try { MapleInventoryManipulator.removeById(chr.getClient(), ItemConstants.getInventoryType(id), id, count * -1, true, false); } catch (InventoryException ie) { System.err.println("[h4x] Completing a quest without meeting the requirements" + ie); } chr.getClient().getSession().write(MaplePacketCreator.getShowItemGain(id, count, true)); } else { int period = item.period / 1440; String name = MapleItemInformationProvider.getInstance().getName(id); if ((id / 10000 == 114) && (name != null) && (name.length() > 0)) { String msg = "恭喜您获得勋章 <" + name + ">"; chr.dropMessage(-1, msg); chr.dropMessage(5, msg); } MapleInventoryManipulator.addById(chr.getClient(), id, count, "", null, period, "任务获得 " + this.quest.getId() + " 时间: " + FileoutputUtil.CurrentReadable_Date()); chr.getClient().getSession().write(MaplePacketCreator.getShowItemGain(id, count, true)); } } break; case nextQuest: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } chr.getClient().getSession().write(MaplePacketCreator.updateQuestFinish(this.quest.getId(), status.getNpc(), this.intStore)); break; case money: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } chr.gainMeso(this.intStore, true, true); break; case quest: for (Pair q : this.state) { chr.updateQuest(new MapleQuestStatus(MapleQuest.getInstance(((Integer) q.left)), ((Integer) q.right))); } break; case skill: Map list = new HashMap(); for (Triple skills : this.skill) { int skillid = ((Integer) skills.left); int skillLevel = ((Integer) skills.mid); int masterLevel = ((Integer) skills.right); Skill skillObject = SkillFactory.getSkill(skillid); boolean found = false; for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) { int applicableJob = ((Integer) i$.next()); if (chr.getJob() == applicableJob) { found = true; break; } } if (found) { list.put(skillObject, new SkillEntry((byte) Math.max(skillLevel, chr.getSkillLevel(skillObject)), (byte) Math.max(masterLevel, chr.getMasterLevel(skillObject)), SkillFactory.getDefaultSExpiry(skillObject))); } } chr.changeSkillsLevel(list); break; case buffItemID: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } int tobuff = this.intStore; if (tobuff <= 0) { break; } MapleItemInformationProvider.getInstance().getItemEffect(tobuff).applyTo(chr); break; case infoNumber: break; case sp: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } int sp_val = this.intStore; if (this.applicableJobs.size() > 0) { int finalJob = 0; for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) { int job_val = ((Integer) i$.next()); if ((chr.getJob() >= job_val) && (job_val > finalJob)) { finalJob = job_val; } } if (finalJob == 0) { chr.gainSP(sp_val); } else { chr.gainSP(sp_val, GameConstants.getSkillBookByJob(finalJob)); } } else { chr.gainSP(sp_val); } break; case charmEXP: case charismaEXP: case craftEXP: case insightEXP: case senseEXP: case willEXP: status = chr.getQuest(this.quest); if (status.getForfeited() > 0) { break; } break; } } public boolean checkEnd(MapleCharacter chr, Integer extSelection) { switch (this.type) { case item: Map props = new HashMap(); for (QuestItem item : this.items) { if ((item.prop > 0) && (canGetItem(item, chr))) { for (int i = 0; i < item.prop; i++) { props.put(props.size(), item.itemid); } } } int selection = 0; int extNum = 0; if (props.size() > 0) { selection = ((Integer) props.get(Randomizer.nextInt(props.size()))); } byte eq = 0; byte use = 0; byte setup = 0; byte etc = 0; byte cash = 0; for (QuestItem item : this.items) { if (!canGetItem(item, chr)) { continue; } int id = item.itemid; if ((item.prop != -2) && (item.prop == -1 ? (extSelection != null) || (extSelection != extNum++) : id != selection)) { continue; } short count = (short) item.count; if (count < 0) { if (!chr.haveItem(id, count, false, true)) { chr.dropMessage(1, "您的任务道具不够,还不能完成任务."); return false; } } else { if ((MapleItemInformationProvider.getInstance().isPickupRestricted(id)) && (chr.haveItem(id, 1, true, false))) { chr.dropMessage(1, "You have this item already: " + MapleItemInformationProvider.getInstance().getName(id)); return false; } switch (ItemConstants.getInventoryType(id)) { case EQUIP: eq++; break; case USE: use++; break; case SETUP: setup++; break; case ETC: etc++; break; case CASH: cash++; break; } } } if (chr.getInventory(MapleInventoryType.EQUIP).getNumFreeSlot() < eq) { chr.dropMessage(1, "装备栏空间不足."); return false; } if (chr.getInventory(MapleInventoryType.USE).getNumFreeSlot() < use) { chr.dropMessage(1, "消耗栏空间不足."); return false; } if (chr.getInventory(MapleInventoryType.SETUP).getNumFreeSlot() < setup) { chr.dropMessage(1, "设置栏空间不足."); return false; } if (chr.getInventory(MapleInventoryType.ETC).getNumFreeSlot() < etc) { chr.dropMessage(1, "其他栏空间不足."); return false; } if (chr.getInventory(MapleInventoryType.CASH).getNumFreeSlot() < cash) { chr.dropMessage(1, "特殊栏空间不足."); return false; } return true; case money: int meso = this.intStore; if (chr.getMeso() + meso < 0) { chr.dropMessage(1, "携带金币数量已达限制."); return false; } if ((meso < 0) && (chr.getMeso() < Math.abs(meso))) { chr.dropMessage(1, "金币不足."); return false; } return true; } return true; } public void runEnd(MapleCharacter chr, Integer extSelection) { int selection; int extNum; switch (type) { case exp: chr.gainExp(this.intStore * GameConstants.getExpRate_Quest(chr.getLevel()) * chr.getStat().questBonus, true, true, true); break; case item: Map props = new HashMap(); for (QuestItem item : this.items) { if ((item.prop > 0) && (canGetItem(item, chr))) { for (int i = 0; i < item.prop; i++) { props.put(props.size(), item.itemid); } } } selection = 0; extNum = 0; if (props.size() > 0) { selection = ((Integer) props.get(Randomizer.nextInt(props.size()))); } for (QuestItem item : this.items) { if (!canGetItem(item, chr)) { continue; } int id = item.itemid; if ((item.prop != -2) && (item.prop == -1 ? (extSelection != null) || (extSelection != extNum++) : id != selection)) { continue; } short count = (short) item.count; if (count < 0) { MapleInventoryManipulator.removeById(chr.getClient(), ItemConstants.getInventoryType(id), id, count * -1, true, false); chr.getClient().getSession().write(MaplePacketCreator.getShowItemGain(id, count, true)); } else { int period = item.period / 1440; String name = MapleItemInformationProvider.getInstance().getName(id); if ((id / 10000 == 114) && (name != null) && (name.length() > 0)) { String msg = "你获得了勋章 <" + name + ">"; chr.dropMessage(-1, msg); chr.dropMessage(5, msg); } MapleInventoryManipulator.addById(chr.getClient(), id, count, "", null, period, "任务获得 " + this.quest.getId() + " 时间: " + FileoutputUtil.CurrentReadable_Date()); chr.getClient().getSession().write(MaplePacketCreator.getShowItemGain(id, count, true)); } } break; case nextQuest: chr.getClient().getSession().write(MaplePacketCreator.updateQuestFinish(this.quest.getId(), chr.getQuest(this.quest).getNpc(), this.intStore)); break; case money: chr.gainMeso(this.intStore, true, true); break; case quest: for (Pair q : this.state) { chr.updateQuest(new MapleQuestStatus(MapleQuest.getInstance(((Integer) q.left)), ((Integer) q.right))); } break; case skill: Map list = new HashMap(); for (Triple skills : this.skill) { int skillid = ((Integer) skills.left); int skillLevel = ((Integer) skills.mid); int masterLevel = ((Integer) skills.right); Skill skillObject = SkillFactory.getSkill(skillid); boolean found = false; for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) { int applicableJob = ((Integer) i$.next()); if (chr.getJob() == applicableJob) { found = true; break; } } if (found) { list.put(skillObject, new SkillEntry((byte) Math.max(skillLevel, chr.getSkillLevel(skillObject)), (byte) Math.max(masterLevel, chr.getMasterLevel(skillObject)), SkillFactory.getDefaultSExpiry(skillObject))); } } chr.changeSkillsLevel(list); break; case buffItemID: int tobuff = this.intStore; if (tobuff <= 0) { break; } MapleItemInformationProvider.getInstance().getItemEffect(tobuff).applyTo(chr); break; case infoNumber: break; case sp: int sp_val = this.intStore; if (this.applicableJobs.size() > 0) { int finalJob = 0; for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) { int job_val = ((Integer) i$.next()); if ((chr.getJob() >= job_val) && (job_val > finalJob)) { finalJob = job_val; } } if (finalJob == 0) { chr.gainSP(sp_val); } else { chr.gainSP(sp_val, GameConstants.getSkillBookByJob(finalJob)); } } else { chr.gainSP(sp_val); } break; case charmEXP: case charismaEXP: case craftEXP: case insightEXP: case senseEXP: case willEXP: break; } } private static List<Integer> getJobBy5ByteEncoding(int encoded) { List ret = new ArrayList(); if ((encoded & 0x1) != 0) { ret.add(0); } if ((encoded & 0x2) != 0) { ret.add(100); } if ((encoded & 0x4) != 0) { ret.add(200); } if ((encoded & 0x8) != 0) { ret.add(300); } if ((encoded & 0x10) != 0) { ret.add(400); } if ((encoded & 0x20) != 0) { ret.add(500); } if ((encoded & 0x400) != 0) { ret.add(1000); } if ((encoded & 0x800) != 0) { ret.add(1100); } if ((encoded & 0x1000) != 0) { ret.add(1200); } if ((encoded & 0x2000) != 0) { ret.add(1300); } if ((encoded & 0x4000) != 0) { ret.add(1400); } if ((encoded & 0x8000) != 0) { ret.add(1500); } if ((encoded & 0x20000) != 0) { ret.add(2001); ret.add(2200); } if ((encoded & 0x100000) != 0) { ret.add(2000); ret.add(2001); } if ((encoded & 0x200000) != 0) { ret.add(2100); } if ((encoded & 0x400000) != 0) { ret.add(2001); ret.add(2200); } if ((encoded & 0x40000000) != 0) { ret.add(3000); ret.add(3200); ret.add(3300); ret.add(3500); } return ret; } private static List<Integer> getJobBySimpleEncoding(int encoded) { List ret = new ArrayList(); if ((encoded & 0x1) != 0) { ret.add(200); } if ((encoded & 0x2) != 0) { ret.add(300); } if ((encoded & 0x4) != 0) { ret.add(400); } if ((encoded & 0x8) != 0) { ret.add(500); } return ret; } public MapleQuestActionType getType() { return this.type; } @Override public String toString() { return this.type.toString(); } public List<Triple<Integer, Integer, Integer>> getSkills() { return this.skill; } public List<QuestItem> getItems() { return this.items; } public static class QuestItem { public int itemid; public int count; public int period; public int gender; public int job; public int jobEx; public int prop; public QuestItem(int itemid, int count, int period, int gender, int job, int jobEx, int prop) { if (RandomRewards.getTenPercent().contains(itemid)) { count += Randomizer.nextInt(3); } this.itemid = itemid; this.count = count; this.period = period; this.gender = gender; this.job = job; this.jobEx = jobEx; this.prop = prop; } } }