本章节将指导你创建一个名为“DialogDemo”的对话模组,玩家可以与NPC交流,并有三个不同的对话选项来影响与NPC的关系。
创建模组
- 创建模组目录:
- 在游戏的Modules目录下新建一个名为DialogDemo的文件夹。
- SubModule.xml配置:
- 在DialogDemo目录中创建一个名为SubModule.xml的文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<Module>
<Name value="Dialog Demo"/>
<Id value="DialogDemo"/>
<Version value="v1.0.0"/>
<SingleplayerModule value="true"/>
<MultiplayerModule value="false"/>
<DependedModules>
<DependedModule Id="Native"/>
<DependedModule Id="SandBoxCore"/>
<DependedModule Id="Sandbox"/>
<DependedModule Id="CustomBattle"/>
<DependedModule Id="StoryMode"/>
</DependedModules>
<SubModules>
<SubModule>
<Name value="DialogDemo"/>
<DLLName value="DialogDemo.dll"/>
<SubModuleClassType value="DialogDemo.MySubModule"/>
</SubModule>
</SubModules>
</Module>实现对话逻辑
- 创建C#类库项目:
- 新建一个名为DialogDemo的C#类库项目,设置参考第三章教程。
- DialogBehavior.cs:
- 创建一个名为DialogBehavior.cs的C#文件,用于定义对话行为和选项。
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Actions;
namespace DialogDemo
{
// DialogBehavior类扩展了CampaignBehaviorBase,以便在游戏中实现自定义行为。
public class DialogBehavior : CampaignBehaviorBase
{
// RegisterEvents方法用于注册事件。这里注册的事件是在游戏会话(Campaign)启动时触发的。
public override void RegisterEvents()
{
CampaignEvents.OnSessionLaunchedEvent.AddNonSerializedListener(this, OnSessionLaunched);
}
// OnSessionLaunched方法定义了当游戏会话启动时应该发生的行为。
private void OnSessionLaunched(CampaignGameStarter starter)
{
// 向玩家展示的初始对话选项,用于启动与NPC的对话。
starter.AddPlayerLine("dialog_demo_start_conversation", "hero_main_options", "dialog_demo_choice",
"我有些问题想问你…", null, null);
// NPC对玩家初始选项的回应,引导对话进入下一阶段。
starter.AddDialogLine("dialog_demo_choice_intro", "dialog_demo_choice", "dialog_demo_choice_output",
"当然,我愿意回答你的问题。", null, null);
// 玩家选择花费金币以增进与NPC的关系,这个选项不直接执行行为,而是转向NPC的回应。
starter.AddPlayerLine("dialog_demo_improve_relation", "dialog_demo_choice_output", "dialog_demo_improve_relation",
"我愿意花费1000金币来增进我们的关系(加好感)", CanPay1000Denars, null);
// 玩家选择辱骂NPC,这个选项也不直接执行行为,而是转向NPC的回应。
starter.AddPlayerLine("dialog_demo_insult", "dialog_demo_choice_output", "dialog_demo_insult", "你马没了(辱骂)", null,
null);
// 玩家选择结束对话的选项,转向NPC的回应,然后关闭对话窗口。
starter.AddPlayerLine("dialog_demo_leave", "dialog_demo_choice_output", "dialog_demo_leave", "没什么,我得走了。", null,
null);
// NPC对玩家选择增进关系的回应,这时执行Pay1000Denars函数,完成金币交易和关系改善。
starter.AddDialogLine("dialog_demo_npc_response_improve_relation", "dialog_demo_improve_relation",
"hero_main_options",
"非常感谢你的慷慨,这对我们的友谊大有帮助。", null, Pay1000Denars);
// NPC对玩家选择辱骂的回应,这时执行InsultNPC函数,降低玩家与NPC的关系。
starter.AddDialogLine("dialog_demo_npc_response_insult", "dialog_demo_insult", "hero_main_options",
"这样的言辞真是让人失望,我希望你能重新考虑你的行为。", null, InsultNPC);
// NPC对玩家选择结束对话的回应,简单地结束对话。
starter.AddDialogLine("dialog_demo_npc_response_leave", "dialog_demo_leave", "close_window",
"好吧,如果你有其他问题,随时欢迎回来。", null, null);
}
// CanPay1000Denars方法检查玩家是否有足够的金币进行交易。
private bool CanPay1000Denars()
{
return Hero.OneToOneConversationHero != null && Hero.MainHero.Gold >= 1000;
}
// Pay1000Denars方法处理玩家支付1000金币以增进与NPC的关系的逻辑。
private void Pay1000Denars()
{
Hero hero = Hero.OneToOneConversationHero;
if (hero != null)
{
GiveGoldAction.ApplyBetweenCharacters(Hero.MainHero, hero, 1000);
ChangeRelationAction.ApplyPlayerRelation(hero, 1);
}
}
// InsultNPC方法处理玩家辱骂NPC,降低与NPC的关系的逻辑。
private void InsultNPC()
{
Hero hero = Hero.OneToOneConversationHero;
if (hero != null)
{
ChangeRelationAction.ApplyPlayerRelation(hero, -10);
}
}
// SyncData方法用于同步数据,此处未使用。
public override void SyncData(IDataStore dataStore)
{
}
}
}- MySubModule.cs:
创建MySubModule.cs文件,用于将DialogBehavior添加到游戏中。
using TaleWorlds.CampaignSystem;
using TaleWorlds.Core;
using TaleWorlds.MountAndBlade;
namespace DialogDemo
{
public class MySubModule : MBSubModuleBase
{
protected override void OnGameStart(Game game, IGameStarter gameStarter)
{
if (game.GameType is Campaign)
{
var campaignGameStarter = (CampaignGameStarter)gameStarter;
campaignGameStarter.AddBehavior(new DialogBehavior());
}
}
}
}测试模块
- 编译项目,并将生成的DLL文件放入DialogDemo模块的bin\Win64_Shipping_Client目录下。
- 启动游戏并激活DialogDemo模块,然后在游戏中随便找一个英雄进行交流。
关键函数
AddPlayerLine 函数
public ConversationSentence AddPlayerLine(
string id,
string inputToken,
string outputToken,
string text,
ConversationSentence.OnConditionDelegate conditionDelegate,
ConversationSentence.OnConsequenceDelegate consequenceDelegate,
int priority = 100,
ConversationSentence.OnClickableConditionDelegate clickableConditionDelegate = null,
ConversationSentence.OnPersuasionOptionDelegate persuasionOptionDelegate = null)
{
return this.AddDialogLine(new ConversationSentence(id, new TextObject(text), inputToken, outputToken, conditionDelegate, clickableConditionDelegate, consequenceDelegate, 1U, priority, persuasionOptionDelegate: persuasionOptionDelegate));
}AddPlayerLine函数用于添加玩家在对话中的选项。当你想要玩家能够在对话中做出选择时,你会使用此函数。这个函数允许定义玩家选项的文本、条件、后果以及优先级。
- id: 对话句子的唯一标识符。
- inputToken: 输入令牌,定义了此对话选项将从哪个对话状态(或节点)跳转。
- outputToken: 输出令牌,定义了选中此对话选项后将跳转到哪个对话状态。
- text: 显示给玩家的文本内容。
- conditionDelegate: 决定此对话选项是否显示的条件。
- consequenceDelegate: 玩家选择此对话选项后执行的后果或行动。
- priority: 对话选项的显示优先级,默认为100。
- clickableConditionDelegate: 决定此对话选项是否可点击的额外条件。
- persuasionOptionDelegate: 用于劝说相关选项的委托,通常为空。
AddDialogLine 函数
public ConversationSentence AddDialogLine(
string id,
string inputToken,
string outputToken,
string text,
ConversationSentence.OnConditionDelegate conditionDelegate,
ConversationSentence.OnConsequenceDelegate consequenceDelegate,
int priority = 100,
ConversationSentence.OnClickableConditionDelegate clickableConditionDelegate = null)
{
return this.AddDialogLine(new ConversationSentence(id, new TextObject(text), inputToken, outputToken, conditionDelegate, clickableConditionDelegate, consequenceDelegate, priority: priority));
}AddDialogLine函数用于添加NPC的对话文本。当NPC需要回应玩家的选择或者向玩家提供信息时,你会使用此函数。
- id: 对话句子的唯一标识符。
- inputToken: 输入令牌,定义了此对话句子将从哪个对话状态(或节点)跳转。
- outputToken: 输出令牌,定义了此对话句子后将跳转到哪个对话状态。
- text: NPC向玩家显示的文本内容。
- conditionDelegate: 决定此对话句子是否显示的条件。
- consequenceDelegate: 在此对话句子显示后执行的后果或行动。
- priority: 对话句子的显示优先级,默认为100。
- clickableConditionDelegate: 决定此对话句子是否可点击的额外条件。
连接玩家和NPC的对话
在实际使用中,你会通过inputToken和outputToken将玩家的选项和NPC的回应串联起来,形成一个完整的对话流程。
- 定义玩家选项:使用AddPlayerLine添加玩家的对话选项,设置outputToken为该选项对应的NPC回应的inputToken。
- 定义NPC回应:使用AddDialogLine添加NPC的回应,设置inputToken为与之前定义的玩家选项outputToken相匹配。
例如,如果你想要玩家有一个“询问任务”的选项,并且NPC对此有回应:
starter.AddPlayerLine("ask_about_mission", "hero_main_options", "npc_response_mission",
"关于那个任务…", null, null);
starter.AddDialogLine("npc_response_mission", "npc_response_mission", "hero_main_options",
"哦,你是想知道那个任务的详情吗?", null, null);在这个例子中,玩家的选择通过outputToken("npc_response_mission")与NPC的回应inputToken(同样是"npc_response_mission")连接起来,从而实现了一个简单的问答对话。通过这种方式,你可以创建复杂的对话树,为玩家和NPC之间的互动提供丰富的内容。