forked from Refactorio/RedMew
-
Notifications
You must be signed in to change notification settings - Fork 0
/
infinite_storage_chest.lua
256 lines (207 loc) · 6.43 KB
/
infinite_storage_chest.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
local Event = require 'utils.event'
local Token = require 'utils.global_token'
local Gui = require 'utils.gui'
local Task = require 'utils.Task'
local Global = require 'utils.global'
local Game = require 'utils.game'
local chests = {}
local chests_next = {}
Global.register(
{chests = chests, chests_next = chests_next},
function(tbl)
chests = tbl.chests
chests_next = tbl.chests_next
end
)
local chest_gui_frame_name = Gui.uid_name()
local chest_content_table_name = Gui.uid_name()
local function built_entity(event)
local entity = event.created_entity
if not entity or not entity.valid or entity.name ~= 'infinity-chest' then
return
end
chests[entity.unit_number] = {entity = entity, storage = {}}
end
local function get_stack_size(name)
local proto = game.item_prototypes[name]
if not proto then
log('item prototype ' .. name .. ' not found')
return 1
end
return proto.stack_size
end
local function do_item(name, count, inv, storage)
local size = get_stack_size(name)
local diff = count - size
if diff == 0 then
return
end
local new_amount = 0
if diff > 0 then
inv.remove({name = name, count = diff})
local prev = storage[name] or 0
new_amount = prev + diff
elseif diff < 0 then
local prev = storage[name]
if not prev then
return
end
diff = math.min(prev, -diff)
local inserted = inv.insert({name = name, count = diff})
new_amount = prev - inserted
end
if new_amount == 0 then
storage[name] = nil
else
storage[name] = new_amount
end
end
local function tick()
local chest_id, chest_data = next(chests, chests_next[1])
chests_next[1] = chest_id
if not chest_id then
return
end
local entity = chest_data.entity
if not entity or not entity.valid then
chests[chest_id] = nil
else
local storage = chest_data.storage
local inv = entity.get_inventory(1) --defines.inventory.chest
local contents = inv.get_contents()
for name, count in pairs(contents) do
do_item(name, count, inv, storage)
end
for name, _ in pairs(storage) do
if not contents[name] then
do_item(name, 0, inv, storage)
end
end
end
end
local function create_chest_gui_content(frame, player, chest)
local storage = chest.storage
local inv = chest.entity.get_inventory(1).get_contents()
local grid = frame[chest_content_table_name]
if grid then
grid.clear()
else
grid = frame.add {type = 'table', name = chest_content_table_name, column_count = 10, style = 'slot_table'}
end
for name, count in pairs(storage) do
local number = count + (inv[name] or 0)
grid.add {
type = 'sprite-button',
sprite = 'item/' .. name,
number = number,
tooltip = name,
--style = 'slot_button'
enabled = false
}
end
for name, count in pairs(inv) do
if not storage[name] then
grid.add {
type = 'sprite-button',
sprite = 'item/' .. name,
number = count,
tooltip = name,
--style = 'slot_button'
enabled = false
}
end
end
player.opened = frame
end
local chest_gui_content_callback
chest_gui_content_callback =
Token.register(
function(data)
local player = data.player
if not player or not player.valid then
return
end
local opened = data.opened
if not opened or not opened.valid then
return
end
local entity = data.chest.entity
if not entity.valid then
player.opened = nil
opened.destroy()
return
end
if not player.connected then
player.opened = nil
opened.destroy()
return
end
create_chest_gui_content(opened, player, data.chest)
Task.set_timeout_in_ticks(60, chest_gui_content_callback, data)
end
)
local function gui_opened(event)
if not event.gui_type == defines.gui_type.entity then
return
end
local entity = event.entity
if not entity or not entity.valid or entity.name ~= 'infinity-chest' then
return
end
local chest = chests[entity.unit_number]
if not chest then
return
end
local player = Game.get_player_by_index(event.player_index)
if not player or not player.valid then
return
end
local frame =
player.gui.center.add {
type = 'frame',
name = chest_gui_frame_name,
caption = 'Infinite Storage Chest',
direction = 'vertical'
}
local text =
frame.add {
type = 'label',
caption = 'This chest stores unlimited quantity of items (up to 48 different item types).\nThe chest is best used with an inserter to add / remove items.\nIf the chest is mined or destroyed the items are lost.\nYou can buy the chest at the market for 100 coins.'
}
text.style.single_line = false
local content_header = frame.add {type = 'label', caption = 'Content'}
content_header.style.font = 'default-listbox'
create_chest_gui_content(frame, player, chest)
Task.set_timeout_in_ticks(60, chest_gui_content_callback, {player = player, chest = chest, opened = frame})
end
Event.add(defines.events.on_built_entity, built_entity)
Event.add(defines.events.on_robot_built_entity, built_entity)
Event.add(defines.events.on_tick, tick)
Event.add(defines.events.on_gui_opened, gui_opened)
Event.add(
defines.events.on_player_died,
function(event)
local player = Game.get_player_by_index(event.player_index or 0)
if not player or not player.valid then
return
end
local element = player.gui.center
if element and element.valid then
element = element[chest_gui_frame_name]
if element and element.valid then
element.destroy()
end
end
end
)
Gui.on_custom_close(
chest_gui_frame_name,
function(event)
event.element.destroy()
end
)
local market_items = require 'resources.market_items'
table.insert(
market_items,
{price = {{market_items.market_item, 100}}, offer = {type = 'give-item', item = 'infinity-chest'}}
)