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("{=LTE01209}Not enough gold...");
return false; // lines 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.
Start battle after the dialog
Not tested
You can try declaring the battle as an action and execute it after the conversation ended like this: