-
Notifications
You must be signed in to change notification settings - Fork 199
/
Copy pathautocheese.lua
187 lines (160 loc) · 5.7 KB
/
autocheese.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
--@module = true
local ic = reqscript('idle-crafting')
---make cheese using a specific barrel and workshop
---@param barrel df.item
---@param workshop df.building_workshopst
---@return df.job
function makeCheese(barrel, workshop)
---@type df.job
local job = ic.make_job()
job.job_type = df.job_type.MakeCheese
local jitem = df.job_item:new()
jitem.quantity = 0
jitem.vector_id = df.job_item_vector_id.ANY_COOKABLE
jitem.flags1.unrotten = true
jitem.flags1.milk = true
job.job_items.elements:insert('#', jitem)
if not dfhack.job.attachJobItem(job, barrel, df.job_item_ref.T_role.Reagent, 0, -1) then
dfhack.error('could not attach item')
end
ic.assignToWorkshop(job, workshop)
return job
end
---unit is ready to take jobs
---@param unit df.unit
---@return boolean
function unitIsAvailable(unit)
if unit.job.current_job then
return false
elseif #unit.individual_drills > 0 then
return false
elseif unit.flags1.caged or unit.flags1.chained then
return false
elseif unit.military.squad_id ~= -1 then
local squad = df.squad.find(unit.military.squad_id)
-- this lookup should never fail
---@diagnostic disable-next-line: need-check-nil
return #squad.orders == 0 and squad.activity == -1
end
return true
end
---check if unit can perform labor at workshop
---@param unit df.unit
---@param unit_labor df.unit_labor
---@param workshop df.building
---@return boolean
function availableLaborer(unit, unit_labor, workshop)
return unit.status.labors[unit_labor]
and unitIsAvailable(unit)
and ic.canAccessWorkshop(unit, workshop)
end
---find unit with a particular labor enabled
---@param unit_labor df.unit_labor
---@param job_skill df.job_skill
---@param workshop df.building
---@return df.unit|nil
---@return integer|nil
function findAvailableLaborer(unit_labor, job_skill, workshop)
local max_unit = nil
local max_skill = -1
for _, unit in ipairs(dfhack.units.getCitizens(true, false)) do
if
availableLaborer(unit, unit_labor, workshop)
then
local unit_skill = dfhack.units.getNominalSkill(unit, job_skill, true)
if unit_skill > max_skill then
max_unit = unit
max_skill = unit_skill
end
end
end
return max_unit, max_skill
end
local function findMilkBarrel(min_liquids)
for _, container in ipairs(df.global.world.items.other.FOOD_STORAGE) do
if
not (container.flags.in_job or container.flags.forbid) and
container.flags.container and #container.general_refs >= min_liquids
then
local content_reference = dfhack.items.getGeneralRef(container, df.general_ref_type.CONTAINS_ITEM)
local contained_item = df.item.find(content_reference and content_reference.item_id or -1)
if contained_item then
local mat_info = dfhack.matinfo.decode(contained_item)
if mat_info:matches { milk = true } then
return container
end
end
end
end
end
---find a workshop to which the barrel can be brought
---if the workshop has a master, only return workshop and master if the master is available
---@param pos df.coord
---@return df.building_workshopst?
---@return df.unit?
function findWorkshop(pos)
for _,workshop in ipairs(df.global.world.buildings.other.WORKSHOP_FARMER) do
if
dfhack.maps.canWalkBetween(pos, xyz2pos(workshop.centerx, workshop.centery, workshop.z)) and
not workshop.profile.blocked_labors[df.unit_labor.MAKE_CHEESE] and
#workshop.jobs == 0
then
if #workshop.profile.permitted_workers == 0 then
-- immediately return workshop without master
return workshop, nil
else
unit = df.unit.find(workshop.profile.permitted_workers[0])
if
unit and availableLaborer(unit, df.unit_labor.MAKE_CHEESE, workshop)
then
-- return workshop and master, if master is available
return workshop, unit
else
print("autocheese: Skipping farmer's workshop with unavailable master")
end
end
end
end
end
if dfhack_flags.module then
return
end
-- actual script action
local argparse = require('argparse')
local min_number = 50
local _ = argparse.processArgsGetopt({...},
{
{ 'm', 'min-milk', hasArg = true,
handler = function(min)
min_number = argparse.nonnegativeInt(min, 'min-milk')
end }
})
local reagent = findMilkBarrel(min_number)
if not reagent then
-- print('autocheese: no sufficiently full barrel found')
return
end
local workshop, worker = findWorkshop(xyz2pos(dfhack.items.getPosition(reagent)))
if not workshop then
print("autocheese: no Farmer's Workshop available")
return
end
-- try to find laborer for workshop without master
if not worker then
worker, _ = findAvailableLaborer(df.unit_labor.MAKE_CHEESE, df.job_skill.CHEESEMAKING, workshop)
end
if not worker then
print('autocheese: no cheesemaker available')
return
end
local job = makeCheese(reagent, workshop)
print(('autocheese: dispatching cheesemaking job for %s (%d milk) to %s'):format(
dfhack.df2console(dfhack.items.getReadableDescription(reagent)),
#reagent.general_refs,
dfhack.df2console(dfhack.units.getReadableName(worker))
))
-- assign a worker and send it to fetch the barrel
dfhack.job.addWorker(job, worker)
dfhack.units.setPathGoal(worker, reagent.pos, df.unit_path_goal.GrabJobResources)
job.items[0].flags.is_fetching = true
job.flags.fetching = true