diff --git a/control.lua b/control.lua index 3fdf887c..dec572f4 100644 --- a/control.lua +++ b/control.lua @@ -10,6 +10,7 @@ require 'walk_distance' require 'follow' require 'autodeconstruct' require 'corpse_util' +require 'infinite_storage_chest' require 'fish_market' require 'reactor_meltdown' require 'map_layout' @@ -140,9 +141,23 @@ Event.add(defines.events.on_console_chat, hodor) Event.add( defines.events.on_player_joined_game, function(event) - local gui = game.players[event.player_index].gui + local player = game.players[event.player_index] + if not player or not player.valid then + return + end + if player.name == 'grilledham' then + -- pink + player.color = {r = 0.9290000202716064, g = 0.3860000739097595, b = 0.51399999856948853, a = 0.5} + player.chat_color = {r = 1, g = 0.51999998092651367, b = 0.63300001621246338, a = 0.5} + end + + local gui = player.gui gui.top.style = 'slot_table_spacing_horizontal_flow' gui.left.style = 'slot_table_spacing_vertical_flow' + + --[[ player.insert {name = 'infinity-chest', count = 10} + player.insert {name = 'electric-energy-interface', count = 10} + player.cheat_mode = true ]] end ) diff --git a/infinite_storage_chest.lua b/infinite_storage_chest.lua new file mode 100644 index 00000000..0fad270c --- /dev/null +++ b/infinite_storage_chest.lua @@ -0,0 +1,214 @@ +local Event = require 'utils.event' +local Gui = require 'utils.gui' +local Token = require 'utils.global_token' +local Task = require 'utils.Task' + +local chests = {} +local chests_data = {chests = chests} +local chests_data_token = Token.register_global(chests_data) + +Event.on_load( + function() + chests_data = Token.get_global(chests_data_token) + chests = chests_data.chests + end +) + +local chest_gui_frame_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 + + local pos = entity.position + + chests[pos.x .. ',' .. pos.y] = {entity = entity, storage = {}} +end + +local function mined_entity(event) + local entity = event.entity + if not entity or not entity.valid or entity.name ~= 'infinity-chest' then + return + end + + local pos = entity.position + + chests[pos.x .. ',' .. pos.y] = nil +end + +local function get_stack_size(name) + local proto = game.item_prototypes[name] + if not proto then + game.print('item prototype not found') + 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) + + new_amount = prev - diff + inv.insert({name = name, count = diff}) + end + + if new_amount == 0 then + storage[name] = nil + else + storage[name] = new_amount + end +end + +local function tick() + local current = chests_data.next + chests_data.next = next(chests, current) + + if not current then + return + end + + local chest = chests[current] + + local entity = chest.entity + if not entity or not entity.valid then + chests[current] = nil + else + local storage = chest.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.add {type = 'table', column_count = 10, style = 'slot_table'} + + 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' + } + 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' + } + 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 + + if not player.connected then + player.opened = nil + opened.destroy() + end + + opened.clear() + 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 pos = entity.position + local chest = chests[pos.x .. ',' .. pos.y] + + if not chest then + return + end + + local player = game.players[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'} + + 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_player_mined_entity, mined_entity) +Event.add(defines.events.on_robot_mined_entity, mined_entity) +Event.on_nth_tick(1, tick) +Event.add(defines.events.on_gui_opened, gui_opened) + +Gui.on_custom_close( + chest_gui_frame_name, + function(event) + event.element.destroy() + end +)