public TriggerControl GetTriggerFromAddress(Nwn2ConversationAddress address) { if (address == null) { throw new ArgumentNullException("address"); } if (address.AttachedAs == Sussex.Flip.Core.ScriptType.Conditional) { return(null); } NWN2GameModule mod = NWN2Toolset.NWN2ToolsetMainForm.App.Module; if (mod == null) { throw new InvalidOperationException("No module is open."); } NWN2GameConversation conversation = session.GetConversation(address.Conversation); if (conversation == null) { throw new ArgumentException("Could not find conversation '" + address.Conversation + "' in this module.", "conversation"); } if (NWN2Toolset.NWN2ToolsetMainForm.App.GetViewerForResource(conversation) == null) { conversation.Demand(); } NWN2ConversationLine line = conversation.GetLineFromGUID(address.LineID); if (line == null) { throw new ArgumentException("Could not find a line with the given ID in conversation '" + address.Conversation + "'.", "conversation"); } return(new DialogueWasSpoken(line.OwningConnector, conversation)); }
/// <summary> /// /// </summary> /// <param name="script"></param> /// <param name="attachment">Only return a script if it is attached /// in the manner indicated by this parameter.</param> /// <returns></returns> /// <remarks>This method expects that the NWN2GameScript is already Loaded /// (that is, the responsibility for calling Demand() falls to the client.)</remarks> public FlipScript GetFlipScript(NWN2GameScript script, Attachment attachment) { if (script == null) { throw new ArgumentNullException("script"); } string code, address, naturalLanguage; ScriptWriter.ParseNWScript(script.Data, out code, out address, out naturalLanguage); ScriptType scriptType = GetScriptType(script); if (attachment == Attachment.Ignore) { return(new FlipScript(code, scriptType, script.Name)); } NWN2GameModule mod = session.GetModule(); if (mod == null) { throw new InvalidOperationException("No module is open."); } Nwn2Address nwn2Address; Nwn2ConversationAddress nwn2ConversationAddress; switch (attachment) { case Attachment.Attached: nwn2Address = Nwn2Address.TryCreate(address); nwn2ConversationAddress = Nwn2ConversationAddress.TryCreate(address); break; case Attachment.AttachedToConversation: nwn2Address = null; nwn2ConversationAddress = Nwn2ConversationAddress.TryCreate(address); break; case Attachment.AttachedToScriptSlot: nwn2Address = Nwn2Address.TryCreate(address); nwn2ConversationAddress = null; break; default: nwn2Address = null; nwn2ConversationAddress = null; break; } if (nwn2Address != null) { try { if (nwn2Address.TargetType == Nwn2Type.Module) { IResourceEntry resource = typeof(NWN2ModuleInformation).GetProperty(nwn2Address.TargetSlot).GetValue(mod.ModuleInfo, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { return(new FlipScript(code, scriptType, script.Name)); } } else if (nwn2Address.TargetType == Nwn2Type.Area) { NWN2GameArea area = session.GetArea(nwn2Address.AreaTag); if (area != null) { IResourceEntry resource = typeof(NWN2GameArea).GetProperty(nwn2Address.TargetSlot).GetValue(area, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { return(new FlipScript(code, scriptType, script.Name)); } } } else { /* * The script might be attached to a Narrative Threads blueprint: */ // First check that if a blueprint which uses this tag as resref exists, it was created by Narrative Threads: if (nt.CreatedByNarrativeThreads(nwn2Address.TargetType, nwn2Address.InstanceTag)) { NWN2ObjectType objectType = Nwn2ScriptSlot.GetObjectType(nwn2Address.TargetType).Value; INWN2Blueprint blueprint = session.GetBlueprint(nwn2Address.InstanceTag.ToLower(), objectType); if (blueprint != null) { IResourceEntry resource = blueprint.GetType().GetProperty(nwn2Address.TargetSlot).GetValue(blueprint, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { return(new FlipScript(code, scriptType, script.Name)); } } } // Check through all OPEN areas. foreach (NWN2GameArea area in mod.Areas.Values) { if (!session.AreaIsOpen(area)) { continue; } NWN2InstanceCollection instances = session.GetObjectsByAddressInArea(nwn2Address, area.Tag); if (instances != null) { // Check the script is still attached to the target object in the slot it claims to be, // in at least one instance, and if so add it to the set of scripts to be opened: foreach (INWN2Instance instance in instances) { IResourceEntry resource = instance.GetType().GetProperty(nwn2Address.TargetSlot).GetValue(instance, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { return(new FlipScript(code, scriptType, script.Name)); } } } } } } catch (Exception x) { throw new ApplicationException(String.Format("Failed to handle script + '{0}' properly.", script.Name), x); } } else if (nwn2ConversationAddress != null) // Check through all conversations, regardless of whether they're open. { NWN2GameConversation conversation = session.GetConversation(nwn2ConversationAddress.Conversation); if (conversation == null) { return(null); } if (NWN2Toolset.NWN2ToolsetMainForm.App.GetViewerForResource(conversation) == null) { conversation.Demand(); } NWN2ConversationLine line = conversation.GetLineFromGUID(nwn2ConversationAddress.LineID); if (line == null) { return(null); } if (line.Actions.Count == 0) { return(null); } IResourceEntry resource = line.Actions[0].Script; if (resource != null && resource.ResRef.Value == script.Name) { return(new FlipScript(code, scriptType, script.Name)); } } return(null); }
/// <summary> /// If there already exists a conversation by the name in the module, then it is fetched, otherwise a new is created /// </summary> /// <param name="questName">The name of the quset</param> /// <param name="gender">The gender which will be used in the quest</param> /// <param name="lang">The spoken (real world) language</param> /// <returns>The conversation</returns> private NWN2GameConversation conversationFixer(string questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { String convName = String.Empty; NWN2GameConversation cConversation = null; /* If the actor is a creature and does not yet belong to a faction, * I set it to be a commoner. */ #region factionSet if (actor.type == EnumTypes.actorType.Creature) { if (actor.boolInstance) { NWN2CreatureInstance inst = (NWN2CreatureInstance)actor.instance; if (inst.FactionID < 0 || inst.FactionID > 12) { inst.FactionID = 2; } } else { NWN2CreatureBlueprint blue = (NWN2CreatureBlueprint)actor.blueprint; if (blue.FactionID < 0 || blue.FactionID > 12) { blue.FactionID = 2; } } } #endregion #region getConversationName if (actor.Conversation != null && System.IO.Path.GetFileNameWithoutExtension(actor.Conversation.FullName) != String.Empty) { // I get the name of what the conversation is/should be called convName = System.IO.Path.GetFileNameWithoutExtension(actor.Conversation.FullName); } else if (trigger != null) { convName = trigger.ToString() + "Conv"; } else { convName = questNamePrep(questName) + "_" + actor.ToString().Replace(" ", ""); } cConversation = module.Conversations[convName]; #endregion #region ensureConversation // If we still have no conversation, then we create one if (cConversation == null) { cConversation = new NWN2GameConversation(convName, module.Repository.DirectoryName, module.Repository); cConversation.Demand(); } else { cConversation.Demand(); // if we have a conversation, and we have not cleaned it yet - then we do so now, and makes // sure that no one else cleans it if (alreadyWiped[cConversation.Name] == null) { alreadyWiped[cConversation.Name] = true; NWN2ConversationConnectorCollection connectors = cConversation.StartingList; LinkedList<NWN2ConversationConnector> removeList = new LinkedList<NWN2ConversationConnector>(); foreach (NWN2ConversationConnector connnect in connectors) { if (connnect.Comment.Contains("pluginGenerated: " + questName + ":" + questId.ToString())) { removeList.AddLast(connnect); } } debug("Number of convs to remove: " + removeList.Count); foreach (NWN2ConversationConnector removeConnect in removeList) { debug("Removed conversation: " + removeConnect.Text[lang]); cConversation.RemoveNode(removeConnect); } } } cConversation.OEISerialize(true); cConversation.NWN1StyleDialogue = true; #endregion cConversation = constructConv(cConversation, questName, gender, lang); #region FixDoorTalk if (actor.type == EnumTypes.actorType.Placeable || actor.type == EnumTypes.actorType.Door) { NWN2GameScript talkScript = module.Scripts["ga_door_talk"]; if (talkScript == null) { talkScript = new NWN2GameScript("ga_door_talk", module.Repository.DirectoryName, module.Repository); talkScript.Data = Properties.Resources.ga_door_talk; talkScript.OEISerialize(); module.Scripts.Add(talkScript); } actor.doorTalk = talkScript.Resource; } #endregion if (triggerHappens != convType.Explore) actor.Conversation = cConversation.Resource; return cConversation; }
/// <summary> /// /// </summary> /// <param name="dict"></param> /// <param name="attachment"></param> /// <returns></returns> /// <remarks>Note that this automatically opens and closes areas/conversations etc. - it is only /// for use with analysis methods, not for users.</remarks> public List <ScriptTriggerTuple> GetAllScriptsFromModule(Attachment attachment) { NWN2GameModule mod = session.GetModule(); if (mod == null) { throw new InvalidOperationException("No module is open."); } NWN2GameScriptDictionary dict = mod.Scripts; if (attachment == Attachment.Ignore) { return(GetTuples(dict)); } Dictionary <Nwn2Address, FlipScript> moduleScripts = new Dictionary <Nwn2Address, FlipScript>(); Dictionary <Nwn2Address, FlipScript> areaScripts = new Dictionary <Nwn2Address, FlipScript>(); Dictionary <Nwn2ConversationAddress, FlipScript> conversationScripts = new Dictionary <Nwn2ConversationAddress, FlipScript>(); foreach (NWN2GameScript nwn2Script in dict.Values) { try { nwn2Script.Demand(); string code, address, naturalLanguage; ScriptWriter.ParseNWScript(nwn2Script.Data, out code, out address, out naturalLanguage); ScriptType scriptType = GetScriptType(nwn2Script); FlipScript script = new FlipScript(code, scriptType, nwn2Script.Name); Nwn2ConversationAddress ca = Nwn2ConversationAddress.TryCreate(address); if (ca != null) { conversationScripts.Add(ca, script); } else { Nwn2Address a = Nwn2Address.TryCreate(address); if (a != null) { if (a.TargetType == Nwn2Type.Module) { moduleScripts.Add(a, script); } else { areaScripts.Add(a, script); } } } nwn2Script.Release(); } catch (Exception) {} } List <ScriptTriggerTuple> scripts = new List <ScriptTriggerTuple>(dict.Count); // this is what we'll return if (attachment == Attachment.AttachedToConversation || attachment == Attachment.Attached) { // Index by conversation name, so we can check all the scripts for a conversation in one go. Dictionary <string, List <Nwn2ConversationAddress> > convNameIndex = new Dictionary <string, List <Nwn2ConversationAddress> >(); foreach (Nwn2ConversationAddress address in conversationScripts.Keys) { if (!convNameIndex.ContainsKey(address.Conversation)) { convNameIndex.Add(address.Conversation, new List <Nwn2ConversationAddress>()); } convNameIndex[address.Conversation].Add(address); } foreach (string convName in convNameIndex.Keys) { NWN2GameConversation conv = mod.Conversations[convName]; if (conv == null) { continue; } conv.Demand(); foreach (Nwn2ConversationAddress address in convNameIndex[convName]) { FlipScript script = conversationScripts[address]; NWN2ConversationLine line = conv.GetLineFromGUID(address.LineID); if (line == null) { continue; } if (address.AttachedAs == ScriptType.Standard && line.Actions.Count > 0) { IResourceEntry resource = line.Actions[0].Script; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); } } else if (address.AttachedAs == ScriptType.Conditional && line.OwningConnector.Conditions.Count > 0) { IResourceEntry resource = line.OwningConnector.Conditions[0].Script; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); } } } conv.Release(); } } if (attachment == Attachment.AttachedToScriptSlot || attachment == Attachment.Attached) { // First, just check for scripts attached to the module - easy: foreach (Nwn2Address address in moduleScripts.Keys) { FlipScript script = moduleScripts[address]; IResourceEntry resource = typeof(NWN2ModuleInformation).GetProperty(address.TargetSlot).GetValue(mod.ModuleInfo, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); } } // Next, check whether any script is attached to a Narrative Threads blueprint, and // if you find one, add it to the collection and remove it from consideration: List <Nwn2Address> processed = new List <Nwn2Address>(); foreach (Nwn2Address address in areaScripts.Keys) { if (Nwn2ScriptSlot.GetObjectType(address.TargetType) == null) { continue; // ignore area, module etc. } FlipScript script = areaScripts[address]; // First check that if a blueprint which uses this tag as resref exists, it was created by Narrative Threads: if (nt.CreatedByNarrativeThreads(address.TargetType, address.InstanceTag)) { NWN2ObjectType objectType = Nwn2ScriptSlot.GetObjectType(address.TargetType).Value; INWN2Blueprint blueprint = session.GetBlueprint(address.InstanceTag.ToLower(), objectType); if (blueprint != null) { IResourceEntry resource = blueprint.GetType().GetProperty(address.TargetSlot).GetValue(blueprint, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); processed.Add(address); } } } } foreach (Nwn2Address p in processed) { areaScripts.Remove(p); // has been added, so don't check for it more than once } // Then, open each area in turn, and see whether a script is attached to it. If it is, add // it to the collection and remove it from consideration: foreach (NWN2GameArea area in mod.Areas.Values) { if (areaScripts.Count == 0) { break; } session.OpenArea(area); processed = new List <Nwn2Address>(); foreach (Nwn2Address address in areaScripts.Keys) { FlipScript script = areaScripts[address]; if (address.TargetType == Nwn2Type.Area) { IResourceEntry resource = typeof(NWN2GameArea).GetProperty(address.TargetSlot).GetValue(area, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); processed.Add(address); // don't check whether to add it more than once } } else { NWN2InstanceCollection instances = session.GetObjectsByAddressInArea(address, area.Tag); if (instances != null) { // Check the script is still attached to the target object in the slot it claims to be, // in at least one instance, and if so add it to the set of scripts to be opened: foreach (INWN2Instance instance in instances) { IResourceEntry resource = instance.GetType().GetProperty(address.TargetSlot).GetValue(instance, null) as IResourceEntry; if (resource != null && resource.ResRef.Value == script.Name) { scripts.Add(new ScriptTriggerTuple(script, triggerFactory.GetTriggerFromAddress(address))); processed.Add(address); break; } } } } } foreach (Nwn2Address p in processed) { areaScripts.Remove(p); // has been added, so don't check for it more than once } session.CloseArea(area); } } return(scripts); }