-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathautocrafting.lua
168 lines (140 loc) · 4.98 KB
/
autocrafting.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
local function add_or_create(t, i, n)
t[i] = t[i] and t[i] + n or n
end
local function get_group_item(invCache, groups)
local maxCount = 0
local maxItem
local isInGroups
for item, count in pairs(invCache) do
isInGroups = true
for _, group in ipairs(groups) do
if minetest.get_item_group(item, group) == 0 then
isInGroups = false
break
end
end
if isInGroups and count > maxCount then
maxItem = item
maxCount = count
end
end
return maxItem
end
function cg.auto_get_craftable(player, craft)
local inv = player:get_inventory():get_list("main")
local invCache = {}
-- Create a cache of the inventory with itemName = count pairs.
-- This speeds up searching for items.
for _, stack in ipairs(inv) do
if stack:get_count() > 0 then
add_or_create(invCache, stack:get_name(), stack:get_count())
end
end
local reqItems = {}
local reqGroups = {}
-- Find out how many of each item/group is required to craft one item.
for _, item in pairs(craft.items) do
if item:sub(1, 6) == "group:" then
add_or_create(reqGroups, item, 1)
else
add_or_create(reqItems, item, 1)
end
end
local gMaxItem
-- For each group, find the item in that group from the player's inventory
-- with the largest count.
for group, count in pairs(reqGroups) do
gMaxItem = get_group_item(invCache, group:sub(7):split(","))
if gMaxItem then
add_or_create(reqItems, gMaxItem, count)
else
return 0
end
end
local craftable = 1000
for item, count in pairs(reqItems) do
if invCache[item] then
craftable = math.min(craftable, math.floor(invCache[item] / count))
else
return 0
end
-- We can't craft more than the stack_max of our ingredients.
if minetest.registered_items[item].stack_max then
craftable = math.min(craftable,
minetest.registered_items[item].stack_max)
end
end
return craftable
end
function cg.auto_craft(player, craft, num)
local inv = player:get_inventory()
if not inv:is_empty("craft") then
-- Attempt to move items to the player's main inventory.
for idx, stack in ipairs(inv:get_list("craft")) do
if not stack:is_empty() then
stack = inv:add_item("main", stack)
inv:set_stack("craft", idx, stack)
end
end
-- Check again, and return if not all items were moved.
if not inv:is_empty("craft") then
minetest.chat_send_player(player:get_player_name(),
cg.S("Item could not be crafted!"))
return
end
end
if craft.width > inv:get_width("craft")
or table.maxn(craft.items) > inv:get_size("craft") then
return
end
local invList = inv:get_list("main")
local width = craft.width == 0 and inv:get_width("craft") or craft.width
local stack, invCache
local groupCache = {}
for idx, item in pairs(craft.items) do
-- Shift the indices so the items in the craft go to the right spots on
-- the crafting grid.
idx = (idx + (inv:get_width("craft") - width) *
math.floor((idx - 1) / width))
if item:sub(1, 6) == "group:" then
-- Create an inventory cache.
if not invCache then
invCache = {}
for _, stack in ipairs(invList) do
if stack:get_count() > 0 then
add_or_create(invCache, stack:get_name(),
stack:get_count())
end
end
end
-- Get the most plentiful item in the group.
if not groupCache[item] then
groupCache[item] = get_group_item(invCache,
item:sub(7):split(","))
end
-- Move the selected item.
if groupCache[item] then
stack = inv:remove_item("main",
ItemStack({name = groupCache[item], count = num}))
inv:set_stack("craft", idx, stack)
end
else
-- Move the item.
stack = inv:remove_item("main",
ItemStack({name = item, count = num}))
inv:set_stack("craft", idx, stack)
end
end
end
minetest.register_on_player_inventory_action(
function(player, action, inventory, inventory_info)
-- Hide the autocrafting menu when the player drops an item.
if cg.AUTOCRAFTING and inventory_info.listname == "main" then
local context = sfinv.get_or_create_context(player)
if context.cg_auto_menu then
context.cg_auto_menu = false
sfinv.set_player_inventory_formspec(player)
end
end
end
)