目录

我的学习分享

记录精彩的程序人生

X

Stendhal任务编码二

您可能希望首先阅读Stendhal任务编码一

询问玩家是否要完成任务

现在我们希望Hayunn向玩家询问他是否会提供帮助:

     quest:我的嘴干了,但我不能放弃这个教室! 你能从酒馆给我带些啤酒吗?
         yes:谢谢!我会在这儿等待。 当然还要守卫。
         no:哦,那就好好忘了。 我想我只是希望它开始下雨,然后我的嘴张开。

作为一个小练习,您可以对此部分进行编码,以检查您是否理解本教程的第一部分。

但是,当前解决方案存在一个小问题:“yes”和“no”只能有一个回复。 所以NPC只能问一个问题才能处理答案。

幸运的是有一个解决方案:NPC需要记住对话的状态:
Npc simple.png

目前我们的NPC知道两种状态:IDLE用于四处走动和ATTENDING用于与玩家交谈。 您可以通过与NPC交谈来改变状态。 因此,如果NPC是IDLE,它将接受“hi”并继续进入ATTENDING状态。 如果再次说“hi”,则不会发生任何事情因为“hi”在这种状态下是未知的。 然而,NPC现在将回复“工作”和“帮助”。 您可以用“再见”结束对话,这将导致NPC返回IDLE(并开始再次走动)。

所以,让我们回到我们的例子。 我们希望NPC回答“是”和“否”,但只有在询问了任务问题之后。 所以我们添加了一个名为QUEST_OFFERED的第三个状态。 当玩家说“任务”时,NPC会进入该状态。 在“是”或“否”时,它返回到ATTENDING。
Npc with quest question.png

您可能已经在上图中注意到有一种叫做“ANY”的东西。 这是一种特殊的“状态”,允许在任何状态下触发与传出箭头相关联的触发器。 除了应该始终有效的“再见”之外,你不应该使用它。

好的,现在有足够的理论,让我们写一些代码:

public void prepareQuestStep() {

    // get a reference to the Hayunn npc
    SpeakerNPC npc = npcs.get("Hayunn Naratha");

    // ...

    // if the player asks for a quest, go to state QUEST_OFFERED
    npc.add(ConversationStates.ATTENDING,
        ConversationPhrases.QUEST_MESSAGES, 
        null,
        ConversationStates.QUEST_OFFERED, 
        "My mouth is dry, but I can't be seen to abandon this teaching room! Could you bring me some beer from the tavern?",
        null);

    // in state QUEST_OFFERED, accept "yes" and go back to ATTENDING
    npc.add(
        ConversationStates.QUEST_OFFERED,
        ConversationPhrases.YES_MESSAGES,
        null,
        ConversationStates.ATTENDING,
        "Thanks! I'll be right here, waiting. And guarding, of course.",
        null);

    // in state QUEST_OFFERED, accept "no" and go back to ATTENDING
    npc.add(
        ConversationStates.QUEST_OFFERED,
        ConversationPhrases.NO_MESSAGES,
        null,
        ConversationStates.ATTENDING,
        "Oh, well forget it then. I guess I'll just hope for it to start raining, and then stand with my mouth open.",
        null);
}

如您所见,我们现在必须使用“add()”而不是“addReply()”,并且该方法有更多参数。

我们在ConversationStates类中预定了一些您可以和应该使用的状态。

图示

最后一件事让您的生活更轻松:如果您使用Linux,安装了graphviz软件包并且您是游戏中的管理员,则可以在NPC的右键菜单中选择View Transitions。 这将生成与上面的图像非常相似的当前转换图的图像。

Conditions And Actions

Hayunn现在有一个短暂的记忆,这对于提问而言很酷。

在我们看一下长期记忆之前,我们先对ChatConditions和ChatActions这个主题进行一些游览。 如果指定了ChatCondition,则必须将其评估为true才能将转换考虑在内。 我们来看一个简单的例子:

    npc.add(ConversationStates.IDLE,
        "hi", 
        new LevelLessThanCondition(6), 
        ConversationStates.IDLE, 
        "Oh sorry, you have way too little experience.",
        null);

NPC将拒绝与低于6级的玩家交谈。

在执行转换后执行ChatAction。 以下示例打开Semos city的地图,如果玩家要求它。

    npc.add(
        ConversationStates.ATTENDING,
        "map",
        null,
        ConversationStates.ATTENDING,
        "1 Townhall, Tad lives here,   2 Library,   3 Bank,   4 Bakery, ...",
       	new ExamineChatAction("map-semos-city.png", "Semos City", "Map of Semos City"));

有许多预制的ChatConditions和ChatActions。 您可以轻松地使用它们。 其中许多需要一些参数,这些参数记录在链接的地方。 当然,您可以针对特殊情况编写自己的条件和操作。

教NPC记住玩家

好的,让我们回到主题:Hayunn需要长期记忆才能每位玩家只接受一杯啤酒。 毕竟他是值班的,一个完全醉酒的老师不好......

长期记忆称为“任务槽”。 它基本上是一个哈希表,每个任务有一行。 您可能还记得我们在本教程开头添加的模板中的以下行:

public static final String QUEST_SLOT = "beer_hayunn";

这就是我们正在使用的插槽的名称。 它必须是独一无二的,但除此之外,我们可以在那里写任何我们想要的东西。 但是,有两个约定使事情变得容易:多个值由“;”分隔 没有空格。 术语“done”和“rejected”用于表示完成或拒绝的任务。 有许多基于这些约定的预定义聊天条件和操作。

话虽如此,让我们让Hayunn检查任务状态并做出相应的回复:

public void prepareQuestStep() {

    // get a reference to the Hayunn npc
    SpeakerNPC npc = npcs.get("Hayunn Naratha");

    // ...

    // check that the player has not completed the quest, yet.
    npc.add(ConversationStates.ATTENDING,
        ConversationPhrases.QUEST_MESSAGES, 
        new QuestNotCompletedCondition(QUEST_SLOT),
        ConversationStates.QUEST_OFFERED, 
        "My mouth is dry, but I can't be seen to abandon this teaching room! Could you bring me some #beer from the #tavern?",
        null);

    // send him away if he has completed the quest already.
    npc.add(ConversationStates.ATTENDING,
        ConversationPhrases.QUEST_MESSAGES,
        new QuestCompletedCondition(QUEST_SLOT),
        ConversationStates.ATTENDING, 
        "Thanks all the same, but I don't want to get too heavily into drinking; I'm still on duty, you know! I'll need my wits about me if a student shows up...",
        null);

    // ...
}

请注意,如果任务已经完成,Hayunn将保持在ATTENDING状态。

下一步是保存任务完成。 我们暂时采取一种简单的方法,只检查玩家是否拥有啤酒:

private void prepareBringingStep() {
    SpeakerNPC npc = npcs.get("Hayunn Naratha");

    // if the players says "beer" and owns one, we set the quest slot to "done".
    npc.add(
        ConversationStates.ATTENDING,
        "beer",
        new PlayerHasItemWithHimCondition("beer"),
        ConversationStates.ATTENDING,
        "*glug glug* Ah! That hit the spot. Let me know if you need anything, ok?",
        new SetQuestAction(QUEST_SLOT, "done"));
}

当然我们需要在addToWorld中添加一个prepareBringingStep()的调用 。

本教程的第三部分

恭喜你,如果你做到这一点。 您现在可以处理基本条件和操作。 而且你可以处理短期和长期记忆。 本教程的第三部分和最后一部分将解释您如何接受任务项目并奖励玩家。 它也描述了一些先进的技术。 在继续本教程的第三部分之前,请确保本教程的步骤有效。