/// <summary> /// Creates a conversation that contains a conflict (i.e. the actor will turn hostile) /// </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 conflictFixer(string questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { // I set the villian to drop the needed loot addInv(); NWN2GameConversation cConversation = null; /* If the villian does not talk to the player, but just attacks, then we don't need to any of the following */ if (!villianTalk) { ushort hostile = 0; foreach (NWN2Faction fact in module.FactionData.Factions) { if (fact.Name == "Hostile") { hostile = (ushort)fact.ID; debug("Value for hostile: " + hostile.ToString()); break; } } if (actor.boolInstance) { NWN2CreatureInstance insActor = (NWN2CreatureInstance)actor.instance; insActor.FactionID = hostile; } else { NWN2CreatureBlueprint bluActor = (NWN2CreatureBlueprint)actor.blueprint; bluActor.FactionID = hostile; } } else { NWN2GameScript killActor = getAdvanceJournal(); questName = questNamePrep(questName); NWN2ScriptVarTable varTable; NWN2CreatureBlueprint creatureBlue = null; NWN2CreatureInstance creatureInst = null; if (actor.boolInstance) { creatureInst = (NWN2CreatureInstance)actor.instance; varTable = creatureInst.Variables; } else { creatureBlue = (NWN2CreatureBlueprint)actor.blueprint; varTable = creatureBlue.Variables; } if (varTable == null) { varTable = new NWN2ScriptVarTable(); } // I remove any old duplicates LinkedList<string> toRemove = new LinkedList<string>(); toRemove.AddLast("DeathScript"); varTable = getAdvanceJournalVar(varTable, questName, questId, xp, toRemove); var deathScript = new NWN2ScriptVariable("DeathScript", "ga_advance_journal"); varTable.Add(deathScript); if (creatureInst != null) { creatureInst.Variables = varTable; } else if (creatureBlue != null) { creatureBlue.Variables = varTable; } cConversation = conversationFixer(questName, gender, lang); } return cConversation; }
/// <summary> /// Either creates or add an entry to the journal that goes with the quest - there will only be one journal pr. quest /// </summary> /// <param name="name">The name of the journal category</param> /// <param name="priority">The priority of the journal entry</param> /// <param name="gender">The gender of the journal entry</param> /// <param name="lang">The language of the journal</param> /// <param name="category">The category that belong to the quest</param> /// <returns>The created journal</returns> public NWN2JournalCategory createJournal(string name, NWN2JournalPriority priority, BWLanguages.Gender gender, BWLanguages.BWLanguage lang, NWN2JournalCategory category) { int localQuestID = (questId == 0) ? 1 : questId; string tag = "Q_" + questNamePrep(name); foreach (NWN2JournalCategory jourCat in module.Journal.Categories) { if (jourCat.Tag == tag) { category = jourCat; break; } } if (category == null) { category = module.Journal.AddCategory(); category.Name.SetString(name, lang, gender); category.Priority = priority; //I create the tag category.Tag = tag; } LinkedList<NWN2JournalEntry> journalEnties = new LinkedList<NWN2JournalEntry>(); NWN2JournalEntry tempJournalEntry; if (localQuestID == 1) { /* for (int i = 0; i < category.Entries.Count; i++) { tempJournalEntry = category.Entries[i]; if ("pluginGenerated:" + localQuestID.ToString() == tempJournalEntry.Comment) { debug("equal comment"); journalEnties.AddLast(tempJournalEntry); break; } } foreach (NWN2JournalEntry tempJournal in journalEnties) { debug("journal entry: " + tempJournal.Text[lang]); category.Entries.Remove(tempJournal); } * */ // If we are starting at a new quest, and there are risidual objects, we just clear them all category.Entries.Clear(); } NWN2JournalEntry entry = category.AddEntry(); entry.ID = (uint)localQuestID; entry.Endpoint = endPoint; entry.Comment = "pluginGenerated:" + entry.ID; entry.Text.SetString(journal, lang, gender); return category; }
/// <summary> /// Transforms a string into a OEIExoLocString with the same information /// </summary> /// <param name="sInput">The string that is to be copied</param> /// <param name="lang">The current Language</param> /// <param name="gender">The current gender</param> /// <returns>The OEIExoLocString with the information from the str, language and gender</returns> private static OEIExoLocString StringtoOEIE(string sInput, BWLanguages.BWLanguage lang, BWLanguages.Gender gender) { OEIExoLocString str = new OEIExoLocString(); OEIExoLocSubString item = new OEIExoLocSubString(); item.Language = lang; item.Gender = gender; item.Value = sInput; str.Strings.Add(item); return str; }
/// <summary> /// Adds a conversation to an actor /// </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> public void addConv(string questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { questName = questNamePrep(questName); NWN2GameConversation cConversation = null; if (happensEnum == EnumTypes.happens.Conv) { cConversation = conversationFixer(questName, gender, lang); } else if (happensEnum == EnumTypes.happens.Conflict) { cConversation = conflictFixer(questName, gender, lang); } else if (happensEnum == EnumTypes.happens.OpenDoor) { doorFixer(questName, gender, lang); } else { cConversation = triggerFixer(questName, gender, lang); } if (cConversation != null) module.AddResource(cConversation); }
/// <summary> /// Sets all the triggers values so that it has the correct triggers /// </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 triggerFixer(string questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { NWN2GameConversation cConversation = null; if (triggerHappens == convType.Explore) { NWN2ScriptVarTable varTable = trigger.Var; if (varTable == null) { varTable = new NWN2ScriptVarTable(); } condAdvance(trigger, varTable, questName, questId, xp, "ga_advance_journal", "XP granted for exploration"); } else if (triggerHappens == convType.Escort) { cConversation = conversationFixer(questName, gender, lang); makeEscort(actor.Tag, trigger, cConversation.Name, questName, questId); } return cConversation; }
/// <summary> /// Currently not correctly implemented - this should make sure that once you open a door/gets an item then the quest is updated /// I have yet to find a way to do this without writing a new script - but perhaps you have an idea - if so you are more than welcome /// to contact me /// </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 void doorFixer(string questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { addInv(); NWN2GameScript advanceScript = getAdvanceJournal(); var varTable = new NWN2ScriptVarTable(); varTable = getAdvanceJournalVar(varTable, questName, questId, xp); var resource = advanceScript.Resource; if (actor.type == EnumTypes.actorType.Door) { if (actor.boolInstance) { var instDoor = (NWN2DoorInstance)actor.instance; instDoor.Variables = varTable; instDoor.OnDeath = advanceScript.Resource; instDoor.OnOpen = resource; } else { var blueDoor = (NWN2DoorBlueprint)actor.blueprint; blueDoor.Variables = varTable; blueDoor.OnDeath = resource; blueDoor.OnOpen = resource; } } else if (actor.type == EnumTypes.actorType.Placeable) { if (actor.boolInstance) { var instPlaceable = (NWN2PlaceableInstance)actor.instance; instPlaceable.Variables = varTable; instPlaceable.OnDeath = resource; if (containerContains && villianItem != null) { NWN2InstanceInventoryItem instanceItem = null; if (villianItem.boolInstance) { instanceItem = createInstanceItemInfo((NWN2ItemInstance)villianItem.instance, false, false); } else { instanceItem = createInstanceItemInfo((NWN2ItemBlueprint)villianItem.blueprint, false, false); } instPlaceable.Inventory.Add(instanceItem); instPlaceable.OnInvDisturbed = resource; } else { instPlaceable.OnOpen = resource; } } else { var bluePlaceable = (NWN2PlaceableBlueprint)actor.blueprint; bluePlaceable.Variables = varTable; bluePlaceable.OnDeath = resource; if (containerContains && villianItem != null) { NWN2BlueprintInventoryItem blueItemItem = null; if (villianItem.boolInstance) { blueItemItem = createBlueprintItemInfo((NWN2ItemInstance)villianItem.instance, false, false); } else { blueItemItem = createBlueprintItemInfo((NWN2ItemBlueprint)villianItem.blueprint, false, false); } bluePlaceable.Inventory.Add(blueItemItem); bluePlaceable.OnInvDisturbed = resource; } else { bluePlaceable.OnOpen = resource; } } } }
/// <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> /// The method that makes sure the correct scripts and conditionas are set on the conversation /// </summary> /// <param name="cConversation">The conversation</param> /// <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 constructConv(NWN2GameConversation cConversation, String questName, BWLanguages.Gender gender, BWLanguages.BWLanguage lang) { // Done in order to avoid a side condition int value = (questId == 0) ? 1 : questId; /* if (happensEnum == EnumTypes.happens.Trigger && triggerHappens == convType.Explore) { var tempConv = cConversation.InsertChild(null); tempConv.Text.SetString(String.Empty, lang, gender); tempConv.Speaker = trigger.Tag; tempConv.Comment = "pluginGenerated:" + value; tempConv.ShowOnce = NWN2ConversationShowOnceType.OncePerModule; // cConversation.InsertChild(tempConv); return cConversation; } */ // I add it to null to indicate that this will be at the root NWN2ConversationConnector conv = cConversation.InsertChild(null); // I set the comments so that it later can be deleted (if you choose to recreate the quest) conv.Comment = "pluginGenerated: " + questName + ":" + questId.ToString(); // I begin the conversation debug("Begin conversation"); conv.Text.SetString(greeting, lang, gender); // I make sure it is only fired once if we are talking escort/exploration NWN2ConversationConnector accept; NWN2ConversationConnector quest; NWN2ConversationConnector reject; #region Conditions // if this requires a node to fire, then we add the requirement here if (// If there is a prerequisite preReq != EnumTypes.prereq.NoPrereq || // or if we are exploring or escorting happensEnum == EnumTypes.happens.Trigger //&& (convHappens == convType.Escort || convHappens == convType.Explore) ) { debug("conditional"); conv.Conditions.Add(conditional(questName)); if (happensEnum == EnumTypes.happens.Trigger || convHappens != convType.None) { // It must be inserted as the first thing conv.Conditions.Insert(0, node()); } } // Once the offer has been accepted it should not appear again debug("makeJournal"); conv.Conditions.Add(makeJournalCheck(questName, "<" + value)); #endregion // If this is only a single comment I add the journal entry - if there is one (or we are opening a door) if (happensEnum == EnumTypes.happens.Trigger || happensEnum == EnumTypes.happens.OpenDoor || (convEnum == EnumTypes.conv.Single && /* since I have made sure that the villian only can call this if he is actually talking, we only need to make sure that we are doing something */ happensEnum != EnumTypes.happens.None)) { debug("setConvValues"); setConvValues(ref conv, ref conv, questName); /* If we are not dealing with a villain, then this is needed to make quest updates fire otherwise any quest update will not fire */ if (happensEnum != EnumTypes.happens.Conflict) cConversation.InsertChild(conv); } else #region Quest if (convEnum == EnumTypes.conv.QuestInfo && happensEnum != EnumTypes.happens.Trigger && happensEnum != EnumTypes.happens.None) { // The player accepts accept = cConversation.InsertChild(conv); accept.Text.SetString(acceptence, lang, gender); // The quest giver responce quest = cConversation.InsertChild(accept); quest.Text.SetString(action, lang, gender); setConvValues(ref accept, ref quest, questName); // The player declines reject = cConversation.InsertChild(conv); reject.Text.SetString(rejection, lang, gender); } #endregion return cConversation; }