/// <summary> /// Reads the DialogueEntries section. DialogueEntry is not a subclass of Asset, /// so we can't reuse the ReadAssets() code above. /// </summary> /// <param name="database">Dialogue database.</param> private void ReadDialogueEntries(DialogueDatabase database, bool add) { Debug.Log("Dialogue System CSV Converter: " + (add ? "Reading" : "Skipping") + " DialogueEntries section"); // Read field names and types: string[] fieldNames = GetValues(GetNextSourceLine()); string[] fieldTypes = GetValues(GetNextSourceLine()); // Keep reading until we reach another asset type heading or end of file: int safeguard = 0; while (!(IsSourceAtEnd() || AssetTypeHeadings.Contains(GetFirstField(PeekNextSourceLine())))) { safeguard++; if (safeguard > MaxIterations) { break; } string[] values = GetValues(GetNextSourceLine()); if (add) { // Create the dialogue entry: DialogueEntry entry = new DialogueEntry(); entry.fields = new List <Field>(); // We can ignore value[0] (entrytag). entry.conversationID = Tools.StringToInt(values[1]); entry.id = Tools.StringToInt(values[2]); entry.ActorID = Tools.StringToInt(values[3]); entry.ConversantID = Tools.StringToInt(values[4]); entry.Title = values[5]; entry.DefaultMenuText = values[6]; entry.DefaultDialogueText = values[7]; entry.isGroup = Tools.StringToBool(values[8]); entry.falseConditionAction = values[9]; entry.conditionPriority = ConditionPriorityTools.StringToConditionPriority(values[10]); entry.conditionsString = values[11]; entry.userScript = values[12]; // Read the remaining values and assign them to the asset's fields: ReadAssetFields(fieldNames, fieldTypes, DialogueEntrySpecialValues, values, entry.fields); // Convert canvasRect field to entry position on node editor canvas: entry.UseCanvasRectField(); // Finally, add the asset: var conversation = database.GetConversation(entry.conversationID); if (conversation == null) { throw new InvalidDataException(string.Format("Conversation {0} referenced in entry {1} not found", entry.conversationID, entry.id)); } conversation.dialogueEntries.Add(entry); } } }
protected bool MatchesVoicePreference(Voice voice, VoicePreference voicePreference) { var gender = (voice.Gender == Crosstales.RTVoice.Model.Enum.Gender.FEMALE) ? Gender.Female : Gender.Male; // string.Equals(voice.Gender, "Female", System.StringComparison.OrdinalIgnoreCase) ? Gender.Female : Gender.Male; var age = Tools.StringToInt(voice.Age); var matchesName = string.IsNullOrEmpty(voicePreference.name) || string.Equals(voicePreference.name, voice.Name); var matchesGender = (gender == voicePreference.gender); var matchesAge = (voicePreference.minAge <= age && age <= voicePreference.maxAge); return(matchesName && matchesGender && matchesAge); }
/// <summary> /// Reads a section of assets such as Actors, Items, etc. /// </summary> /// <param name="assets">List of assets to populate.</param> /// <typeparam name="T">The type of asset.</typeparam> private void ReadAssets <T>(List <T> assets, bool add) where T : Asset, new() { string typeName = typeof(T).Name; bool isActorSection = (typeof(T) == typeof(Actor)); Debug.Log(string.Format("Dialogue System CSV Importer: {0} {1} section", (add ? "Reading" : "Skipping"), typeName)); // Read field names and types: string[] fieldNames = GetValues(GetNextSourceLine()); string[] fieldTypes = GetValues(GetNextSourceLine()); // Set up ignore list for values that aren't actual fields: List <string> ignore = isActorSection ? ActorSpecialValues : DefaultSpecialValues; // Keep reading until we reach another asset type heading or end of file: int safeguard = 0; while (!(IsSourceAtEnd() || AssetTypeHeadings.Contains(GetFirstField(PeekNextSourceLine())))) { safeguard++; if (safeguard > MaxIterations) { break; } string[] values = GetValues(GetNextSourceLine()); if (add) { // Create the asset: T asset = new T(); asset.id = Tools.StringToInt(values[0]); asset.fields = new List <Field>(); // Preprocess a couple extra values for actors: if (isActorSection) { FindActorPortraits(asset as Actor, values[1], values[2]); } // Read the remaining values and assign them to the asset's fields: ReadAssetFields(fieldNames, fieldTypes, ignore, values, asset.fields); // If the database already has an old asset with the same ID, delete it first: assets.RemoveAll(a => a.id == asset.id); // Finally, add the asset: assets.Add(asset); } } }
private static ChatMapper.Item ItemToCmp(DialogueSystem.Item item) { ChatMapper.Item cmpItem = new ChatMapper.Item(); cmpItem.ID = item.id; cmpItem.Fields = FieldsToCmp(item.fields); AddRequiredItemFields(cmpItem.Fields); Field entryCount = Field.Lookup(item.fields, "Entry Count"); if (entryCount != null) { maxEntryCount = Mathf.Max(maxEntryCount, Tools.StringToInt(entryCount.value)); } return(cmpItem); }
public Voice GetVoice(string voiceName, string gender, int minAge, int maxAge) { var culture = Localization.Language; var availableVoices = string.IsNullOrEmpty(culture) ? Speaker.Voices : Speaker.VoicesForCulture(culture); foreach (var availableVoice in availableVoices) { var matchesName = string.IsNullOrEmpty(voiceName) || string.Equals(voiceName, availableVoice.Name); var matchesGender = string.Equals(gender, availableVoice.Gender.ToString(), System.StringComparison.OrdinalIgnoreCase); var age = Tools.StringToInt(availableVoice.Age); var matchesAge = (minAge == 0 && maxAge == 0) || (minAge <= age && age <= maxAge); if (matchesName && matchesGender && matchesAge) { return(availableVoice); } } return((availableVoices != null && availableVoices.Count > 0) ? availableVoices[0] : null); }
/// <summary> /// Reads the OutgoingLinks section. Again, Link is not a subclass of Asset, /// so we can't reuse the ReadAssets() method. /// </summary> /// <param name="database">Dialogue database.</param> private void ReadOutgoingLinks(DialogueDatabase database) { Debug.Log("Reading OutgoingLinks section"); GetNextSourceLine(); // Headings GetNextSourceLine(); // Types // Keep reading until we reach another asset type heading or end of file: while (!(IsSourceAtEnd() || AssetTypeHeadings.Contains(PeekNextSourceLine()))) { string[] values = GetValues(GetNextSourceLine()); var link = new Link(Tools.StringToInt(values[0]), Tools.StringToInt(values[1]), Tools.StringToInt(values[2]), Tools.StringToInt(values[3])); var entry = database.GetDialogueEntry(link.originConversationID, link.originDialogueID); if (entry == null) { throw new InvalidDataException(string.Format("Dialogue entry {0}.{1} referenced in link not found", link.originConversationID, link.originDialogueID)); } entry.outgoingLinks.Add(link); } }
public void AssignPortraitSprite(AssignSpriteDelegate assignSprite) { var originalDebugLevel = DialogueDebug.level; // Suppress logging for Lua return Actor[].Current_Portrait. DialogueDebug.level = DialogueDebug.DebugLevel.Warning; string imageName = DialogueLua.GetActorField(Name, DialogueSystemFields.CurrentPortrait).asString; DialogueDebug.level = originalDebugLevel; if (string.IsNullOrEmpty(imageName)) { assignSprite(GetPortraitSprite(1)); } else if (imageName.StartsWith("pic=")) { assignSprite(GetPortraitSprite(Tools.StringToInt(imageName.Substring("pic=".Length)))); } else { DialogueManager.LoadAsset(imageName, typeof(Texture2D), (asset) => { assignSprite(UITools.CreateSprite(asset as Texture2D)); }); } }
/// @endcond /// <summary> /// Gets the value with the specified string key. Returns a standard type such as /// <c>string</c>, <c>float</c>, <c>bool</c>, or <c>null</c>. If the value /// is a table, it returns a LuaTableWrapper around it. /// </summary> /// <param name="key">Key.</param> public object this[string key] { get { if (luaTable == null) { if (DialogueDebug.logErrors) { Debug.LogError(string.Format("{0}: Lua table is null; lookup[{1}] failed", new object[] { DialogueDebug.Prefix, key })); } return(null); } LuaValue luaValue = LuaNil.Nil; if (luaTable.Length > 0) { // Get list value: luaValue = luaTable.GetValue(Tools.StringToInt(key)); } else { // Get dictionary value: LuaValue luaValueKey = luaTable.GetKey(key); if (luaValueKey == LuaNil.Nil) { //--- Suppressed: if (DialogueDebug.LogErrors) Debug.LogError(string.Format("{0}: Lua table does not contain key [{1}]", new string[] { DialogueDebug.Prefix, key })); return(null); } luaValue = luaTable.GetValue(key); } if (luaValue is LuaTable) { return(new LuaTableWrapper(luaValue as LuaTable)); } else { return(LuaInterpreterExtensions.LuaValueToObject(luaValue)); } } }
public Sprite GetPortraitSprite() { //--- Was: return UITools.GetSprite(portrait, spritePortrait); //--- Instead, check for override set by SetPortrait(): var originalDebugLevel = DialogueDebug.level; // Suppress logging for Lua return Actor[].Current_Portrait. DialogueDebug.level = DialogueDebug.DebugLevel.Warning; string imageName = DialogueLua.GetActorField(Name, DialogueSystemFields.CurrentPortrait).asString; DialogueDebug.level = originalDebugLevel; if (string.IsNullOrEmpty(imageName)) { return(GetPortraitSprite(1)); } else if (imageName.StartsWith("pic=")) { return(GetPortraitSprite(Tools.StringToInt(imageName.Substring("pic=".Length)))); } else { return(UITools.CreateSprite(DialogueManager.LoadAsset(imageName) as Texture2D)); } }
/// <summary> /// Reads a section of assets such as Actors, Items, etc. /// </summary> /// <param name="assets">List of assets to populate.</param> /// <typeparam name="T">The type of asset.</typeparam> private void ReadAssets <T>(List <T> assets) where T : Asset, new() { string typeName = typeof(T).Name; bool isActorSection = (typeof(T) == typeof(Actor)); Debug.Log(string.Format("Reading {0} section", typeName)); // Read field names and types: string[] fieldNames = GetValues(GetNextSourceLine()); string[] fieldTypes = GetValues(GetNextSourceLine()); // Set up ignore list for values that aren't actual fields: List <string> ignore = isActorSection ? ActorSpecialValues : DefaultSpecialValues; // Keep reading until we reach another asset type heading or end of file: while (!(IsSourceAtEnd() || AssetTypeHeadings.Contains(PeekNextSourceLine()))) { string[] values = GetValues(GetNextSourceLine()); // Create the asset: T asset = new T(); asset.id = Tools.StringToInt(values[0]); asset.fields = new List <Field>(); // Preprocess a couple extra values for actors: if (isActorSection) { FindActorPortraits(asset as Actor, values[1], values[2]); } // Read the remaining values and assign them to the asset's fields: ReadAssetFields(fieldNames, fieldTypes, ignore, values, asset.fields); // Finally, add the asset: assets.Add(asset); } }
/// <summary> /// Reads the OutgoingLinks section. Again, Link is not a subclass of Asset, /// so we can't reuse the ReadAssets() method. /// </summary> /// <param name="database">Dialogue database.</param> private void ReadOutgoingLinks(DialogueDatabase database, bool add) { Debug.Log("Dialogue System CSV Importer: " + (add ? "Reading" : "Skipping") + " OutgoingLinks section"); GetNextSourceLine(); // Headings GetNextSourceLine(); // Types // Keep reading until we reach another asset type heading or end of file: int safeguard = 0; while (!(IsSourceAtEnd() || AssetTypeHeadings.Contains(GetFirstField(PeekNextSourceLine())))) { safeguard++; if (safeguard > MaxIterations) { break; } string[] values = GetValues(GetNextSourceLine()); if (add) { var link = new Link(Tools.StringToInt(values[0]), Tools.StringToInt(values[1]), Tools.StringToInt(values[2]), Tools.StringToInt(values[3])); link.priority = ConditionPriorityUtility.StringToConditionPriority(values[4]); var entry = database.GetDialogueEntry(link.originConversationID, link.originDialogueID); if (entry == null) { Debug.LogWarning(string.Format("Dialogue System: CSV import error: dialogue entry {0}.{1} referenced in an outgoing link was not found.", link.originConversationID, link.originDialogueID)); numWarnings++; } else { entry.outgoingLinks.Add(link); } } } }
/// <summary> /// A static utility method that looks up a field in a list and returns its int value. /// </summary> /// <param name='fields'> /// A list of fields. /// </param> /// <param name='title'> /// Title of the field. /// </param> /// <returns> /// The value of the field, or <c>0</c> if the field doesn't exist or isn't an int. /// </returns> public static int LookupInt(List <Field> fields, string title) { return(Tools.StringToInt(LookupValue(fields, title))); }
/// <summary> /// When loading a game, load the dialogue entry records and resume the conversation. /// </summary> public virtual void OnApplyPersistentData() { if (DontLoadInThisScene()) { Debug.Log("OnApplyPersistentData Dont Load in this scene: " + SceneManager.GetActiveScene().buildIndex); } if (DontLoadInThisScene()) { return; } records.Clear(); if (!DialogueLua.DoesVariableExist(currentDialogueEntryRecords)) { return; } StopAllCoroutines(); // Load dialogue entry records: var s = DialogueLua.GetVariable(currentDialogueEntryRecords).AsString; if (Debug.isDebugBuild) { Debug.Log("TextlineDialogueUI.OnApplyPersistentData: Restoring current conversation from " + currentDialogueEntryRecords + ": " + s); } var ints = s.Split(';'); var numRecords = Tools.StringToInt(ints[0]); for (int i = 0; i < numRecords; i++) { var conversationID = Tools.StringToInt(ints[1 + i * 2]); var entryID = Tools.StringToInt(ints[2 + i * 2]); records.Add(new DialogueEntryRecord(conversationID, entryID)); } // If we have records, resume the conversation: if (records.Count == 0) { return; } var lastRecord = records[records.Count - 1]; if (lastRecord.conversationID >= 0 && lastRecord.entryID > 0) { UnityEngine.UI.Button lastContinueButton = null; try { // Resume conversation: //if (dontRepeatLastSequence) isLoadingGame = true; isLoadingGame = true; var conversation = DialogueManager.MasterDatabase.GetConversation(lastRecord.conversationID); var actorName = DialogueLua.GetVariable(currentConversationActor).AsString; var conversantName = DialogueLua.GetVariable(currentConversationConversant).AsString; var actor = GameObject.Find(actorName); var conversant = GameObject.Find(conversantName); var actorTransform = (actor != null) ? actor.transform : null; var conversantTransform = (conversant != null) ? conversant.transform : null; if (Debug.isDebugBuild) { Debug.Log("Resuming '" + conversation.Title + "' at entry " + lastRecord.entryID); } DialogueManager.StopConversation(); var lastEntry = DialogueManager.MasterDatabase.GetDialogueEntry(lastRecord.conversationID, lastRecord.entryID); var originalSequence = lastEntry.Sequence; // Handle last entry's sequence differently if end entry. npcPreDelaySettings.CopyTo(npcPreDelaySettingsCopy); pcPreDelaySettings.CopyTo(pcPreDelaySettingsCopy); npcPreDelaySettings.basedOnTextLength = false; npcPreDelaySettings.additionalSeconds = 0; pcPreDelaySettings.basedOnTextLength = false; pcPreDelaySettings.additionalSeconds = 0; var isEndEntry = lastEntry.Sequence.Contains("WaitForMessage(Forever)") || lastEntry.outgoingLinks.Count == 0; if (isEndEntry) { if (!lastEntry.Sequence.Contains("WaitForMessage(Forever)")) { lastEntry.Sequence = "WaitForMessage(Forever); " + lastEntry.Sequence; } } else if (dontRepeatLastSequence) { lastEntry.Sequence = "None()"; } else { lastEntry.Sequence = "Delay(0.1)"; } skipNextRecord = true; isInPreDelay = false; DialogueManager.StartConversation(conversation.Title, actorTransform, conversantTransform, lastRecord.entryID); lastContinueButton = continueButton; lastEntry.Sequence = originalSequence; npcPreDelaySettingsCopy.CopyTo(npcPreDelaySettings); pcPreDelaySettingsCopy.CopyTo(pcPreDelaySettings); // Populate UI with previous records: var lastInstance = (instantiatedMessages.Count > 0) ? instantiatedMessages[instantiatedMessages.Count - 1] : null; instantiatedMessages.Remove(lastInstance); DestroyInstantiatedMessages(); for (int i = 0; i < records.Count - 1; i++) { var entry = DialogueManager.MasterDatabase.GetDialogueEntry(records[i].conversationID, records[i].entryID); var speakerInfo = DialogueManager.ConversationModel.GetCharacterInfo(entry.ActorID); var listenerInfo = DialogueManager.ConversationModel.GetCharacterInfo(entry.ConversantID); var formattedText = FormattedText.Parse(entry.currentDialogueText, DialogueManager.MasterDatabase.emphasisSettings); var subtitle = new Subtitle(speakerInfo, listenerInfo, null, formattedText, "None()", entry.ResponseMenuSequence, entry); AddMessage(subtitle); } if (lastInstance != null) { instantiatedMessages.Add(lastInstance); lastInstance.transform.SetAsLastSibling(); } } finally { isLoadingGame = false; scrollRect.verticalNormalizedPosition = 0; continueButton = lastContinueButton; if (shouldShowContinueButton && lastContinueButton != null) { lastContinueButton.gameObject.SetActive(true); } } } ScrollToBottom(); }