《饥荒联机版》模组:所有角色夜晚讲故事功能实现

ChatGPT4o 使用 ChatGPT 4o 回答

问题:

我想编写一个游戏模组,游戏名是《饥荒联机版》,该游戏英文名是《Don't Starve Together》,该游戏模组由lua语言编写,游戏内有一名叫做沃尔特的角色,英文名是Walter,玩家可以使用该角色在夜晚,用鼠标右键在火坑使用讲故事的能力。请你参考角色沃尔特讲故事的游戏相关代码,帮我编写一个模组,让所有角色,包括模组角色,获得跟沃尔特相同的讲故事能力。故事的内容可以在模组内自定义修改,并且每天晚上都会随机讲多个不同的故事,直到故事列表所有不同的故事都讲完,才能讲之前讲过的故事。并且讲故事时,每句话的语速可以在代码中自行调整,请帮我写一个模组实现以上功能。

回答:

好的,我可以帮助你编写一个《Don't Starve Together》的模组,使所有角色都能在夜晚使用讲故事的能力。我们将参考沃尔特的讲故事功能,并扩展到所有角色。以下是一个基本的模组代码框架,你可以根据需要进行自定义。

首先,创建一个新的模组文件夹,并在其中创建以下文件和文件夹结构:

modinfo.lua
modmain.lua
scripts/
    components/
        storyteller.lua
    prefabs/
        storybook.lua

1. modinfo.lua

这是模组的基本信息文件。

name = "Universal Storyteller"
description = "All characters can tell stories at night."
author = "Your Name"
version = "1.0"

forumthread = ""

api_version = 10

dst_compatible = true
all_clients_require_mod = true
client_only_mod = false

icon_atlas = "modicon.xml"
icon = "modicon.tex"

2. modmain.lua

这是模组的主文件,负责初始化和加载模组功能。

PrefabFiles = {
    "storybook",
}

local function AddStorytellerComponent(inst)
    if not inst.components.storyteller then
        inst:AddComponent("storyteller")
    end
end

local function OnPlayerSpawn(inst)
    inst:DoTaskInTime(0, function()
        AddStorytellerComponent(inst)
    end)
end

AddPlayerPostInit(OnPlayerSpawn)

3. scripts/components/storyteller.lua

这是自定义的讲故事组件。

local Storyteller = Class(function(self, inst)
    self.inst = inst
    self.stories = {
        "Once upon a time...",
        "In a land far, far away...",
        "There was a brave adventurer...",
        -- Add more stories here
    }
    self.current_story_index = 1
    self.story_interval = 2 -- Time between sentences
end)

function Storyteller:TellStory()
    if not self.inst.components.talker then
        self.inst:AddComponent("talker")
    end

    local function TellNextSentence()
        if self.current_story_index <= #self.stories then
            self.inst.components.talker:Say(self.stories[self.current_story_index])
            self.current_story_index = self.current_story_index + 1
            self.inst:DoTaskInTime(self.story_interval, TellNextSentence)
        else
            self.current_story_index = 1
        end
    end

    TellNextSentence()
end

function Storyteller:OnRightClick()
    if TheWorld.state.isnight then
        self:TellStory()
    else
        self.inst.components.talker:Say("I can only tell stories at night.")
    end
end

return Storyteller

4. scripts/prefabs/storybook.lua

这是一个虚拟的物品,用于触发讲故事功能。

local function OnRightClick(inst, doer, target, actions, right)
    if right and doer.components.storyteller then
        table.insert(actions, ACTIONS.TELLSTORY)
    end
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddNetwork()

    inst:AddTag("storybook")

    if not TheWorld.ismastersim then
        return inst
    end

    inst.entity:SetPristine()

    inst:AddComponent("inspectable")

    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem.imagename = "storybook"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/storybook.xml"

    inst:AddComponent("useableitem")
    inst.components.useableitem:SetOnUseFn(function(inst, doer)
        if doer.components.storyteller then
            doer.components.storyteller:OnRightClick()
        end
    end)

    return inst
end

return Prefab("common/inventory/storybook", fn, assets)

5. images/inventoryimages/storybook.xmlimages/inventoryimages/storybook.tex

你需要创建一个图标文件用于故事书物品。你可以使用 TexTool 工具将 PNG 图像转换为 .tex 格式,并创建相应的 .xml 文件。

6. scripts/actions.lua

定义一个新的动作 TELLSTORY

local Action = GLOBAL.Action
local ACTIONS = GLOBAL.ACTIONS

ACTIONS.TELLSTORY = Action({ priority = 10, rmb = true })
ACTIONS.TELLSTORY.id = "TELLSTORY"
ACTIONS.TELLSTORY.str = "Tell Story"
ACTIONS.TELLSTORY.fn = function(act)
    if act.doer.components.storyteller then
        act.doer.components.storyteller:OnRightClick()
        return true
    end
end

AddAction(ACTIONS.TELLSTORY)

7. scripts/stategraphs/SGwilson.lua

添加新的状态图以处理讲故事动作。

local State = GLOBAL.State
local EventHandler = GLOBAL.EventHandler
local TimeEvent = GLOBAL.TimeEvent

local function TellStoryAction(inst)
    if inst.components.storyteller then
        inst.components.storyteller:OnRightClick()
    end
end

AddStategraphActionHandler("wilson", GLOBAL.ActionHandler(GLOBAL.ACTIONS.TELLSTORY, "doshortaction"))

AddStategraphState("wilson", State{
    name = "tellstory",
    tags = { "doing", "busy" },

    onenter = function(inst)
        inst.components.locomotor:Stop()
        inst.AnimState:PlayAnimation("idle")
        inst:PerformBufferedAction()
    end,

    timeline = {
        TimeEvent(0, TellStoryAction),
    },

    events = {
        EventHandler("animover", function(inst)
            inst.sg:GoToState("idle")
        end),
    },
})

自定义故事内容和语速

你可以在 storyteller.lua 文件中自定义故事内容和语速:

self.stories = {
    "Once upon a time...",
    "In a land far, far away...",
    "There was a brave adventurer...",
    -- Add more stories here
}
self.story_interval = 2 -- Time between sentences

以上代码提供了一个基本的框架,你可以根据需要进行扩展和修改。希望这能帮助你实现你的模组!