/// <summary> /// /// </summary> /// <param name="entry"></param> /// <returns></returns> private static ScriptMetadata GetScript(DictionaryEntry entry) { if (!(entry.Key is string fileName)) { return(null); } var version = GetVersionFromFileName(fileName); if (version == null) { return(null); } if (!(entry.Value is string script)) { return(null); } if (string.IsNullOrEmpty(script)) { return(null); } var scriptMetadata = new ScriptMetadata(); scriptMetadata.FileName = fileName; scriptMetadata.VersionString = version.ToString(); scriptMetadata.Version = version; scriptMetadata.ScriptText = script; return(scriptMetadata); }
public static void ExcessCatalystError(GameSession session, ItemEnchant itemEnchant) { int npcId = itemEnchant.Type switch { EnchantType.Ophelia => 11000508, _ => 11000510 }; ScriptMetadata scriptMetadata = ScriptMetadataStorage.GetNpcScriptMetadata(npcId); NpcScript npcScript = scriptMetadata?.NpcScripts.FirstOrDefault(x => x.Id == 31); if (npcScript is null) { return; } Script script = ScriptLoader.GetScript($"Npcs/{npcId}", session); DynValue excessCatalystFunction = script.RunFunction("getExcessCatalystEventId"); if (excessCatalystFunction is null) { return; } int eventId = (int)excessCatalystFunction.Number; if (eventId == 0) { return; } HandleNpcTalkEventType(session, npcScript, eventId); }
private static DialogType GetDialogType(ScriptMetadata scriptMetadata, NpcTalk npcTalk, bool hasNextScript) { DialogType dialogType = DialogType.CloseNext1; Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); if (option.Goto.Count == 0) { dialogType = DialogType.CloseNext1; } if (option.AmountContent > 1) { dialogType = DialogType.CloseNext; } if (!hasNextScript) { ScriptIdType type = (ScriptIdType)(npcTalk.ScriptId / 100); if (npcTalk.IsQuest) { dialogType = type switch { ScriptIdType.Start => DialogType.AcceptDecline, ScriptIdType.End => DialogType.QuestReward, _ => DialogType.Close1, }; } else { dialogType = DialogType.Close1; } } return(dialogType); }
/// <summary> /// /// </summary> /// <param name="scriptMetadata"></param> public MetadataScriptInfo(ScriptMetadata scriptMetadata) { ScriptMetadata = scriptMetadata; ScriptText = scriptMetadata.ScriptText; MigrateName = scriptMetadata.MigrateName; Version = scriptMetadata.Version; }
public override void InitFromRawDecompressed(byte[] decompressedBytes) { using (var decompressedStream = new BinaryReader(new MemoryStream(decompressedBytes))) { this.Resource = Read_ScriptMetadataResource(decompressedStream); } }
private static int GetNextScript(ScriptMetadata scriptMetadata, NpcTalk npcTalk, int index) { if (npcTalk.IsQuest && npcTalk.ScriptId == 0) { QuestStatus questStatus = npcTalk.Quests[index]; if (questStatus.Started) { // Talking to npc that start the quest and condition is not completed if (questStatus.StartNpcId == npcTalk.Npc.Id && questStatus.Condition.Count != questStatus.Condition.Count(x => x.Goal == x.Current)) { return(200); } return(300); // Talking to npc that end the quest } return(100); // Talking to npc that start the quest and isn't started } Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); if (npcTalk.ScriptId == 0) { return(scriptMetadata.Options.First(x => x.Id > npcTalk.ScriptId).Id); } if (option.Goto.Count == 0) { return(npcTalk.ScriptId); } return(option.Goto[index]); }
public static void TalkError(GameSession session, ItemEnchant itemEnchant) { int npcId = itemEnchant.Type switch { EnchantType.Ophelia => 11000508, _ => 11000510 }; ScriptMetadata scriptMetadata = ScriptMetadataStorage.GetNpcScriptMetadata(npcId); NpcScript npcScript = scriptMetadata?.NpcScripts.FirstOrDefault(x => x.Id == 31); if (npcScript is null) { return; } Script script = ScriptLoader.GetScript($"Npcs/{npcId}", session); int eventId = (int)script.RunFunction("getProcessEventId", PlayerHasIngredients(itemEnchant, session.Player.Inventory), PlayerHasRequiredCatalysts(itemEnchant)).Number; if (eventId == 0) { return; } HandleNpcTalkEventType(session, npcScript, eventId); }
private void ReadMonoBehaviours(PrefabMetadata metadata, string content) { var documents = content.Split(new string[] { "--- !u!114" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < documents.Length; i++) { var document = documents[i]; var monoBehaviour = new MonoBehaviourMetadata(); var script = new ScriptMetadata { FileId = ReadFileId(document, ScriptFileIdRegex), Guid = ReadString(document, ScriptGuidRegex, "guid") }; script.FullName = m_scriptMetadataService.GetFullNameByFileId(script.FileId); if (String.IsNullOrEmpty(script.FullName)) { script.FullName = MetaFileService.GetFileNameByGuid(script.Guid); } monoBehaviour.Script = script; metadata.MonoBehaviours.Add(monoBehaviour); } }
public void ReplaceGuid_OldAndNew_Replaced() { var fs = MetadataBootstrap.FileSystem; var prefabPath = "PrefabSample1.ReplaceGuidTest.prefab"; fs.CopyFile("PrefabSample1.prefab", prefabPath); var target = new YamlPrefabMetadataWriter(fs, MockRepository.GenerateMock <ILog>()); var oldScript1 = new ScriptMetadata { FileId = 1363015578, Guid = "a184ae646778d4bf48c881bb73f2188a" }; var oldScript2 = new ScriptMetadata { FileId = -1557964980, Guid = "a184ae646778d4bf48c881bb73f2188a" }; target.ReplaceGuid(oldScript1, "1ReplaceGuidTest1", prefabPath); target.ReplaceGuid(oldScript2, "2ReplaceGuidTest2", prefabPath); var reader = new YamlPrefabMetadataReader(MetadataBootstrap.ScriptMetadataService, fs); var actual = reader.Read(prefabPath); Assert.AreEqual(2, actual.MonoBehaviours.Count); Assert.AreEqual("1ReplaceGuidTest1", actual.MonoBehaviours.First().Script.Guid); Assert.AreEqual("2ReplaceGuidTest2", actual.MonoBehaviours.Last().Script.Guid); }
private static int GetNextScript(ScriptMetadata scriptMetadata, NpcTalk npcTalk, int index, ScriptLoader scriptLoader) { if (npcTalk.IsQuest && npcTalk.ScriptId == 0) { QuestStatus questStatus = npcTalk.Quests[index]; if (questStatus.Started) { // Talking to npc that start the quest and condition is not completed if (questStatus.StartNpcId == npcTalk.Npc.Id && questStatus.Condition.Count != questStatus.Condition.Count(x => x.Completed)) { return(200); } return(300); // Talking to npc that end the quest } return(100); // Talking to npc that start the quest and isn't started } if (npcTalk.ScriptId == 0) { if (scriptLoader.Script != null) { // Usually hardcoded functions to get the first script id which // otherwise wouldn't be possible only with the xml data DynValue result = scriptLoader.Call("getFirstScriptId"); if (result != null && result.Number != -1) { return((int)result.Number); } } return(scriptMetadata.Options.First(x => x.Id > npcTalk.ScriptId).Id); } Option currentOption = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); if (currentOption.Contents[npcTalk.ContentIndex].Goto.Count == 0 || currentOption?.Contents.Count > 1 && currentOption?.Contents.Count > npcTalk.ContentIndex + 1) { return(npcTalk.ScriptId); } // If content has goto fail, use the lua scripts to check the requirements if (currentOption.Contents[npcTalk.ContentIndex].GotoFail.Count > 0) { if (scriptLoader.Script != null) { DynValue result = scriptLoader.Call("handleGotoFail", currentOption.Contents[npcTalk.ContentIndex].Goto[index]); if (result == null) { return(0); } return((int)result.Number); } } // TODO: check for the requirements for goto return(currentOption.Contents[npcTalk.ContentIndex].Goto[index]); }
private ScriptMetadata Read_ScriptMetadataResource(BinaryReader reader) { var result = new ScriptMetadata(); result.Version = ReadVersion(reader, 5, 0x141115FB0); // C3038F16B1058B48 if (result.Version < 2) { result.Parameters = new List <KeyValuePair <string, string> >(); var ParameterCount = reader.ReadUInt32(); // skip for (int i = 0; i < ParameterCount; i++) { var ParamKey = ReadString(reader); var ParamValue = ReadString(reader); result.Parameters.Add(new KeyValuePair <string, string>(ParamKey, ParamValue)); } return(result); } if (result.Version < 3) { result.SourceFileName = ReadString(reader); } result.Info = ReadString(reader); result.Errors = ReadString(reader); result.Flags = reader.ReadUInt32(); if (result.Version >= 4) { result.ScriptClasses = Read_List(reader, Read_ScriptClass, 1, 0x1411D2370); result.DefaultScript = ReadString(reader); } else { result.Properties = Read_List(reader, Read_Property, 1, 0x1411D2360); } result.Tags = Read_List(reader, Read_ScriptTag, 1, 0x1411D2380); if (result.Version >= 5) { result.Tooltip = ReadString(reader); } return(result); }
private static int GetFirstScriptId(ScriptLoader scriptLoader, ScriptMetadata scriptMetadata) { if (scriptLoader.Script != null) { // Usually hardcoded functions to get the first script id which // otherwise wouldn't be possible only with the xml data DynValue result = scriptLoader.Call("getFirstScriptId"); if (result != null && result.Number != -1) { return((int)result.Number); } } return(scriptMetadata.Options.First(x => x.Type == ScriptType.Script).Id); }
/// <summary> /// Replaces the GUID. /// </summary> /// <param name="oldScript">Old script.</param> /// <param name="newGuid">New GUID.</param> /// <param name="fileName">File name.</param> public void ReplaceGuid(ScriptMetadata oldScript, string newGuid, string fileName) { m_log.Debug("Replacing guid from '{0}' to '{1}' on file '{2}'...", oldScript.Guid, newGuid, fileName); var content = m_fs.ReadAllText(fileName); var regex = new Regex(@"(\{{fileID: {0}, guid: )({1})(, type: 3)".With(oldScript.FileId, oldScript.Guid), RegexOptions.Compiled | RegexOptions.IgnoreCase); content = regex.Replace( content, (m) => { return("{0}{1}{2}".With(m.Groups[1].Value, newGuid, m.Groups[3].Value)); }); m_fs.WriteAllText(fileName, content); }
public ScriptMetadata[] LoadScriptMetadata() { var list = new List <ScriptMetadata>(); var scripts = XUtil.GetScriptMap(); using (var reader = OpenFile("properties", "scriptMetadata.txt")) using (var txt = new StreamReader(reader)) { string line; while ((line = txt.ReadLine()) != null) { if (!line.HasValue() || line[0] == '#') { continue; } string[] fields = line.Split(';'); string code = fields[0]?.Trim(); if (!code.HasValue()) { continue; } if (!scripts.TryGetValue(code, out WritingScript script)) { throw new FormatException("Id " + code); } var cur = new ScriptMetadata(); cur.Script = script; list.Add(cur); code = fields[1].Trim(); if (int.TryParse(code, out int rank)) { cur.Rank = rank; } code = fields[3].Trim(); if (code.HasValue()) { cur.Territory = GetTerritory(code); } code = fields[4].Trim(); if (int.TryParse(code, out rank)) { cur.Density = rank; } } } return(list.ToArray()); }
private static int GetNextScript(ScriptMetadata scriptMetadata, NpcTalk npcTalk, int index) { if (npcTalk.IsQuest && npcTalk.ScriptId == 0) { if (npcTalk.Quests[index].Started) { // Talking to npc that start the quest and is started if (npcTalk.Quests[index].StartNpcId == npcTalk.Npc.Id) { return(200); } else // Talking to npc that end the quest { return(300); } } else // Talking to npc that start the quest and isn't started { return(100); } } else { Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); if (npcTalk.ScriptId == 0) { return(scriptMetadata.Options.First(x => x.Id > npcTalk.ScriptId).Id); } else { if (option.Goto.Count == 0) { return(npcTalk.ScriptId); } else { return(option.Goto[index]); } } } }
private static DialogType GetDialogType(ScriptMetadata scriptMetadata, NpcTalk npcTalk, bool hasNextScript) { DialogType dialogType = DialogType.None; Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); // If npc has buttonSet by xmls, use it if (option.Contents[npcTalk.ContentIndex].ButtonSet != DialogType.None) { return(option.Contents[npcTalk.ContentIndex].ButtonSet); } if (option.Contents[npcTalk.ContentIndex].Goto.Count == 0) { dialogType = DialogType.CloseNext; } else { dialogType = DialogType.CloseNextWithDistractor; } if (!hasNextScript) { // Get the correct dialog type for the last quest content ScriptIdType type = (ScriptIdType)(npcTalk.ScriptId / 100); if (npcTalk.IsQuest) { dialogType = type switch { ScriptIdType.Start => DialogType.AcceptDecline, ScriptIdType.End => DialogType.QuestReward, _ => DialogType.Close1, }; } else { dialogType = DialogType.Close1; } } return(dialogType); }
private static DialogType GetDialogType(ScriptMetadata scriptMetadata, NpcTalk npcTalk, bool hasNextScript) { Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); Content content = option.Contents[npcTalk.ContentIndex]; // If npc has buttonSet by xmls, use it if (content.ButtonSet != DialogType.None) { return(content.ButtonSet); } if (!hasNextScript) { // Get the correct dialog type for the last quest content ScriptIdType type = (ScriptIdType)(npcTalk.ScriptId / 100); if (npcTalk.IsQuest) { return(type switch { ScriptIdType.Start => DialogType.AcceptDecline, ScriptIdType.End => DialogType.QuestReward, _ => DialogType.Close1 });
public static List <ScriptMetadata> ParseNpc(MemoryMappedFile m2dFile, IEnumerable <PackFileEntry> entries) { List <ScriptMetadata> scripts = new List <ScriptMetadata>(); foreach (PackFileEntry entry in entries) { if (!entry.Name.StartsWith("script/npc")) { continue; } ScriptMetadata metadata = new ScriptMetadata(); string npcID = Path.GetFileNameWithoutExtension(entry.Name); XmlDocument document = m2dFile.GetDocument(entry.FileHeader); foreach (XmlNode node in document.DocumentElement.ChildNodes) { int id = int.Parse(node.Attributes["id"].Value); string feature = node.Attributes["feature"].Value; int randomPick = string.IsNullOrEmpty(node.Attributes["randomPick"]?.Value) ? 0 : int.Parse(node.Attributes["randomPick"].Value); int popupState = string.IsNullOrEmpty(node.Attributes["popupState"]?.Value) ? 0 : int.Parse(node.Attributes["popupState"].Value); int popupProp = string.IsNullOrEmpty(node.Attributes["popupProp"]?.Value) ? 0 : int.Parse(node.Attributes["popupProp"].Value); List <int> gotoConditionTalkID = new List <int>(); if (!string.IsNullOrEmpty(node.Attributes["popupProp"]?.Value)) { foreach (string item in node.Attributes["popupProp"].Value.Split(",")) { gotoConditionTalkID.Add(int.Parse(item)); } } List <Content> contents = new List <Content>(); foreach (XmlNode content in node.ChildNodes) { long contentScriptID = string.IsNullOrEmpty(content.Attributes["text"]?.Value) ? 0 : long.Parse(content.Attributes["text"].Value.Substring(8, 16)); string voiceID = string.IsNullOrEmpty(content.Attributes["voiceID"]?.Value) ? "" : content.Attributes["voiceID"].Value; int otherNpcTalk = string.IsNullOrEmpty(content.Attributes["otherNpcTalk"]?.Value) ? 0 : int.Parse(content.Attributes["otherNpcTalk"].Value); string leftIllust = string.IsNullOrEmpty(content.Attributes["leftIllust"]?.Value) ? "" : content.Attributes["leftIllust"].Value; string illust = string.IsNullOrEmpty(content.Attributes["illust"]?.Value) ? "" : content.Attributes["illust"].Value; string speakerIllust = string.IsNullOrEmpty(content.Attributes["speakerIllust"]?.Value) ? "" : content.Attributes["speakerIllust"].Value; bool myTalk = !string.IsNullOrEmpty(content.Attributes["myTalk"]?.Value); byte functionID = string.IsNullOrEmpty(content.Attributes["functionID"]?.Value) ? 0 : byte.Parse(content.Attributes["functionID"].Value); List <Distractor> distractors = new List <Distractor>(); List <Event> events = new List <Event>(); foreach (XmlNode distractor in content.ChildNodes) { if (distractor.Name == "event") { int eventid = string.IsNullOrEmpty(content.Attributes["id"]?.Value) ? 0 : int.Parse(content.Attributes["id"].Value); List <Content> contents2 = new List <Content>(); foreach (XmlNode item in distractor.ChildNodes) { long contentScriptID2 = long.Parse(item.Attributes["text"].Value.Substring(8, 16)); string voiceID2 = string.IsNullOrEmpty(item.Attributes["voiceID"]?.Value) ? "" : item.Attributes["voiceID"].Value; int otherNpcTalk2 = string.IsNullOrEmpty(item.Attributes["otherNpcTalk"]?.Value) ? 0 : int.Parse(item.Attributes["otherNpcTalk"].Value); string leftIllust2 = string.IsNullOrEmpty(item.Attributes["leftIllust"]?.Value) ? "" : item.Attributes["leftIllust"].Value; string illust2 = string.IsNullOrEmpty(item.Attributes["illust"]?.Value) ? "" : item.Attributes["illust"].Value; string speakerIllust2 = string.IsNullOrEmpty(item.Attributes["speakerIllust"]?.Value) ? "" : item.Attributes["speakerIllust"].Value; bool myTalk2 = !string.IsNullOrEmpty(item.Attributes["myTalk"]?.Value); byte functionID2 = string.IsNullOrEmpty(item.Attributes["functionID"]?.Value) ? 0 : byte.Parse(item.Attributes["functionID"].Value); contents2.Add(new Content(contentScriptID2, voiceID2, functionID2, leftIllust2, speakerIllust2, otherNpcTalk2, myTalk2, illust2, null)); } events.Add(new Event(eventid, contents2)); } else { long distractorScriptID = long.Parse(distractor.Attributes["text"].Value.Substring(8, 16)); List <int> goTo = new List <int>(); if (!string.IsNullOrEmpty(distractor.Attributes["goto"]?.Value)) { foreach (string item in distractor.Attributes["goto"].Value.Split(",")) { goTo.Add(int.Parse(item)); } } List <int> goToFail = new List <int>(); if (!string.IsNullOrEmpty(distractor.Attributes["gotoFail"]?.Value)) { foreach (string item in distractor.Attributes["gotoFail"].Value.Split(",")) { goToFail.Add(int.Parse(item)); } } distractors.Add(new Distractor(distractorScriptID, goTo, goToFail)); } } contents.Add(new Content(contentScriptID, voiceID, functionID, leftIllust, speakerIllust, otherNpcTalk, myTalk, illust, distractors)); } metadata.Id = int.Parse(npcID); metadata.IsQuestScript = false; if (node.Name == "select") { metadata.Selects[id] = new Select(id, contents); } else if (node.Name == "script") { metadata.Scripts[id] = new Script(id, feature, randomPick, gotoConditionTalkID, contents); } else if (node.Name == "monologue") { metadata.Monologues[id] = new Monologue(id, popupState, popupProp, contents); } } scripts.Add(metadata); } return(scripts); }
private static void HandleContinue(GameSession session, PacketReader packet) { NpcTalk npcTalk = session.Player.NpcTalk; if (npcTalk.Npc.IsBeauty()) { HandleBeauty(session); return; } int index = packet.ReadInt(); // selection index // index is quest if (index <= npcTalk.Quests.Count - 1 && npcTalk.ScriptId == 0) { npcTalk.QuestId = npcTalk.Quests[index].Basic.Id; npcTalk.IsQuest = true; } ScriptMetadata scriptMetadata = npcTalk.IsQuest ? ScriptMetadataStorage.GetQuestScriptMetadata(npcTalk.QuestId) : ScriptMetadataStorage.GetNpcScriptMetadata(npcTalk.Npc.Id); ResponseType responseType = npcTalk.IsQuest ? ResponseType.Quest : ResponseType.Dialog; if (npcTalk.ScriptId != 0) { Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); if (option.AmountContent <= npcTalk.ContentIndex && option.Goto.Count == 0) { session.Send(NpcTalkPacket.Close()); return; } } // Find next script id int nextScript = GetNextScript(scriptMetadata, npcTalk, index); Option option2 = scriptMetadata.Options.FirstOrDefault(x => x.Id == npcTalk.ScriptId); if (option2?.AmountContent > 1 && option2?.AmountContent > npcTalk.ContentIndex) { nextScript = npcTalk.ScriptId; } if (npcTalk.ScriptId != nextScript) { npcTalk.ContentIndex = 1; } else { npcTalk.ContentIndex++; } Option option1 = scriptMetadata.Options.First(x => x.Id == nextScript); bool hasNextScript = option1.Goto.Count != 0; if (option1.AmountContent > npcTalk.ContentIndex) { hasNextScript = true; } npcTalk.ScriptId = nextScript; DialogType dialogType = GetDialogType(scriptMetadata, npcTalk, hasNextScript); session.Send(NpcTalkPacket.ContinueChat(nextScript, responseType, dialogType, npcTalk.ContentIndex - 1, npcTalk.QuestId)); }
private static void HandleRespond(GameSession session, PacketReader packet) { List <QuestStatus> npcQuests = new List <QuestStatus>(); int objectId = packet.ReadInt(); // Find if npc object id exists in field manager if (!session.FieldManager.State.Npcs.TryGetValue(objectId, out IFieldObject <Npc> npc)) { return; } // Get all quests for this npc foreach (QuestStatus item in session.Player.QuestList.Where(x => !x.Completed)) { if (npc.Value.Id == item.StartNpcId) { npcQuests.Add(item); } if (item.Started && npc.Value.Id == item.CompleteNpcId && !npcQuests.Contains(item)) { npcQuests.Add(item); } } session.Player.NpcTalk = new NpcTalk(npc.Value, npcQuests); ScriptLoader scriptLoader = new ScriptLoader($"Npcs/{npc.Value.Id}", session); // If NPC is a shop, load and open the shop if (npc.Value.IsShop()) { ShopHandler.HandleOpen(session, npc); return; } else if (npc.Value.IsBank()) { session.Send(HomeBank.OpenBank()); return; } else if (npc.Value.IsBeauty()) { NpcMetadata npcTarget = NpcMetadataStorage.GetNpc(session.Player.NpcTalk.Npc.Id); if (npcTarget.ShopId == 507) // mirror { session.Send(NpcTalkPacket.Respond(npc, NpcType.Default, DialogType.Beauty, 0)); HandleBeauty(session); return; } session.Send(NpcTalkPacket.Respond(npc, NpcType.Default, DialogType.Beauty, 1)); return; } // Check if npc has an exploration quest QuestHelper.UpdateExplorationQuest(session, npc.Value.Id.ToString(), "talk_in"); // If npc has quests, send quests and talk option if (npcQuests.Count != 0) { session.Player.NpcTalk.ScriptId = 0; session.Send(QuestPacket.SendDialogQuest(objectId, npcQuests)); session.Send(NpcTalkPacket.Respond(npc, NpcType.Unk2, DialogType.TalkOption, session.Player.NpcTalk.ScriptId)); return; } ScriptMetadata scriptMetadata = ScriptMetadataStorage.GetNpcScriptMetadata(npc.Value.Id); if (!scriptMetadata.Options.Exists(x => x.Type == ScriptType.Script)) { return; } int firstScriptId = GetFirstScriptId(scriptLoader, scriptMetadata); session.Player.NpcTalk.ScriptId = firstScriptId; Option option = scriptMetadata.Options.First(x => x.Id == firstScriptId); DialogType dialogType = DialogType.None; if (option.Contents[0].Goto.Count == 0) { dialogType = DialogType.Close1; } else { dialogType = DialogType.CloseNextWithDistractor; } session.Send(NpcTalkPacket.Respond(npc, NpcType.Unk3, dialogType, firstScriptId)); // If npc has buttonset roulette, send roulette id 13. // TODO: Send the correct roulette id if (scriptMetadata.Options.Any(x => x.ButtonSet == "roulette")) { session.Send(NpcTalkPacket.Action(ActionType.OpenWindow, "RouletteDialog", "13")); } }
public void AddMetadata(ScriptMetadata metadata) { ScriptData.Add(metadata); }
private static void HandleContinue(GameSession session, int index) { NpcTalk npcTalk = session.Player.NpcTalk; if (npcTalk.Npc.IsBeauty()) { HandleBeauty(session); return; } ScriptLoader scriptLoader = new ScriptLoader($"Npcs/{npcTalk.Npc.Id}", session); // index is quest if (index <= npcTalk.Quests.Count - 1 && npcTalk.ScriptId == 0) { npcTalk.QuestId = npcTalk.Quests[index].Basic.Id; npcTalk.IsQuest = true; } ScriptMetadata scriptMetadata = npcTalk.IsQuest ? ScriptMetadataStorage.GetQuestScriptMetadata(npcTalk.QuestId) : ScriptMetadataStorage.GetNpcScriptMetadata(npcTalk.Npc.Id); ResponseType responseType = npcTalk.IsQuest ? ResponseType.Quest : ResponseType.Dialog; if (npcTalk.ScriptId != 0) { Option option = scriptMetadata.Options.First(x => x.Id == npcTalk.ScriptId); // Find if player has quest condition for type "talk_in" and option id QuestHelper.UpdateQuest(session, npcTalk.Npc.Id.ToString(), "talk_in", option.Id.ToString()); // If npc has no more options, close dialog if (option.Contents.Count <= npcTalk.ContentIndex + 1 && option.Contents[npcTalk.ContentIndex].Goto.Count == 0) { session.Send(NpcTalkPacket.Close()); return; } } int nextScriptId = GetNextScript(scriptMetadata, npcTalk, index, scriptLoader); // If last script is different from next, reset content index, else increment content index if (npcTalk.ScriptId != nextScriptId) { npcTalk.ContentIndex = 0; } else { npcTalk.ContentIndex++; } Option nextScript = scriptMetadata.Options.First(x => x.Id == nextScriptId); bool hasNextScript = nextScript.Contents[npcTalk.ContentIndex].Goto.Count != 0; if (nextScript.Contents.Count > npcTalk.ContentIndex + 1) { hasNextScript = true; } npcTalk.ScriptId = nextScriptId; DialogType dialogType = GetDialogType(scriptMetadata, npcTalk, hasNextScript); session.Send(NpcTalkPacket.ContinueChat(nextScriptId, responseType, dialogType, npcTalk.ContentIndex, npcTalk.QuestId)); // It appears if content has buttonset roulette, it's send again on every continue chat, unsure why since it doesn't break anything }
private static void HandleRespond(GameSession session, PacketReader packet) { List <QuestStatus> npcQuests = new List <QuestStatus>(); int objectId = packet.ReadInt(); if (!session.FieldManager.State.Npcs.TryGetValue(objectId, out IFieldObject <Npc> npc)) { return; // Invalid NPC } foreach (QuestStatus item in session.Player.QuestList.Where(x => !x.Completed)) { if (npc.Value.Id == item.StartNpcId) { npcQuests.Add(item); } if (item.Started && npc.Value.Id == item.CompleteNpcId && !npcQuests.Contains(item)) { npcQuests.Add(item); } } session.Player.NpcTalk = new NpcTalk(npc.Value, npcQuests); // If NPC is a shop, load and open the shop if (npc.Value.IsShop()) { ShopHandler.HandleOpen(session, npc); return; } else if (npc.Value.IsBank()) { session.Send(HomeBank.OpenBank()); return; } else if (npc.Value.IsBeauty()) { session.Send(NpcTalkPacket.Respond(npc, NpcType.Default, DialogType.Beauty, 1)); return; } QuestHelper.UpdateExplorationQuest(session, npc.Value.Id.ToString(), "talk_in"); if (npcQuests.Count != 0) { session.Player.NpcTalk.ScriptId = 0; session.Send(QuestPacket.SendDialogQuest(objectId, npcQuests)); session.Send(NpcTalkPacket.Respond(npc, NpcType.Unk2, DialogType.TalkOption, session.Player.NpcTalk.ScriptId)); } else { ScriptMetadata scriptMetadata = ScriptMetadataStorage.GetNpcScriptMetadata(npc.Value.Id); int firstScript = scriptMetadata.Options.First(x => x.Type == ScriptType.Script).Id; session.Player.NpcTalk.ScriptId = firstScript; Option option = scriptMetadata.Options.First(x => x.Id == firstScript); bool hasNextScript = option.Goto.Count != 0; DialogType dialogType = DialogType.CloseNext1; if (option.Goto.Count == 0) { session.Player.NpcTalk.ContentIndex++; dialogType = DialogType.CloseNext1; } if (!hasNextScript) { dialogType = DialogType.Close1; } if (option.AmountContent > 1) { dialogType = DialogType.CloseNext; } session.Send(NpcTalkPacket.Respond(npc, NpcType.Unk3, dialogType, firstScript)); } }
private static void HandleBegin(GameSession session, PacketReader packet) { int objectId = packet.ReadInt(); List <QuestStatus> npcQuests = new(); int contentIndex = 0; // Find if npc object id exists in field manager if (!session.FieldManager.State.Npcs.TryGetValue(objectId, out Npc npc)) { return; } // Get all quests for this npc foreach (QuestStatus item in session.Player.QuestData.Values.Where(x => x.State is not QuestState.Completed)) { if (npc.Value.Id == item.StartNpcId) { npcQuests.Add(item); } if (item.State is QuestState.Started && npc.Value.Id == item.CompleteNpcId && !npcQuests.Contains(item)) { npcQuests.Add(item); } } session.Player.NpcTalk = new(npc.Value, npcQuests); NpcTalk npcTalk = session.Player.NpcTalk; ScriptMetadata scriptMetadata = ScriptMetadataStorage.GetNpcScriptMetadata(npc.Value.Id); NpcKind kind = npc.Value.NpcMetadataBasic.Kind; // need to find script properly before continuing NpcScript npcScript = GetFirstScript(session, scriptMetadata, npcTalk, npcQuests); switch (kind) { // reputation NPCs only have UI Dialog Type even if they have quests to accept/accepted. case NpcKind.SkyLumiknightCommander: case NpcKind.SkyGreenHoodCommander: case NpcKind.SkyDarkWindCommander: case NpcKind.SkyMapleAllianceCommander: case NpcKind.SkyRoyalGuardCommander: case NpcKind.KritiasLumiknightCommander: case NpcKind.KritiasGreenHoodCommander: case NpcKind.KritiasMapleAllianceCommander: case NpcKind.Humanitas: npcTalk.DialogType = DialogType.UI; ShopHandler.HandleOpen(session, npc, npc.Value.Id); break; case NpcKind.BalmyShop: case NpcKind.FixedShop: case NpcKind.RotatingShop: ShopHandler.HandleOpen(session, npc, npc.Value.Id); break; case NpcKind.Storage: case NpcKind.BlackMarket: case NpcKind.Birthday: // TODO: needs a special case? select if birthday. script if not npcTalk.DialogType = DialogType.UI; break; } npcTalk.ScriptId = npcScript?.Id ?? 0; ResponseSelection responseSelection = GetResponseSelection(kind, npcTalk.DialogType, contentIndex, npcScript); if (npcTalk.DialogType.HasFlag(DialogType.Quest)) { session.Send(QuestPacket.SendDialogQuest(objectId, npcQuests)); } QuestManager.OnTalkNpc(session.Player, npc.Value.Id, npcTalk.ScriptId); session.Send(NpcTalkPacket.Respond(npc, npcTalk.DialogType, contentIndex, responseSelection, npcTalk.ScriptId)); if (npcScript != null) { npcTalk.TalkFunction(session, npcScript.Contents[npcTalk.ContentIndex].FunctionId, "preTalkActions"); } }