| 优先级 | 产出 | 投入条件(凑满 4 格) | 示例 |
| --- | --- | --- | --- |
| 1 | 猪皮 | 纯正常肉,肉价值 ≥ 2,且无怪物肉/蔬菜/水果/鱼/蛋 | 2 大肉;1 大肉 + 2 小肉;4 小肉 |
| 2 | 怪物肉 | 混入怪物肉(怪物价值 ≥ 1 且 肉价值 ≥ 1) | 1 怪物肉 + 任意 3 个食物 |
| 3 | 大肉 | 蔬菜价值 ≥ 4 或 水果价值 ≥ 4 | 4 胡萝卜;4 玉米 |
| 4 | 鱼肉 | 鱼价值 ≥ 1.5 | 2 鱼 + 2 任意 |
| 5 | 鸡腿 | 蛋价值 ≥ 2 | 2 鸟蛋 + 2 任意 |
| 6 | 小肉 | 兜底(以上都不满足) | 任意 4 个食物 |
目录:I:\WeGameApps\rail_apps\饥荒:联机版(2000004)\mods
meat_factory:
scripts\prefabs\meatfactory.lua:
-- 肉类工厂结构:复用原版「烹饪锅」的 stewer 组件与动画,
-- 放入食物后经过「烹饪」转化出肉类(产出由 cooking 配方决定,见 modmain.lua)。
require "prefabutil"
local assets =
{
Asset("ANIM", "anim/cook_pot.zip"),
Asset("ANIM", "anim/ui_cookpot_1x4.zip"),
}
local prefabs =
{
"collapse_small",
}
local function onhammered(inst, worker)
if inst.components.burnable ~= nil and inst.components.burnable:IsBurning() then
inst.components.burnable:Extinguish()
end
if not inst:HasTag("burnt") and inst.components.stewer.product ~= nil and inst.components.stewer:IsDone() then
inst.components.stewer:Harvest()
end
if inst.components.container ~= nil then
inst.components.container:DropEverything()
end
inst.components.lootdropper:DropLoot()
local fx = SpawnPrefab("collapse_small")
fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
fx:SetMaterial("metal")
inst:Remove()
end
local function onhit(inst, worker)
if not inst:HasTag("burnt") then
if inst.components.stewer:IsCooking() then
inst.AnimState:PlayAnimation("hit_cooking")
inst.AnimState:PushAnimation("cooking_loop", true)
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
elseif inst.components.stewer:IsDone() then
inst.AnimState:PlayAnimation("hit_full")
inst.AnimState:PushAnimation("idle_full", false)
else
if inst.components.container ~= nil and inst.components.container:IsOpen() then
inst.components.container:Close()
else
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
end
inst.AnimState:PlayAnimation("hit_empty")
inst.AnimState:PushAnimation("idle_empty", false)
end
end
end
-- 动画 / 音效回调
local function startcookfn(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("cooking_loop", true)
inst.SoundEmitter:KillSound("snd")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_rattle", "snd")
inst.Light:Enable(true)
end
end
local function onopen(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("cooking_pre_loop")
inst.SoundEmitter:KillSound("snd")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_open")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot", "snd")
end
end
local function onclose(inst)
if not inst:HasTag("burnt") then
if not inst.components.stewer:IsCooking() then
inst.AnimState:PlayAnimation("idle_empty")
inst.SoundEmitter:KillSound("snd")
end
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
end
end
local function donecookfn(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("cooking_pst")
inst.AnimState:PushAnimation("idle_full", false)
inst.SoundEmitter:KillSound("snd")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_finish")
inst.Light:Enable(false)
end
end
local function continuedonefn(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("idle_full")
end
end
local function continuecookfn(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("cooking_loop", true)
inst.Light:Enable(true)
inst.SoundEmitter:KillSound("snd")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_rattle", "snd")
end
end
local function harvestfn(inst)
if not inst:HasTag("burnt") then
inst.AnimState:PlayAnimation("idle_empty")
inst.SoundEmitter:PlaySound("dontstarve/common/cookingpot_close")
end
end
local function getstatus(inst)
return (inst:HasTag("burnt") and "BURNT")
or (inst.components.stewer:IsDone() and "DONE")
or (not inst.components.stewer:IsCooking() and "EMPTY")
or (inst.components.stewer:GetTimeToCook() > 15 and "COOKING_LONG")
or "COOKING_SHORT"
end
local function onbuilt(inst)
inst.AnimState:PlayAnimation("place")
inst.AnimState:PushAnimation("idle_empty", false)
inst.SoundEmitter:PlaySound("dontstarve/common/cook_pot_craft")
end
local function onsave(inst, data)
if inst:HasTag("burnt") or (inst.components.burnable ~= nil and inst.components.burnable:IsBurning()) then
data.burnt = true
end
end
local function onload(inst, data)
if data ~= nil and data.burnt then
inst.components.burnable.onburnt(inst)
inst.Light:Enable(false)
end
end
local function onloadpostpass(inst, newents, data)
if data and data.additems and inst.components.container then
for i, itemname in ipairs(data.additems) do
local ent = SpawnPrefab(itemname)
inst.components.container:GiveItem(ent)
end
end
end
local function fn()
local inst = CreateEntity()
inst.entity:AddTransform()
inst.entity:AddAnimState()
inst.entity:AddSoundEmitter()
inst.entity:AddMiniMapEntity()
inst.entity:AddLight()
inst.entity:AddNetwork()
inst:SetDeploySmartRadius(1)
MakeObstaclePhysics(inst, .5)
inst.Light:Enable(false)
inst.Light:SetRadius(.6)
inst.Light:SetFalloff(1)
inst.Light:SetIntensity(.5)
inst.Light:SetColour(235/255, 62/255, 12/255)
inst:AddTag("structure")
-- stewer 标签:让 componentactions / actions 通用地识别为可烹饪结构
inst:AddTag("stewer")
inst.AnimState:SetBank("cook_pot")
inst.AnimState:SetBuild("cook_pot")
inst.AnimState:PlayAnimation("idle_empty")
inst.MiniMapEntity:SetIcon("cookpot.png")
MakeSnowCoveredPristine(inst)
inst.entity:SetPristine()
if not TheWorld.ismastersim then
return inst
end
inst:AddComponent("stewer")
inst.components.stewer.onstartcooking = startcookfn
inst.components.stewer.oncontinuecooking = continuecookfn
inst.components.stewer.oncontinuedone = continuedonefn
inst.components.stewer.ondonecooking = donecookfn
inst.components.stewer.onharvest = harvestfn
inst:AddComponent("container")
inst.components.container:WidgetSetup("meatfactory")
inst.components.container.onopenfn = onopen
inst.components.container.onclosefn = onclose
inst.components.container.skipclosesnd = true
inst.components.container.skipopensnd = true
inst:AddComponent("inspectable")
inst.components.inspectable.getstatus = getstatus
inst:AddComponent("lootdropper")
inst:AddComponent("workable")
inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
inst.components.workable:SetWorkLeft(4)
inst.components.workable:SetOnFinishCallback(onhammered)
inst.components.workable:SetOnWorkCallback(onhit)
inst:AddComponent("hauntable")
inst.components.hauntable:SetHauntValue(TUNING.HAUNT_TINY)
MakeSnowCovered(inst)
SetLunarHailBuildupAmountSmall(inst)
inst:ListenForEvent("onbuilt", onbuilt)
MakeMediumBurnable(inst, nil, nil, true)
MakeSmallPropagator(inst)
inst.OnSave = onsave
inst.OnLoad = onload
inst.OnLoadPostPass = onloadpostpass
return inst
end
return Prefab("meatfactory", fn, assets, prefabs),
MakePlacer("meatfactory_placer", "cook_pot", "cook_pot", "idle_empty")
modinfo.lua:
name = "Meat Factory(肉类工厂)"
description = "新增一个「肉类工厂」结构:放入食物,按不同配方转化出不同肉类(大肉、小肉、鱼肉、鸡腿)。"
author = "local"
version = "1.0.0"
forumthread = ""
api_version = 10
dst_compatible = true
all_clients_require_mod = false
client_only_mod = false
priority = 0
modmain.lua:
-- 肉类工厂(Meat Factory)
-- 结构本体见 scripts/prefabs/meatfactory.lua,这里负责:
-- 1. 容器 UI(4 格,只能放入食物)
-- 2. 产出配方(不同食物组合 → 不同肉类)
-- 3. 建筑合成配方
-- 4. 名称 / 描述 / 检查文案
PrefabFiles =
{
"meatfactory",
}
-- 游戏全局对象不会自动暴露给 mod 沙箱,需通过 GLOBAL 引用并缓存为局部变量。
local GLOBAL = GLOBAL
local STRINGS = GLOBAL.STRINGS
local ACTIONS = GLOBAL.ACTIONS
local TECH = GLOBAL.TECH
local FOODTYPE = GLOBAL.FOODTYPE
local Vector3 = GLOBAL.Vector3
local BufferedAction = GLOBAL.BufferedAction
local SendRPCToServer = GLOBAL.SendRPCToServer
local RPC = GLOBAL.RPC
--------------------------------------------------------------------------
-- 容器 UI
--------------------------------------------------------------------------
local containers = require("containers")
local params = containers.params
local function IsFoodItem(item)
for _, v in pairs(FOODTYPE) do
if item:HasTag("edible_" .. v) then
return true
end
end
return false
end
params.meatfactory =
{
widget =
{
slotpos =
{
Vector3(0, 64 + 32 + 8 + 4, 0),
Vector3(0, 32 + 4, 0),
Vector3(0, -(32 + 4), 0),
Vector3(0, -(64 + 32 + 8 + 4), 0),
},
animbank = "ui_cookpot_1x4",
animbuild = "ui_cookpot_1x4",
pos = Vector3(200, 0, 0),
side_align_tip = 100,
buttoninfo =
{
text = STRINGS.ACTIONS.COOK,
position = Vector3(0, -165, 0),
},
},
acceptsstacks = false,
type = "cooker",
}
function params.meatfactory.itemtestfn(container, item, slot)
return not container.inst:HasTag("burnt") and IsFoodItem(item)
end
function params.meatfactory.widget.buttoninfo.fn(inst, doer)
if inst.components.container ~= nil then
BufferedAction(doer, inst, ACTIONS.COOK):Do()
elseif inst.replica.container ~= nil and not inst.replica.container:IsBusy() then
SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.COOK.code, inst, ACTIONS.COOK.mod_name)
end
end
function params.meatfactory.widget.buttoninfo.validfn(inst)
return inst.replica.container ~= nil and inst.replica.container:IsFull()
end
--------------------------------------------------------------------------
-- 产出配方
--
-- 放入 4 格食物并「烹饪」后,按下方优先级从高到低判定,命中第一条即产出
--(数值为食物类型价值累计,与烹饪锅一致):
-- 纯正常肉(肉≥2,无怪物肉/蔬菜/水果/鱼/蛋)→ 猪皮(pigskin)
-- 混入怪物肉(怪物≥1 且 肉≥1) → 怪肉(monstermeat)
-- 蔬菜或水果价值 ≥ 4 → 大肉(meat)
-- 鱼类价值 ≥ 1.5 → 鱼肉(fishmeat)
-- 蛋类价值 ≥ 2 → 鸡腿(drumstick)
-- 其他任意食物 → 小肉(smallmeat)(兜底)
--
-- 肉类(大肉/小肉/鱼肉/怪物肉等)本身就是可投入的原料,
-- 它们通过「肉」「怪物」价值参与上面「猪皮」「怪肉」两个配方的判定。
--------------------------------------------------------------------------
local function MakeRecipe(name, priority, cooktime, stacksize, test)
return {
name = name,
test = test,
priority = priority,
weight = 1,
cooktime = cooktime,
stacksize = stacksize,
no_cookbook = true,
}
end
local RECIPES =
{
-- 猪皮:纯正常肉 → 皮(2 大肉,或 1 大肉 + 2 小肉,或 4 小肉 等)
MakeRecipe("pigskin", 12, 2, 1, function(cooker, names, tags)
return (tags.meat or 0) >= 2
and (tags.monster or 0) == 0
and (tags.veggie or 0) == 0
and (tags.fruit or 0) == 0
and (tags.fish or 0) == 0
and (tags.egg or 0) == 0
end),
-- 怪肉:怪物肉混入后污染整锅(1 怪物肉 + 任意 3 个食物)
MakeRecipe("monstermeat", 11, 2, 1, function(cooker, names, tags)
return (tags.monster or 0) >= 1 and (tags.meat or 0) >= 1
end),
MakeRecipe("meat", 10, 3, 1, function(cooker, names, tags)
return (tags.veggie or 0) >= 4 or (tags.fruit or 0) >= 4
end),
MakeRecipe("fishmeat", 9, 2, 1, function(cooker, names, tags)
return (tags.fish or 0) >= 1.5
end),
MakeRecipe("drumstick", 8, 1, 1, function(cooker, names, tags)
return (tags.egg or 0) >= 2
end),
MakeRecipe("smallmeat", 1, 1, 1, function(cooker, names, tags)
return true
end),
}
for _, recipe in ipairs(RECIPES) do
AddCookerRecipe("meatfactory", recipe, true)
end
--------------------------------------------------------------------------
-- 建筑合成配方
--------------------------------------------------------------------------
AddRecipe2("meatfactory",
{ Ingredient("cutstone", 2), Ingredient("charcoal", 2), Ingredient("twigs", 4) },
TECH.SCIENCE_ONE,
{
atlas = "images/inventoryimages.xml",
image = "cookpot.tex",
placer = "meatfactory_placer",
min_spacing = 2,
})
--------------------------------------------------------------------------
-- 字符串(名称 / 描述 / 检查文案)
--------------------------------------------------------------------------
STRINGS.NAMES.MEATFACTORY = "肉类工厂"
STRINGS.RECIPE_DESC.MEATFACTORY = "把食物转化出肉。"
STRINGS.CHARACTERS.GENERIC.DESCRIBE.MEATFACTORY =
{
EMPTY = "空空如也,等它变出肉来。",
COOKING_LONG = "正在制造肉类……",
COOKING_SHORT = "肉快好了。",
DONE = "肉做好了!",
BURNT = "工厂被烧坏了。",
}