Modding Dialogs
Tutorials
- Creating Hero Dialogue / Conversations
- Modding Conversations - research (OUTDATED?)
- Danqna and Gispry - Adding dialog with conditions and consequence
- Danqna and Gispry - Dialogue in game
- Custom Audio with LipSync
Implementation example
private void OnSessionLaunched(CampaignGameStarter starter)
{
AddDialogs(starter);
}
private void AddDialogs(CampaignGameStarter starter)
{
starter.AddPlayerLine("tavernkeeper_book", "tavernkeeper_talk", "tavernkeeper_book_seller_location", "Have you seen any book vendor recently?", TavernKeeperOnCondition, () => { GiveGoldAction.ApplyBetweenCharacters(null, Hero.MainHero, -5, false); }, 100, (out TextObject explanation) =>
{
if (Hero.MainHero.Gold < 5)
{
explanation = new TextObject("Not enough gold...");
return false;
}
else
{
explanation = new TextObject("5 {GOLD_ICON}");
return true;
}
});
starter.AddDialogLine("tavernkeeper_book_a", "tavernkeeper_book_seller_location", "tavernkeeper_books_thanks", "Yeah, saw {VENDOR.FIRSTNAME} recently. Look around the town.", () => { return IsBookVendorInTown(); }, null, 100, null);
starter.AddDialogLine("tavernkeeper_book_a", "tavernkeeper_book_seller_location", "tavernkeeper_books_thanks", "I heard you can find what you are looking for in {SETTLEMENT}.", () => { return IsBookVendorNearby(); }, null, 100, null);
starter.AddDialogLine("tavernkeeper_book_b", "tavernkeeper_book_seller_location", "tavernkeeper_books_thanks", "No, haven't heard lately.", null, null, 100, null);
starter.AddPlayerLine("tavernkeeper_book", "tavernkeeper_books_thanks", "tavernkeeper_pretalk", "Thanks!", null, null, 100, null, null);
starter.AddDialogLine("tavernkeeper_book", "tavernkeeper_pretalk", "tavernkeeper_talk", "Anything else?", null, null, 100, null);
}
// Condition example
private bool IsBookVendorInTown()
{
foreach (Hero vendor in _vendorList)
{
if (vendor.CurrentSettlement == Settlement.CurrentSettlement)
{
StringHelpers.SetCharacterProperties("VENDOR", vendor.CharacterObject, null, false);
return true;
}
}
return false;
}
Diagram of the example above:
AddPlayerLine
What player (you) says
AddPlayerLine(id, inputToken, outputToken, text, condition, consequence, priority, clickableCondition, persuasionOption)
- id - just a name for the entry, not used anywhere?
- inputToken - entry name, where we can come from another dialog line
- outputToken - where to go from here, to another dialog's line entry (inputToken). outputToken --> inputToken
- text - what to show
- condition - on what condition to show this dialog line (can be several, true - show, false - do not show, no condition -> show if no other conditions or other conditions false, hide if more conditions and one of it's true)
- priority - default 100, if you want to overwrite default dialog, make it greater, like 110 and use same id/inputToken
- clickableCondition - possible to disable with the explanation (example follows)
- persuasionOption - something about the persuasions, consult with dnSpy
Disable with Explanation

Disable the PlayerLine with the Explanation like this:
starter.AddPlayerLine("tavernkeeper_book", "tavernkeeper_talk", "tavernkeeper_book_seller_location", "{TAVERN_KEEPER_GREETING}", TavernKeeperOnCondition, () => { GiveGoldAction.ApplyBetweenCharacters(null, Hero.MainHero, -5, false); }, 100, (out TextObject explanation) =>
{
if (Hero.MainHero.Gold < 5)
{
explanation = new TextObject("Not enough gold...");
return false; // line is disabled
}
else
{
explanation = new TextObject("5 {GOLD_ICON}");
return true; // line is enabled
}
});
AddDialogLine
What NPC says
AddDialogLine(id, inputToken, outputToken, text, condition, consequence, priority, clickableCondition)
Parameters same as in AddPlayerLine.
InputToken - "start" on first dialog entry point and it needs a start condition.
The last line should have outputToken "end" if you want the dialog to end:
If you will use outputToken "end" with AddPlayerLine - the game will hang
Also it can be ''close_window'' (for notables at least)
starter.AddDialogLine("village_build_job", "village_build_job_options_selected", "close_window", "Great, let's start.", null, null);
Story demo
starter.AddPlayerLine("tavernkeeper_story", "tavernkeeper_talk", "tavernkeeper_story_part1", "Tell me a story", null, null, 100, null, null);
starter.AddDialogLine("tavernkeeper_story", "tavernkeeper_story_part1", "tavernkeeper_story_part2", "STORY PART 1", null, null, 100, null);
starter.AddDialogLine("tavernkeeper_story", "tavernkeeper_story_part2", "tavernkeeper_story_part3", "STORY PART 2", null, null, 100, null);
starter.AddDialogLine("tavernkeeper_story", "tavernkeeper_story_part3", "tavernkeeper_story_part_end", "STORY PART 3", null, null, 100, null);
starter.AddDialogLine("tavernkeeper_story", "tavernkeeper_story_part_end", "tavernkeeper_story_part_end_player", "THE END", null, null, 100, null);
starter.AddPlayerLine("tavernkeeper_story", "tavernkeeper_story_part_end_player", "tavernkeeper_story_part_end_teller", "Thank you. That was quite a story", null, null, 100, null, null);
starter.AddDialogLine("tavernkeeper_story", "tavernkeeper_story_part_end_teller", "tavernkeeper_talk", "I am glad you liked it.", null, null, 100, null);
AddRepeatablePlayerLine
Dynamic method to add several options to choose from.
AddRepeatablePlayerLine
(string id,
string inputToken,
string outputToken,
string text,
string continueListingRepeatedObjectsText,
string continueListingOptionOutputToken,
ConversationSentence.OnConditionDelegate conditionDelegate,
ConversationSentence.OnConsequenceDelegate consequenceDelegate,
int priority = 100,
ConversationSentence.OnClickableConditionDelegate clickableConditionDelegate = null)
Example in which we can choose what fief to give to our companion:
campaignGameStarter.AddRepeatablePlayerLine("turn_companion_to_lord_has_fief_list", "player_has_fief_list", "player_selected_fief_to_grant", "{=3rHeoq6r}{SETTLEMENT_NAME}.", "{=sxc2D6NJ}I am thinking of a different location.", "check_player_has_fief_to_grant", new ConversationSentence.OnConditionDelegate(CompanionRolesCampaignBehavior.list_player_fief_on_condition), new ConversationSentence.OnConsequenceDelegate(this.list_player_fief_selected_on_consequence), 100, new ConversationSentence.OnClickableConditionDelegate(CompanionRolesCampaignBehavior.list_player_fief_clickable_condition));
private static bool list_player_fief_on_condition()
{
Settlement settlement = ConversationSentence.CurrentProcessedRepeatObject as Settlement;
if (settlement != null)
{
ConversationSentence.SelectedRepeatLine.SetTextVariable("SETTLEMENT_NAME", settlement.Name);
}
return true;
}
AddDialogLineWithVariation
Different answers based on character traits for example:
From LordConversationsCampaignBehaviour
starter.AddDialogLineWithVariation("player_turns_down_surrender", "party_encounter_lord_hostile_attacker_3", "close_window", null, null, 100, "", "", "", "", null).Variation(new object[]
{
"{=QWzGkQrT}So we fight, then.[if:idle_angry][ib:warrior]",
"DefaultTag",
1
}).Variation(new object[]
{
"{=6i7a1c4E}Very well. Death before dishonor![if:idle_angry][ib:warrior]",
"PersonaEarnestTag",
1,
"ChivalrousTag",
1
}).Variation(new object[]
{
"{=FMJuPZlm}I'm not surrendering, so do what you must.[if:idle_angry][ib:warrior]",
"ChivalrousTag",
1
}).Variation(new object[]
{
"{=ZG6kWWwW}I'm not yielding, so let's go to it, then.[if:idle_angry][ib:warrior]",
"PersonaCurtTag",
1
}).Variation(new object[]
{
"{=SPYDUXvx}We meet on the battlefield, then.[if:idle_angry][ib:warrior]",
"PersonaSoftspokenTag",
1
}).Variation(new object[]
{
"{=3WA4MLzx}One way or the other, you'll regret this. If I fall, my people will have their revenge.[if:idle_angry][ib:warrior]",
"UncharitableTag",
1
}).Variation(new object[]
{
"{=yzzY4uXN}Very well. Expect no mercy.[if:idle_angry][ib:warrior]",
"CruelTag",
1,
"FriendlyRelationshipTag",
-1
});
AddDialogLineMultiAgent
No examples in the game code...
Just a guess that could be used in the dialog with several NPCs.
OneToOneConversationHero
Get the Hero you are talking to in the dialog
Notes
Requires to reload a game for a new dialog change to appear in-game.
- [ ] does not show up in the AddDialogLine. Maybe because of the [if:idle_angry][ib:warrior] tags.
String helpers
In ConditionDelegate set variables:
StringHelpers.SetCharacterProperties("HERO", hero.CharacterObject, null, false);
MBTextManager.SetTextVariable("GOLD_ICON", "{=!}<img src=\"General\\Icons\\Coin@2x\" extend=\"8\">", false);
MBTextManager.SetTextVariable("GREETING", "Howdy", false);
MBTextManager.SetTextVariable("SETTLEMENT", settlement.EncyclopediaLinkWithName, false);
Use in the dialog:
starter.AddDialogLine("a", "b", "c", "{GOLD_ICON} {GREETING} {HERO.NAME} in {SETTLEMENT}! {GOLD_ICON}", OnConditionDelegateFunction, null, 100, null);
For random text, generate it in the ConditionDelegate which is run on each menu instance.
Face/Body NPC Tags

Face/Body control tags for NPCs in Dialogs
Control how NPCs behave during the dialog.
Action after the dialog
In ConsequenceDelegate:
Campaign.Current.ConversationManager.ConversationEndOneShot += delegate
{
Mission.Current.EndMission();
};
You can try declaring the battle as an action and execute it after the conversation ended like this: