277 lines
10 KiB
Lua
277 lines
10 KiB
Lua
Connections = {}
|
|
|
|
-- Connection types --
|
|
|
|
local type_map = {}
|
|
|
|
-- Not using metatables, for..... reasons
|
|
local c_unlocked = {}
|
|
local c_color = {}
|
|
local c_connect = {}
|
|
local c_recheck = {}
|
|
local c_direction = {}
|
|
local c_rotate = {}
|
|
local c_adjust = {}
|
|
local c_tick = {}
|
|
local c_destroy = {}
|
|
local indicator_names = {}
|
|
Connections.indicator_names = indicator_names
|
|
|
|
local function register_connection_type(ctype, class)
|
|
for _, etype in pairs(class.entity_types) do
|
|
type_map[etype] = ctype
|
|
end
|
|
c_unlocked[ctype] = class.unlocked
|
|
c_color[ctype] = class.color
|
|
c_connect[ctype] = class.connect
|
|
c_recheck[ctype] = class.recheck
|
|
c_direction[ctype] = class.direction
|
|
c_rotate[ctype] = class.rotate
|
|
c_adjust[ctype] = class.adjust
|
|
c_tick[ctype] = class.tick
|
|
c_destroy[ctype] = class.destroy
|
|
for _, name in pairs(class.indicator_settings) do
|
|
indicator_names['factory-connection-indicator-' .. ctype .. '-' .. name] = ctype
|
|
end
|
|
end
|
|
|
|
local function is_connectable(entity)
|
|
return type_map[entity.type] or type_map[entity.name]
|
|
end
|
|
Connections.is_connectable = is_connectable
|
|
|
|
-- Connection data structure --
|
|
|
|
local CYCLIC_BUFFER_SIZE = 600
|
|
local function init_data_structure()
|
|
global.connections = global.connections or {}
|
|
global.delayed_connection_checks = global.delayed_connection_checks or {}
|
|
for i = 0, CYCLIC_BUFFER_SIZE - 1 do
|
|
global.connections[i] = global.connections[i] or {}
|
|
end
|
|
end
|
|
Connections.init_data_structure = init_data_structure
|
|
|
|
local function add_connection_to_queue(conn)
|
|
local current_pos = (math.floor(game.tick / CONNECTION_UPDATE_RATE) + 1) * CONNECTION_UPDATE_RATE % CYCLIC_BUFFER_SIZE
|
|
table.insert(global.connections[current_pos], conn)
|
|
end
|
|
|
|
-- Connection settings --
|
|
|
|
local function get_connection_settings(factory, cid, ctype)
|
|
factory.connection_settings[cid] = factory.connection_settings[cid] or {}
|
|
factory.connection_settings[cid][ctype] = factory.connection_settings[cid][ctype] or {}
|
|
return factory.connection_settings[cid][ctype]
|
|
end
|
|
Connections.get_connection_settings = get_connection_settings
|
|
|
|
-- Connection indicators --
|
|
|
|
local function set_connection_indicator(factory, cid, ctype, setting, dir)
|
|
local old_indicator = factory.connection_indicators[cid]
|
|
if old_indicator and old_indicator.valid then old_indicator.destroy() end
|
|
local cpos = factory.layout.connections[cid]
|
|
local new_indicator = factory.inside_surface.create_entity{
|
|
name = 'factory-connection-indicator-' .. ctype .. '-' .. setting,
|
|
direction = dir, force = factory.force,
|
|
position = {x = factory.inside_x + cpos.inside_x + cpos.indicator_dx, y = factory.inside_y + cpos.inside_y + cpos.indicator_dy},
|
|
create_build_effect_smoke = false
|
|
}
|
|
new_indicator.destructible = false
|
|
factory.connection_indicators[cid] = new_indicator
|
|
end
|
|
|
|
local function delete_connection_indicator(factory, cid, ctype)
|
|
local old_indicator = factory.connection_indicators[cid]
|
|
if old_indicator and old_indicator.valid then old_indicator.destroy() end
|
|
end
|
|
|
|
local function refresh_connection_indicator(conn) -- Used in update 5
|
|
if conn and conn._valid then
|
|
local setting, dir = c_direction[conn._type](conn)
|
|
set_connection_indicator(conn._factory, conn._id, conn._type, setting, dir)
|
|
end
|
|
end
|
|
Connections.refresh_connection_indicator = refresh_connection_indicator
|
|
|
|
-- Connection changes --
|
|
|
|
local function register_connection(factory, cid, ctype, conn, settings)
|
|
conn._id = cid
|
|
conn._type = ctype
|
|
conn._factory = factory
|
|
conn._settings = settings
|
|
conn._valid = true
|
|
factory.connections[cid] = conn
|
|
if conn.do_tick_update then add_connection_to_queue(conn) end
|
|
local setting, dir = c_direction[ctype](conn)
|
|
set_connection_indicator(factory, cid, ctype, setting, dir)
|
|
end
|
|
|
|
local function init_connection(factory, cid, cpos) -- Only call this when factory.connections[cid] == nil!
|
|
local outside_entities = factory.outside_surface.find_entities_filtered{
|
|
position = {cpos.outside_x + factory.outside_x, cpos.outside_y + factory.outside_y},
|
|
force = factory.force
|
|
}
|
|
if (outside_entities == nil or next(outside_entities) == nil) then return end
|
|
local inside_entities = factory.inside_surface.find_entities_filtered{
|
|
position = {cpos.inside_x + factory.inside_x, cpos.inside_y + factory.inside_y},
|
|
force = factory.force
|
|
}
|
|
if (inside_entities == nil or next(inside_entities) == nil) then return end
|
|
for _, outside_entity in pairs(outside_entities) do
|
|
local oct = type_map[outside_entity.type] or type_map[outside_entity.name]
|
|
if oct ~= nil then
|
|
for _, inside_entity in pairs(inside_entities) do
|
|
local ict = type_map[inside_entity.type] or type_map[inside_entity.name]
|
|
if oct == ict then
|
|
if c_unlocked[oct](factory.force) then
|
|
local sound_1 = {path = 'entity-close/assembling-machine-3', position = inside_entity.position}
|
|
local sound_2 = {path = 'entity-close/assembling-machine-3', position = outside_entity.position}
|
|
local settings = get_connection_settings(factory, cid, oct)
|
|
local conn = c_connect[oct](factory, cid, cpos, outside_entity, inside_entity, settings)
|
|
if conn then
|
|
factory.inside_surface.play_sound(sound_1)
|
|
factory.outside_surface.play_sound(sound_2)
|
|
register_connection(factory, cid, oct, conn, settings)
|
|
return
|
|
end
|
|
else
|
|
factory.inside_surface.create_entity{name = 'flying-text', position = inside_entity.position, text = {'research-required'}}
|
|
factory.outside_surface.create_entity{name = 'flying-text', position = outside_entity.position, text = {'research-required'}}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Connections.init_connection = init_connection
|
|
|
|
local function destroy_connection(conn)
|
|
if conn._valid then
|
|
c_destroy[conn._type](conn)
|
|
conn._valid = false -- _valid should be true iff conn._factory.connections[conn._id] == conn
|
|
conn._factory.connections[conn._id] = nil -- Lua can handle this
|
|
delete_connection_indicator(conn._factory, conn._id, conn._type)
|
|
end
|
|
end
|
|
Connections.destroy_connection = destroy_connection
|
|
|
|
local function in_area(x, y, area)
|
|
return (x >= area.left_top.x and x <= area.right_bottom.x and y >= area.left_top.y and y <= area.right_bottom.y)
|
|
end
|
|
|
|
local function recheck_factory(factory, outside_area, inside_area) -- Areas are optional
|
|
if (not factory.built) then return end
|
|
for cid, cpos in pairs(factory.layout.connections) do
|
|
if (outside_area == nil or in_area(cpos.outside_x+factory.outside_x, cpos.outside_y+factory.outside_y, outside_area))
|
|
and (inside_area == nil or in_area(cpos.inside_x+factory.inside_x, cpos.inside_y+factory.inside_y, inside_area)) then
|
|
local conn = factory.connections[cid]
|
|
if conn then
|
|
if c_recheck[conn._type](conn) then
|
|
-- Everything is fine
|
|
else
|
|
destroy_connection(conn)
|
|
init_connection(factory, cid, cpos)
|
|
end
|
|
else
|
|
init_connection(factory, cid, cpos)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Connections.recheck_factory = recheck_factory
|
|
|
|
-- During deconstruction events of an entity that is part of a connection, the entity is still valid and built, so recheck_factory would not destroy the connection involved.
|
|
-- Delaying the recheck causes these connections to be properly deconstructed immediately, instead of having to wait until the connection ticks again.
|
|
local function recheck_factory_delayed(factory, outside_area, inside_area)
|
|
-- Note that connections should still be designed such that absolutely nothing would break even if this function was empty!
|
|
global.delayed_connection_checks[1+#(global.delayed_connection_checks)] = {
|
|
factory = factory,
|
|
outside_area = outside_area,
|
|
inside_area = inside_area
|
|
}
|
|
end
|
|
Connections.recheck_factory_delayed = recheck_factory_delayed
|
|
|
|
local function disconnect_factory(factory)
|
|
for cid, conn in pairs(factory.connections) do
|
|
destroy_connection(conn)
|
|
end
|
|
end
|
|
Connections.disconnect_factory = disconnect_factory
|
|
|
|
-- Connection effects --
|
|
|
|
local function update()
|
|
-- First let's run all them delayed connection checks
|
|
for _, check in ipairs(global.delayed_connection_checks) do
|
|
recheck_factory(check.factory, check.outside_area, check.inside_area)
|
|
end
|
|
global.delayed_connection_checks = {}
|
|
|
|
local current_pos = game.tick % CYCLIC_BUFFER_SIZE
|
|
local connections = global.connections
|
|
local current_slot = connections[current_pos]
|
|
connections[current_pos] = {}
|
|
for _, conn in pairs(current_slot) do
|
|
local delay = (conn._valid and c_tick[conn._type](conn))
|
|
if delay then
|
|
-- Reinsert connection after delay
|
|
-- Not checking for inappropriate delays, so keep your delays civil
|
|
local queue_pos = (current_pos + delay) % CYCLIC_BUFFER_SIZE
|
|
local new_slot = connections[queue_pos]
|
|
new_slot[1 + #new_slot] = conn
|
|
elseif conn._valid then
|
|
destroy_connection(conn)
|
|
init_connection(conn._factory, conn._id, conn._factory.layout.connections[conn._id])
|
|
end
|
|
end
|
|
end
|
|
Connections.update = update
|
|
|
|
local function rotate(factory, indicator)
|
|
for cid, ind2 in pairs(factory.connection_indicators) do
|
|
if ind2 and ind2.valid then
|
|
if (ind2.unit_number == indicator.unit_number) then
|
|
local conn = factory.connections[cid]
|
|
local text = c_rotate[conn._type](conn)
|
|
factory.inside_surface.create_entity{name='flying-text', position=indicator.position, color=c_color[conn._type], text=text}
|
|
local setting, dir = c_direction[conn._type](conn)
|
|
set_connection_indicator(factory, cid, conn._type, setting, dir)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Connections.rotate = rotate
|
|
|
|
local function adjust(factory, indicator, positive)
|
|
for cid, ind2 in pairs(factory.connection_indicators) do
|
|
if ind2 and ind2.valid then
|
|
if (ind2.unit_number == indicator.unit_number) then
|
|
local conn = factory.connections[cid]
|
|
local text = c_adjust[conn._type](conn, positive)
|
|
factory.inside_surface.create_entity{name='flying-text', position=indicator.position, color=c_color[conn._type], text=text}
|
|
local setting, dir = c_direction[conn._type](conn)
|
|
set_connection_indicator(factory, cid, conn._type, setting, dir)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Connections.adjust = adjust
|
|
|
|
local beeps = {'Beep', 'Boop', 'Beep', 'Boop', 'Beeple'}
|
|
Connections.beep = function()
|
|
local t = game.tick
|
|
return beeps[t % 5 + 1]
|
|
end
|
|
|
|
register_connection_type('belt', require('belt'))
|
|
register_connection_type('chest', require('chest'))
|
|
register_connection_type('fluid', require('fluid'))
|
|
register_connection_type('circuit', require('circuit'))
|
|
register_connection_type('heat', require('heat'))
|