using Server.MirObjects; using System.Text.RegularExpressions; using Server.MirEnvir; namespace Server.MirDatabase { public class QuestInfo { protected static Envir Envir { get { return Envir.Main; } } protected static Envir EditEnvir { get { return Envir.Edit; } } protected static MessageQueue MessageQueue { get { return MessageQueue.Instance; } } public int Index; public uint NpcIndex; public NPCInfo NpcInfo; private uint _finishNpcIndex; public uint FinishNpcIndex { get { return _finishNpcIndex == 0 ? NpcIndex : _finishNpcIndex; } set { _finishNpcIndex = value; } } public NPCObject FinishNPC { get { return Envir.NPCs.Single(x => x.ObjectID == FinishNpcIndex); } } public string Name = string.Empty, Group = string.Empty, FileName = string.Empty, GotoMessage = string.Empty, KillMessage = string.Empty, ItemMessage = string.Empty, FlagMessage = string.Empty; public List Description = new List(); public List TaskDescription = new List(); public List ReturnDescription = new List(); public List CompletionDescription = new List(); public int RequiredMinLevel, RequiredMaxLevel, RequiredQuest; public RequiredClass RequiredClass = RequiredClass.None; public QuestType Type; public int TimeLimitInSeconds = 0; public List CarryItems = new List(); public List KillTasks = new List(); public List ItemTasks = new List(); public List FlagTasks = new List(); //TODO: ZoneTasks //TODO: EscortTasks public uint GoldReward; public uint ExpReward; public uint CreditReward; public List FixedRewards = new List(); public List SelectRewards = new List(); private Regex _regexMessage = new Regex("\"([^\"]*)\""); public QuestInfo() { } public QuestInfo(BinaryReader reader) { Index = reader.ReadInt32(); Name = reader.ReadString(); Group = reader.ReadString(); FileName = reader.ReadString(); RequiredMinLevel = reader.ReadInt32(); RequiredMaxLevel = reader.ReadInt32(); if (RequiredMaxLevel == 0) RequiredMaxLevel = ushort.MaxValue; RequiredQuest = reader.ReadInt32(); RequiredClass = (RequiredClass)reader.ReadByte(); Type = (QuestType)reader.ReadByte(); GotoMessage = reader.ReadString(); KillMessage = reader.ReadString(); ItemMessage = reader.ReadString(); FlagMessage = reader.ReadString(); if (Envir.LoadVersion > 90) { TimeLimitInSeconds = reader.ReadInt32(); } LoadInfo(); } public void Save(BinaryWriter writer) { writer.Write(Index); writer.Write(Name); writer.Write(Group); writer.Write(FileName); writer.Write(RequiredMinLevel); writer.Write(RequiredMaxLevel); writer.Write(RequiredQuest); writer.Write((byte)RequiredClass); writer.Write((byte)Type); writer.Write(GotoMessage); writer.Write(KillMessage); writer.Write(ItemMessage); writer.Write(FlagMessage); writer.Write(TimeLimitInSeconds); } public void LoadInfo(bool clear = false) { if (clear) ClearInfo(); if (!Directory.Exists(Settings.QuestPath)) return; string fileName = Path.Combine(Settings.QuestPath, FileName + ".txt"); if (File.Exists(fileName)) { List lines = File.ReadAllLines(fileName).ToList(); ParseFile(lines); } else MessageQueue.Enqueue(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.FileNotFoundQuest), fileName, Name)); } public void ClearInfo() { Description.Clear(); KillTasks = new List(); ItemTasks = new List(); FlagTasks = new List(); FixedRewards = new List(); SelectRewards = new List(); ExpReward = 0; GoldReward = 0; CreditReward = 0; } public void ParseFile(List lines) { const string descriptionCollectKey = "[@DESCRIPTION]", descriptionTaskKey = "[@TASKDESCRIPTION]", descriptionReturnKey = "[@RETURNDESCRIPTION]", descriptionCompletionKey = "[@COMPLETION]", carryItemsKey = "[@CARRYITEMS]", killTasksKey = "[@KILLTASKS]", itemTasksKey = "[@ITEMTASKS]", flagTasksKey = "[@FLAGTASKS]", fixedRewardsKey = "[@FIXEDREWARDS]", selectRewardsKey = "[@SELECTREWARDS]", expRewardKey = "[@EXPREWARD]", goldRewardKey = "[@GOLDREWARD]", creditRewardKey = "[@CREDITREWARD]"; List headers = new List { descriptionCollectKey, descriptionTaskKey, descriptionCompletionKey, carryItemsKey, killTasksKey, itemTasksKey, flagTasksKey, fixedRewardsKey, selectRewardsKey, expRewardKey, goldRewardKey, creditRewardKey, descriptionReturnKey }; int currentHeader = 0; while (currentHeader < headers.Count) { for (int i = 0; i < lines.Count; i++) { string line = lines[i].ToUpper(); if (line != headers[currentHeader].ToUpper()) continue; for (int j = i + 1; j < lines.Count; j++) { string innerLine = lines[j]; if (innerLine.StartsWith("[") || innerLine.StartsWith("//")) break; if (string.IsNullOrEmpty(lines[j])) continue; switch (line) { case descriptionCollectKey: Description.Add(innerLine); break; case descriptionTaskKey: TaskDescription.Add(innerLine); break; case descriptionReturnKey: ReturnDescription.Add(innerLine); break; case descriptionCompletionKey: CompletionDescription.Add(innerLine); break; case carryItemsKey: QuestItemTask t = ParseItem(innerLine); if (t != null) CarryItems.Add(t); break; case killTasksKey: QuestKillTask t1 = ParseKill(innerLine); if (t1 != null) KillTasks.Add(t1); break; case itemTasksKey: QuestItemTask t2 = ParseItem(innerLine); if (t2 != null) ItemTasks.Add(t2); break; case flagTasksKey: QuestFlagTask t3 = ParseFlag(innerLine); if (t3 != null) FlagTasks.Add(t3); break; case fixedRewardsKey: { ParseReward(FixedRewards, innerLine); break; } case selectRewardsKey: { ParseReward(SelectRewards, innerLine); break; } case expRewardKey: uint.TryParse(innerLine, out ExpReward); break; case goldRewardKey: uint.TryParse(innerLine, out GoldReward); break; case creditRewardKey: uint.TryParse(innerLine, out CreditReward); break; } } } currentHeader++; } } public void ParseReward(List list, string line) { if (line.Length < 1) return; string[] split = line.Split(' '); ushort count = 1; if (split.Length > 1) ushort.TryParse(split[1], out count); ItemInfo mInfo = Envir.GetItemInfo(split[0]); if (mInfo == null) { mInfo = Envir.GetItemInfo(split[0] + "(M)"); if (mInfo != null) list.Add(new QuestItemReward() { Item = mInfo, Count = count }); mInfo = Envir.GetItemInfo(split[0] + "(F)"); if (mInfo != null) list.Add(new QuestItemReward() { Item = mInfo, Count = count }); } else { list.Add(new QuestItemReward() { Item = mInfo, Count = count }); } } public QuestKillTask ParseKill(string line) { if (line.Length < 1) return null; string[] split = line.Split(' '); int count = 1; string message = ""; MonsterInfo mInfo = Envir.GetMonsterInfo(split[0]); if (split.Length > 1) int.TryParse(split[1], out count); var match = _regexMessage.Match(line); if (match.Success) { message = match.Groups[1].Captures[0].Value; } return mInfo == null ? null : new QuestKillTask() { Monster = mInfo, Count = count, Message = message }; } public QuestItemTask ParseItem(string line) { if (line.Length < 1) return null; string[] split = line.Split(' '); ushort count = 1; string message = ""; ItemInfo mInfo = Envir.GetItemInfo(split[0]); if (split.Length > 1) ushort.TryParse(split[1], out count); var match = _regexMessage.Match(line); if (match.Success) { message = match.Groups[1].Captures[0].Value; } //if (mInfo.StackSize <= 1) //{ // //recursively add item if cant stack??? //} return mInfo == null ? null : new QuestItemTask { Item = mInfo, Count = count, Message = message }; } public QuestFlagTask ParseFlag(string line) { if (line.Length < 1) return null; string[] split = line.Split(' '); int number = -1; string message = ""; int.TryParse(split[0], out number); if (number < 0 || number > Globals.FlagIndexCount - 1000) return null; var match = _regexMessage.Match(line); if (match.Success) { message = match.Groups[1].Captures[0].Value; } return new QuestFlagTask { Number = number, Message = message }; } public bool CanAccept(PlayerObject player) { if (RequiredMinLevel > player.Level || RequiredMaxLevel < player.Level) return false; if (RequiredQuest > 0 && !player.CompletedQuests.Contains(RequiredQuest)) return false; switch (player.Class) { case MirClass.Warrior: if (!RequiredClass.HasFlag(RequiredClass.Warrior)) return false; break; case MirClass.Wizard: if (!RequiredClass.HasFlag(RequiredClass.Wizard)) return false; break; case MirClass.Taoist: if (!RequiredClass.HasFlag(RequiredClass.Taoist)) return false; break; case MirClass.Assassin: if (!RequiredClass.HasFlag(RequiredClass.Assassin)) return false; break; case MirClass.Archer: if (!RequiredClass.HasFlag(RequiredClass.Archer)) return false; break; } return true; } public ClientQuestInfo CreateClientQuestInfo(PlayerObject viewer = null) { var description = LinkFormatter.ReplacePlaceholders(Description, (type, index) => EnsureLinkInfo(viewer, type, index)) ?? new List(); var taskDescription = LinkFormatter.ReplacePlaceholders(TaskDescription, (type, index) => EnsureLinkInfo(viewer, type, index)) ?? new List(); var returnDescription = LinkFormatter.ReplacePlaceholders(ReturnDescription, (type, index) => EnsureLinkInfo(viewer, type, index)) ?? new List(); var completionDescription = LinkFormatter.ReplacePlaceholders(CompletionDescription, (type, index) => EnsureLinkInfo(viewer, type, index)) ?? new List(); return new ClientQuestInfo { Index = Index, NPCIndex = NpcIndex, FinishNPCIndex = FinishNpcIndex, Name = Name, Group = Group, Description = description, TaskDescription = taskDescription, ReturnDescription = returnDescription, CompletionDescription = completionDescription, MinLevelNeeded = RequiredMinLevel, MaxLevelNeeded = RequiredMaxLevel, ClassNeeded = RequiredClass, QuestNeeded = RequiredQuest, Type = Type, TimeLimitInSeconds = TimeLimitInSeconds, RewardGold = GoldReward, RewardExp = ExpReward, RewardCredit = CreditReward, RewardsFixedItem = FixedRewards, RewardsSelectItem = SelectRewards }; } private void EnsureLinkInfo(PlayerObject viewer, string linkType, int index) { if (viewer?.Connection == null) return; switch (linkType) { case "ITEM": var itemInfo = Envir.GetItemInfo(index); if (itemInfo != null) viewer.Connection.CheckItemInfo(itemInfo); break; case "MONSTER": viewer.Connection.CheckMonsterInfo(index); break; case "NPC": viewer.Connection.CheckNPCInfo(index); break; } } public static void FromText(string text) { string[] data = text.Split(new[] { ',' }); if (data.Length < 10) return; QuestInfo info; bool isNew = false; if (!int.TryParse(data[0], out var index)) { index = -1; } if (index == -1 || (info = EditEnvir.QuestInfoList.FirstOrDefault(it => it.Index == index)) == null) { info = new QuestInfo() { Index = ++EditEnvir.QuestIndex }; isNew = true; } info.Name = data[1]; info.Group = data[2]; byte temp; byte.TryParse(data[3], out temp); info.Type = (QuestType)temp; info.FileName = data[4]; info.GotoMessage = data[5]; info.KillMessage = data[6]; info.ItemMessage = data[7]; info.FlagMessage = data[8]; int.TryParse(data[9], out info.RequiredMinLevel); int.TryParse(data[10], out info.RequiredMaxLevel); int.TryParse(data[11], out info.RequiredQuest); byte.TryParse(data[12], out temp); info.RequiredClass = (RequiredClass)temp; if (isNew) EditEnvir.QuestInfoList.Add(info); } public string ToText() { return string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12}", Index, Name, Group, (byte)Type, FileName, GotoMessage, KillMessage, ItemMessage, FlagMessage, RequiredMinLevel, RequiredMaxLevel, RequiredQuest, (byte)RequiredClass); } public override string ToString() { return string.Format("{0}: {1}", Index, Name); } } public class QuestKillTask { public MonsterInfo Monster; public int Count; public string Message; } public class QuestItemTask { public ItemInfo Item; public ushort Count; public string Message; } public class QuestFlagTask { public int Number; public string Message; } }