1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/features/infinite_storage_chest.lua

254 lines
6.4 KiB
Lua
Raw Normal View History

2018-06-04 01:42:22 +02:00
local Event = require 'utils.event'
2018-11-26 03:07:03 +02:00
local Token = require 'utils.token'
2018-08-08 12:55:45 +02:00
local Gui = require 'utils.gui'
2019-01-04 22:02:55 +02:00
local Task = require 'utils.task'
2018-08-08 12:55:45 +02:00
local Global = require 'utils.global'
2018-09-23 00:25:13 +02:00
local Game = require 'utils.game'
2018-06-04 01:42:22 +02:00
local chests = {}
2018-08-08 12:55:45 +02:00
local chests_next = {}
2018-06-04 01:42:22 +02:00
2018-08-08 12:55:45 +02:00
Global.register(
{chests = chests, chests_next = chests_next},
function(tbl)
chests = tbl.chests
chests_next = tbl.chests_next
2018-06-04 01:42:22 +02:00
end
)
local chest_gui_frame_name = Gui.uid_name()
2018-08-07 13:29:27 +02:00
local chest_content_table_name = Gui.uid_name()
2018-06-04 01:42:22 +02:00
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
2018-08-07 01:14:54 +02:00
chests[entity.unit_number] = {entity = entity, storage = {}}
2018-06-04 01:42:22 +02:00
end
local function get_stack_size(name)
local proto = game.item_prototypes[name]
if not proto then
2018-06-08 17:47:53 +02:00
log('item prototype ' .. name .. ' not found')
return 1
2018-06-04 01:42:22 +02:00
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)
2018-06-08 00:14:03 +02:00
local inserted = inv.insert({name = name, count = diff})
new_amount = prev - inserted
2018-06-04 01:42:22 +02:00
end
if new_amount == 0 then
storage[name] = nil
else
storage[name] = new_amount
end
end
local function tick()
2018-08-08 12:55:45 +02:00
local chest_id, chest_data = next(chests, chests_next[1])
2018-06-04 01:42:22 +02:00
2018-08-08 12:55:45 +02:00
chests_next[1] = chest_id
if not chest_id then
2018-06-04 01:42:22 +02:00
return
end
2018-08-08 12:55:45 +02:00
local entity = chest_data.entity
2018-06-04 01:42:22 +02:00
if not entity or not entity.valid then
2018-08-08 12:55:45 +02:00
chests[chest_id] = nil
2018-06-04 01:42:22 +02:00
else
2018-08-08 12:55:45 +02:00
local storage = chest_data.storage
2018-06-04 01:42:22 +02:00
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()
2018-08-07 13:29:27 +02:00
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
2018-06-04 01:42:22 +02:00
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,
2018-06-08 17:47:53 +02:00
--style = 'slot_button'
enabled = false
2018-06-04 01:42:22 +02:00
}
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,
2018-06-08 17:47:53 +02:00
--style = 'slot_button'
enabled = false
2018-06-04 01:42:22 +02:00
}
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
2018-06-04 01:42:22 +02:00
if not player.connected then
player.opened = nil
opened.destroy()
return
2018-06-04 01:42:22 +02:00
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
2018-08-07 01:14:54 +02:00
local chest = chests[entity.unit_number]
2018-06-04 01:42:22 +02:00
if not chest then
return
end
local player = Game.get_player_by_index(event.player_index)
2018-06-04 01:42:22 +02:00
if not player or not player.valid then
return
end
local frame =
2018-08-07 13:29:27 +02:00
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'
2018-06-04 01:42:22 +02:00
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)
2018-06-08 17:47:53 +02:00
Event.add(defines.events.on_tick, tick)
2018-06-04 01:42:22 +02:00
Event.add(defines.events.on_gui_opened, gui_opened)
2018-08-07 01:14:54 +02:00
Event.add(
defines.events.on_player_died,
function(event)
local player = Game.get_player_by_index(event.player_index or 0)
2018-08-07 01:14:54 +02:00
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
)
2018-06-04 01:42:22 +02:00
Gui.on_custom_close(
chest_gui_frame_name,
function(event)
event.element.destroy()
end
)
2018-06-07 18:26:52 +02:00
local market_items = require 'resources.market_items'
2019-01-05 13:12:22 +02:00
table.insert(market_items, {price = 100, name = 'infinity-chest', description = 'Stores unlimited quantity of items for up to 48 different item types'})