返回目录
Chapter 13 第十三章:创建对话
开发者文档 更新于 2024-03-21 19:32:12

第十三章:创建对话

本章节将指导你创建一个名为“DialogDemo”的对话模组,玩家可以与NPC交流,并有三个不同的对话选项来影响与NPC的关系。

创建模组

  1. 创建模组目录
  1. 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>

实现对话逻辑

  1. 创建C#类库项目
  1. DialogBehavior.cs
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)
        {
        }
    }
}
  1. 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());
            }
        }
    }
}

测试模块

关键函数

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函数用于添加玩家在对话中的选项。当你想要玩家能够在对话中做出选择时,你会使用此函数。这个函数允许定义玩家选项的文本、条件、后果以及优先级。

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需要回应玩家的选择或者向玩家提供信息时,你会使用此函数。

连接玩家和NPC的对话

在实际使用中,你会通过inputTokenoutputToken将玩家的选项和NPC的回应串联起来,形成一个完整的对话流程。

  1. 定义玩家选项:使用AddPlayerLine添加玩家的对话选项,设置outputToken为该选项对应的NPC回应的inputToken
  2. 定义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之间的互动提供丰富的内容。