forked from DFHack/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
growcrops.lua
150 lines (123 loc) · 4.25 KB
/
growcrops.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
-- Instantly grow crops in farm plots
-- Collections crop name and growdur from the raws.
-- The returned table can be indexed by mat_index
function cacheCropRaws()
local crops = {}
-- store ID and grow duration for each crop
for idx, p in ipairs(df.global.world.raws.plants.all) do
crops[idx] = { name = p.id, growdur = p.growdur }
end
return crops
end
-- Gets a ref by type from the given refs collection or nil if not found
-- e.g. local ref = getRefByType(item.general_refs, df.general_ref_type.BUILDING_HOLDER)
function getRefByType(refs, type)
for _, ref in ipairs(refs) do
if ref:getType() == type then
return ref
end
end
return nil
end
-- Returns true if the given seed item is in a farm plot; false otherwise
function isSeedInFarmPlot(seed)
local buildingRef = getRefByType(seed.general_refs, df.general_ref_type.BUILDING_HOLDER)
if not buildingRef then
return false
end
local building = buildingRef:getBuilding()
return building ~= nil and building:getType() == df.building_type.FarmPlot
end
-- create a table of planted seed counts indexed by mat_index
function collectInventory(crop_raws)
local inventory = {}
for _, seed in ipairs(df.global.world.items.other.SEEDS) do
if not isSeedInFarmPlot(seed) then
goto skipseed
end
if seed.grow_counter < crop_raws[seed.mat_index].growdur then
inventory[seed.mat_index] = (inventory[seed.mat_index] or 0) + 1
end
:: skipseed ::
end
return inventory
end
-- Display a list of planted crops
function listPlantedCrops(crop_raws, inventory)
local crops = {}
-- create a copy of crops from inventory to use for sorting
for mat, invCount in pairs(inventory) do
table.insert(crops, { name = crop_raws[mat].name, count = invCount })
end
-- sort the table in descending order by seed count
table.sort(crops, function(a, b) return a.count > b.count end)
for _, crop in ipairs(crops) do
print(("%s %d"):format(crop.name, crop.count))
end
end
-- Tries to find a crop raw in crop_raws that matches the given name
-- The returned value contains the mat_index and name of the crop or is nil if not found
function findRawsCrop(crop_raws, material)
if not material then
return nil
end
local lower_mat = string.lower(material)
local possible_matches = {}
for mat_index, crop in pairs(crop_raws) do
local lower_crop_name = string.lower(crop.name)
if lower_mat == lower_crop_name then
return {mat_index = mat_index, name = crop.name}
end
if string.find(lower_crop_name, lower_mat) then
table.insert(possible_matches, {mat_index = mat_index, name = crop.name})
end
end
if #possible_matches == 1 then
return possible_matches[1]
end
return nil
end
-- grow specific crop
function growCrop(crop_raws, material)
-- find the matching crop
local wanted_mat = findRawsCrop(crop_raws, material)
if not wanted_mat then
-- no crop with that name
qerror("invalid plant material " .. material)
end
-- grow each seed for specified crop
local count = 0
for _, seed in pairs(df.global.world.items.other.SEEDS) do
-- Skip seeds that don't match the material
if seed.mat_index ~= wanted_mat.mat_index then
goto growskip
end
if not isSeedInFarmPlot(seed) then
goto growskip
end
if seed.grow_counter < crop_raws[seed.mat_index].growdur then
seed.grow_counter = crop_raws[seed.mat_index].growdur
count = count + 1
end
:: growskip ::
end
print(("Grew %d %s"):format(count, wanted_mat.name))
end
local args = {...}
local material = args[1]
if material == "help" then
print(dfhack.script_help())
return
end
local crop_raws = cacheCropRaws()
if not material or material == "list" then
local inventory = collectInventory(crop_raws)
listPlantedCrops(crop_raws, inventory)
elseif material == 'all' then
local inventory = collectInventory(crop_raws)
for mat_idx, _ in pairs(inventory) do
growCrop(crop_raws, crop_raws[mat_idx].name)
end
else
growCrop(crop_raws, material)
end