201 lines
6.2 KiB
Lua

local Chest = {}
Chest.color = {r = 200/255, g = 110/255, b = 38/255}
Chest.entity_types = {'container', 'logistic-container', 'infinity-container', 'linked-container'}
Chest.unlocked = function(force) return force.technologies['factory-connection-type-chest'].researched end
local blacklist = {'factory-overlay-controller', 'factory-overlay-display'}
local blacklisted = {}
for _, name in pairs(blacklist) do blacklisted[name] = true end
local function get_chest_type(chest)
local type = chest.prototype.logistic_mode
if type == 'requester' then return 'input'
elseif type == 'active-provider' then return 'output'
elseif type == 'passive-provider' then return 'output'
elseif type == 'buffer' then return 'output'
elseif type == 'storage' then return 'input'
else return 'neutral' end
end
Chest.connect = function(factory, cid, cpos, outside_entity, inside_entity, settings)
if blacklisted[outside_entity.name] or blacklisted[inside_entity.name] then return nil end
-- Connection mode: 0 for balance, 1 for inwards, 2 for outwards
if not settings.mode then
local outside_type = get_chest_type(outside_entity)
local inside_type = get_chest_type(inside_entity)
if outside_type == inside_type then
settings.mode = 0
elseif outside_type == 'input' or inside_type == 'output' then
settings.mode = 1
elseif outside_type == 'output' or inside_type == 'input' then
settings.mode = 2
end
end
return {outside = outside_entity, inside = inside_entity, do_tick_update = true}
end
Chest.recheck = function(conn)
return conn.outside.valid and conn.inside.valid
end
local DELAYS = {10, 20, 60, 180, 600}
local DEFAULT_DELAY = 60
Chest.indicator_settings = {'d0', 'b0'}
for _,v in pairs(DELAYS) do
table.insert(Chest.indicator_settings, 'd' .. v)
table.insert(Chest.indicator_settings, 'b' .. v)
end
local function make_valid_delay(delay)
for _,v in pairs(DELAYS) do
if v == delay then return v end
end
return 0 -- Catchall
end
Chest.direction = function(conn)
local mode = (conn._settings.mode or 0)
if mode == 0 then
return 'b' .. make_valid_delay(conn._settings.delay or DEFAULT_DELAY), defines.direction.north
elseif mode == 1 then
return 'd' .. make_valid_delay(conn._settings.delay or DEFAULT_DELAY), conn._factory.layout.connections[conn._id].direction_in
else
return 'd' .. make_valid_delay(conn._settings.delay or DEFAULT_DELAY), conn._factory.layout.connections[conn._id].direction_out
end
end
Chest.rotate = function(conn)
conn._settings.mode = ((conn._settings.mode or 0)+1)%3
local mode = conn._settings.mode
if mode == 0 then
return {'factory-connection-text.balance-mode'}
elseif mode == 1 then
return {'factory-connection-text.input-mode'}
else
return {'factory-connection-text.output-mode'}
end
end
Chest.adjust = function(conn, positive)
local delay = conn._settings.delay or DEFAULT_DELAY
if positive then
for i = #DELAYS,1,-1 do
if DELAYS[i] < delay then
delay = DELAYS[i]
break
end
end
conn._settings.delay = delay
return {'factory-connection-text.update-faster', delay}
else
for i = 1,#DELAYS do
if DELAYS[i] > delay then
delay = DELAYS[i]
break
end
end
conn._settings.delay = delay
return {'factory-connection-text.update-slower', delay}
end
end
local basic_item_types = {['item'] = true, ['capsule'] = true, ['gun'] = true, ['rail-planner'] = true, ['module'] = true}
local function check_for_basic_item(item)
local items_with_metadata = global.items_with_metadata
if not items_with_metadata then
items_with_metadata = {}
for item_name, prototype in pairs(game.item_prototypes) do
if not basic_item_types[prototype.type] then
items_with_metadata[item_name] = true
end
end
global.items_with_metadata = items_with_metadata
end
return not items_with_metadata[item]
end
local function move_item(item, count, input_inv, output_inv)
if check_for_basic_item(item) then
-- basic item being transfered
local inserted_count = output_inv.insert{name = item, count = count}
if inserted_count > 0 then
input_inv.remove{name = item, count = inserted_count}
end
else
-- advanced item being transfered, need to preserve tags, durablity, ect
-- not safe to "split" the stack here, may result in some item sloshing
while count > 0 do
local stack = input_inv.find_item_stack(item)
local empty_slot, i = output_inv.find_empty_stack(item)
if not stack or not empty_slot then break end
if output_inv.supports_bar() and output_inv.get_bar() == i then break end
if not stack.swap_stack(empty_slot) then break end
count = count - stack.count
end
output_inv.sort_and_merge()
end
end
local floor = math.floor
local function balance(outside_inv, inside_inv)
local outside_contents = outside_inv.get_contents()
local inside_contents = inside_inv.get_contents()
for item, count in pairs(outside_contents) do
local count2 = inside_contents[item] or 0
local diff = count - count2
if diff > 1 then
move_item(item, floor(diff / 2), outside_inv, inside_inv)
elseif diff < -1 then
move_item(item, floor(-diff / 2), inside_inv, outside_inv)
end
end
for item, count in pairs(inside_contents) do
if count > 1 and not outside_contents[item] then
move_item(item, floor(count / 2), inside_inv, outside_inv)
end
end
end
local function inwards(outside_inv, inside_inv)
local outside_contents = outside_inv.get_contents()
for item, count in pairs(outside_contents) do
move_item(item, count, outside_inv, inside_inv)
end
end
local function outwards(outside_inv, inside_inv)
local inside_contents = inside_inv.get_contents()
for item, count in pairs(inside_contents) do
move_item(item, count, inside_inv, outside_inv)
end
end
Chest.tick = function(conn)
local outside = conn.outside
local inside = conn.inside
if outside.valid and inside.valid then
local outside_inv = outside.get_inventory(defines.inventory.chest)
local inside_inv = inside.get_inventory(defines.inventory.chest)
local mode = conn._settings.mode or 0
if mode == 0 then
balance(outside_inv, inside_inv)
elseif mode == 1 then
inwards(outside_inv, inside_inv)
else
outwards(outside_inv, inside_inv)
end
return conn._settings.delay or DEFAULT_DELAY
else
return false
end
end
Chest.destroy = function(conn)
end
return Chest