2019-01-11 20:25:54 +02:00
local Module = { }
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
2019-02-08 04:05:30 +02:00
local format = string.format
2018-06-04 01:42:22 +02:00
local chests = { }
2018-08-08 12:55:45 +02:00
local chests_next = { }
2019-02-08 04:05:30 +02:00
local config = global.config . infinite_storage_chest
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
2019-01-11 20:25:54 +02:00
function Module . create_chest ( surface , position , storage )
local entity = surface.create_entity { name = ' infinity-chest ' , position = position , force = ' player ' }
chests [ entity.unit_number ] = { entity = entity , storage = storage }
return entity
end
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
2018-06-25 00:21:27 +02:00
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 ( )
2018-06-25 00:21:27 +02:00
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
2018-09-23 12:46:58 +02:00
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 ' ,
2019-02-08 04:05:30 +02:00
caption = format ( ' This chest stores unlimited quantity of items (up to 48 different item types). \n The chest is best used with an inserter to add / remove items. \n If the chest is mined or destroyed the items are lost. \n You can buy the chest at the market for %s coins. ' , config.cost )
2018-08-07 13:29:27 +02:00
}
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 )
2018-09-23 12:46:58 +02:00
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-02-08 04:05:30 +02:00
table.insert ( market_items , { price = config.cost , name = ' infinity-chest ' , description = ' Stores unlimited quantity of items for up to 48 different item types ' } )
2019-01-11 20:25:54 +02:00
return Module