返回目录
Chapter 15 第十五章:任务的制作
开发者文档 更新于 2024-04-24 20:15:56

第十五章:任务的制作

在这一章中,我们将学习如何为《骑马与砍杀2》创建一个名为“决斗任务”的模块。通过决斗解决与竞争对手的纷争,争取爱人的芳心。

创建C#类库项目

  1. 启动 Visual Studio
  2. 选择“创建新项目”。
  3. 搜索并选择“类库(.NET Framework)”,确保它与游戏兼容(建议.NET Framework 4.7.2)。
  4. 命名项目为 CompetitionQuest 并点击“创建”。

项目配置

创建模块目录和配置文件

SubModule.xml 示例配置

<?xml version="1.0" encoding="utf-8"?>
<Module>
  <Name value="Competition Quest"/>
  <Id value="CompetitionQuest"/>
  <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="CompetitionQuest"/>
      <DLLName value="CompetitionQuest.dll"/>
      <SubModuleClassType value="CompetitionQuest.MySubModule"/>
    </SubModule>
  </SubModules>
</Module>

C# 代码实现

创建 MySubModule.cs 文件

这个文件定义了模块的主要逻辑和初始化。

using TaleWorlds.CampaignSystem;
using TaleWorlds.Core;
using TaleWorlds.MountAndBlade;

namespace CompetitionQuest
{
    public class MySubModule : MBSubModuleBase
    {
        protected override void OnGameStart(Game game, IGameStarter gameStarterObject)
        {
            if (starterObject is CampaignGameStarter campaignGameStarter)
            {
                campaignGameStarter.AddBehavior(new QuestBehavior());
            }
        }
    }
}
创建任务类 CompetitionQuest

这个类继承自 StoryModeQuestBase,用于定义与处理整个任务的流程,包括对话、决斗以及任务的结果。

using System;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.GameMenus;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

namespace CompetitionQuest.Quests;

public class CompetitionQuest : StoryModeQuestBase
{
    [SaveableField(1)]
    private JournalLog _startLog;

    [SaveableField(2)]
    private Hero _competitor;

    [SaveableField(3)]
    private Hero _lover;

    public CompetitionQuest(string questId, Hero lover, Hero competitor, CampaignTime duration)
        : base(questId, lover, duration)
        {
            _competitor = competitor;
            _lover = lover;
            var startLog = GetStartLog(lover, competitor);
            _startLog = AddDiscreteLog(startLog, TalkLog, 0, 1);
            AddDialogs();
        }

    private TextObject GetStartLog(Hero lover, Hero competitor)
    {
        TextObject startLog = new TextObject("{PLAYER}与{RIVAL}因争夺{LOVED_ONE}的爱情而决定决斗。");
        startLog.SetTextVariable("PLAYER", Hero.MainHero.CharacterObject);
        startLog.SetTextVariable("LOVED_ONE", lover.CharacterObject);
        startLog.SetTextVariable("RIVAL", competitor.CharacterObject);
        return startLog;
    }

    private TextObject TalkLog => new TextObject("与{HERO_NAME}为了{LOVED_ONE}的爱情进行决斗。")
        .SetTextVariable("HERO_NAME", _competitor.Name)
        .SetTextVariable("LOVED_ONE", _lover.Name);

    protected override void RegisterEvents()
    {
        // 在此注册任务相关的事件
    }

    protected override void HourlyTick()
    {
        // 处理任务每小时的更新
    }

    private TextObject TimeOutLog => new TextObject("与{HERO_NAME}的决斗因时间耗尽而未能发生。")
        .SetTextVariable("HERO_NAME", _competitor.Name);

    protected override void OnTimedOut()
    {
        CompleteQuestWithTimeOut(TimeOutLog);
        _competitor.ForceNpcMarry(_lover, false);
    }

    public override TextObject Title => new TextObject("爱情决斗");

    protected override void InitializeQuestOnGameLoad()
    {
        SetDialogs();
    }

    protected override void SetDialogs()
    {
        AddDialogs();
    }

    private void AddDialogs()
    {
        Campaign.Current.ConversationManager.AddDialogFlow(CreateDuelQuestDialog(), this);
    }

    private DialogFlow CreateDuelQuestDialog()
    {
        return DialogFlow.CreateDialogFlow("hero_main_options", 150)
            .BeginPlayerOptions()
            .PlayerOption(new TextObject("我为{LOVED_ONE}的心挑战你!").SetTextVariable("LOVED_ONE", _lover.Name))
            .Condition(() => Hero.OneToOneConversationHero == _competitor)
            .NpcResponse(new TextObject("很好,让我们开始决斗!"))
            .Consequence(StartDuelWithCompetitor)
            .CloseDialog();
    }

    private void StartDuelWithCompetitor()
    {
        // 在此实现启动决斗的逻辑
    }

    private void CompleteDuel()
    {
        // 在此处理决斗完成后的逻辑
    }
}
QuestBehavior 类

此类将处理恋人和玩家之间的对话,以及启动决斗任务的逻辑。

using TaleWorlds.CampaignSystem;
using TaleWorlds.Localization;

namespace CompetitionQuest.Behaviors;

public class QuestBehavior : CampaignBehaviorBase
{
    public override void RegisterEvents()
    {
        CampaignEvents.OnSessionLaunchedEvent.AddNonSerializedListener(this, OnSessionLaunched);
    }

    private void OnSessionLaunched(CampaignGameStarter starter)
    {
        AddQuestDialogs(starter);
    }

    private void AddQuestDialogs(CampaignGameStarter starter)
    {
        // 添加对话选项,恋人让玩家决斗
        starter.AddPlayerLine("talk_to_lover", "hero_main_options", "lover_discuss_competition",
                              new TextObject("我们该如何处理那个混蛋的问题?").ToString(), null, null);

        starter.AddDialogLine("lover_suggest_duel", "lover_discuss_competition", "player_accept_duel",
                              new TextObject("我觉得你需要和他决斗,证明你的爱。”").ToString(),
                              null, null);

        starter.AddPlayerLine("player_agree_duel", "player_accept_duel", "close_window",
                              new TextObject("你说得对,我会证明我的爱!").ToString(), null, AgreeToDuel);
    }

    private void AgreeToDuel()
    {
        Hero player = Hero.MainHero;
        Hero lover = Hero.OneToOneConversationHero;
        Hero rival = lover.GetHighestRankedEnemy(); // 假设情敌是恋人认为的最大威胁,需要实现这个方法

        if (lover != null && rival != null)
        {
            CompetitionQuest competitionQuest = new CompetitionQuest("CompetitionDuelQuest", lover, rival, CampaignTime.Days(30));
            competitionQuest.StartQuest();
        }
    }

    public override void SyncData(IDataStore dataStore)
    {
    }
}