饥荒mod开发——消耗道具通用组件

通用:
组件为主客机通用组件,应该在客机添加,主客机分别配置,可以配置的有:

  • 客机配置:
    • userCheckFn(inst, doer, target) 对玩家的检测,为nil则表示任何玩家可使用,默认nil
    • targetCheckFn(inst, doer, target) 对目标对象的检测,为nil则表示任何目标都行,默认只能对玩家自己使用
    • state 执行的state,默认domediumaction
    • str 需要显示的文本
  • 主机配置:
    • onUseFn 使用时执行函数,必须赋值,道具的删除要在里面自己写
    • useSound使用时音效,默认黄金那个清脆的音效

下面示例代码我的mod前缀为lappland_

1. 组件代码

local componentPre = debug.getinfo(1, 'S').source:match("([^/]+)_consumable%.lua$") --当前文件前缀
local componentName = componentPre .. "_consumable"

local function DefaultTargetCheckFn(inst, doer, target)
    return doer == target
end

--- 通用消耗品组件,主客机通用组件
--- 该组件和trader组件功能有些重叠,两者的区别在于trader组件功能强大,但是不够灵活,比如trader必须在给予方添加tradable组件,不能修改动作,
--      一次只能给一个,不能在客机拦截显示,tradable的东西对所有trader的东西都能互动,即便有时候不想显示文本也不行,也不能修改显示的文本,
--      trader是站在被给予方进行判断的,该组件是站在给予方进行判断的
--- 该组件也有缺点,必须在主客机添加并分别配置,功能单一,有时候想站在被给予方进行判断会比较麻烦,比如让肉类可与一个建筑互动,就得给所有有
--      肉类标签的对象添加组件并判断(虽然trader也类似,不过判断方是建筑)
local Consumable = Class(function(self, inst)
    self.inst = inst

    -- 3个限制
    inst:AddTag(componentName)                --根据标签判断是否可以消耗,默认可以
    self.userCheckFn = nil
    self.targetCheckFn = DefaultTargetCheckFn --默认只能自己用

    self.state = "domediumaction"             --使用执行的state,建议give/domediumaction
    self.str = nil

    if not TheWorld.ismastersim then return end

    self.onUseFn = nil                                  --使用时执行函数,必须赋值,道具的删除要在里面自己写
    self.useSound = "dontstarve/wilson/equip_item_gold" --使用音效
end)

function Consumable:Use(doer, target)
    local status, msg
    if self.onUseFn then
        status, msg = self.onUseFn(self.inst, doer, target)
    else
        status, msg = false, "NOT_INIT" --不应该发生
    end

    if status and self.useSound then
        if doer and doer.SoundEmitter then
            doer.SoundEmitter:PlaySound(self.useSound)
        elseif self.inst.SoundEmitter then
            self.inst.SoundEmitter:PlaySound(self.useSound)
        end
    end

    return status, msg
end

return Consumable

2. 使用示例

2.1 创建对应的action

local LAPPLAND_USE_ITEM = Action({ priority = 1 })
LAPPLAND_USE_ITEM.id = "LAPPLAND_USE_ITEM"
LAPPLAND_USE_ITEM.strfn = function(act)
    return act.invobject.components.lappland_consumable.str
end
LAPPLAND_USE_ITEM.fn = function(act)
    return act.invobject.components.lappland_consumable:Use(act.doer)
end
AddAction(LAPPLAND_USE_ITEM)
-- 可显示的文本
STRINGS.ACTIONS.LAPPLAND_USE_ITEM = {
    GENERIC = "使用",
    PLANT = "种植"
}
-- 失败原因
STRINGS.CHARACTERS.GENERIC.ACTIONFAIL.LAPPLAND_USE_ITEM = {
    EXIST_CAREER = "已经选过职业了。",
}

2.2 添加对应的ComponentAction

local function CheckConsumable(inst, doer, target, actions)
    local com = inst.components.lappland_consumable
    if com
        and inst:HasTag("lappland_consumable") --默认有
        and (not com.userCheckFn or com.userCheckFn(inst, doer, target)) --对玩家的检测
        and (not com.targetCheckFn or com.targetCheckFn(inst, doer, target)) --对目标单位的检测
    then
        table.insert(actions, ACTIONS.LAPPLAND_USE_ITEM)
    end
end

-- 可以自己使用
AddComponentAction("INVENTORY", "lappland_consumable", function(inst, doer, actions, right)
    CheckConsumable(inst, doer, doer, actions)
end)

-- 可以对目标使用
AddComponentAction("USEITEM", "lappland_consumable", function(inst, doer, target, actions, right)
    CheckConsumable(inst, doer, target, actions)
end)

2.3 在玩家的sg中添加对应的事件处理

-- 使用消耗品道具
AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.LAPPLAND_USE_ITEM,
    function(inst, action)
        return action.invobject.components.lappland_consumable.state
    end))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.LAPPLAND_USE_ITEM,
function(inst, action)
    return action.invobject.components.lappland_consumable.state
end))

2.4 在预制体中添加组件并配置

-- 使用后执行的操作,在主机执行,actions的返回值别忘了,成功就返回true,失败就返回false和失败原因
local function OnUseFn(inst, doer, target)
    inst:Remove()
    return true
end

-- 对目标的要求,在客机执行
local function TargetCheck(inst, doer, target)
    return target ~= nil
end

local function fn()
    -- ...
    inst.components.lappland_consumable.targetCheckFn = TargetCheck --其实只在客机设置就行
    inst.components.lappland_consumable.str = "PLANT" --显示的文本

    if not TheWorld.ismastersim then
        return inst
     end

    inst:AddComponent("lappland_consumable")
    inst.components.lappland_consumable.state = "domediumaction"
    inst.components.lappland_consumable.onUseFn = OnUseFn

    -- ...
end
posted @ 2024-04-30 10:16  高价领主  阅读(144)  评论(0)    收藏  举报