295 lines
12 KiB
Lua
295 lines
12 KiB
Lua
-------------------------------------------------------------------------------
|
|
--[[roboport-interface]]
|
|
-------------------------------------------------------------------------------
|
|
local Event = require('__stdlib__/stdlib/event/event')
|
|
local Position = require('__stdlib__/stdlib/area/position')
|
|
local table = require('__stdlib__/stdlib/utils/table')
|
|
local Queue = require('scripts/hash_queue')
|
|
local queue
|
|
|
|
local floor = math.floor
|
|
|
|
local params_to_check = {
|
|
['nano-signal-chop-trees'] = {
|
|
action = 'mark_items_or_trees',
|
|
find_type = 'tree',
|
|
item_name = 'raw-wood'
|
|
},
|
|
['nano-signal-item-on-ground'] = {
|
|
action = 'mark_items_or_trees',
|
|
find_type = 'item-entity'
|
|
},
|
|
['nano-tile'] = {
|
|
action = 'tile_ground'
|
|
},
|
|
['nano-signal-deconstruct-finished-miners'] = {
|
|
action = 'deconstruct_finished_miners',
|
|
find_type = 'mining-drill'
|
|
},
|
|
--[[['nano-signal-landfill-the-world'] = {
|
|
action = 'landfill_the_world'
|
|
},
|
|
['nano-signal-remove-tiles'] = {
|
|
action = 'remove_tiles'
|
|
},]] -- signals removed
|
|
['nano-signal-catch-fish'] = {
|
|
action = 'mark_items_or_trees',
|
|
find_type = 'fish',
|
|
item_name = 'fish'
|
|
}
|
|
}
|
|
|
|
--[[
|
|
raw-wood-cutting, scan for trees, if value is negative only scan for trees if wood in network is less then that amount
|
|
tile-item, scan for tiles, only checks first signal, if negative, will not place tiles unless that many are in network.
|
|
item-on-ground-sig, Scan for items on ground, if found cell will check for items-ground and mark for pickup if no enemies in range
|
|
networks-sig
|
|
|
|
parameters ={
|
|
{
|
|
count = 1,
|
|
index = 1,
|
|
signal = {
|
|
name = "nano-signal-item-on-ground",
|
|
type = "virtual"
|
|
}
|
|
},
|
|
{
|
|
count = 1,
|
|
index = 2,
|
|
signal = {
|
|
type = "item"
|
|
}
|
|
},
|
|
}
|
|
--]]
|
|
local function get_parameters(params)
|
|
local parameters = {}
|
|
for _, param in pairs(params) do
|
|
if param.signal.name then
|
|
parameters[param.signal.name] = param.count
|
|
end
|
|
end
|
|
return parameters
|
|
end
|
|
|
|
local function get_entity_info(entity)
|
|
return entity.surface, entity.force, entity.position
|
|
end
|
|
|
|
Queue.mark_items_or_trees =
|
|
function(data)
|
|
if data.logistic_cell.valid and data.logistic_cell.construction_radius > 0 and data.logistic_cell.logistic_network then
|
|
local surface, force, position = get_entity_info(data.logistic_cell.owner)
|
|
if not (data.find_type or data.find_name) then
|
|
data.find_type = 'NIL'
|
|
end
|
|
if not surface.find_nearest_enemy {position = position, max_distance = data.logistic_cell.construction_radius * 1.5 + 40, force = force} then
|
|
local filter = {
|
|
area = Position.expand_to_area(position, data.logistic_cell.construction_radius),
|
|
name = data.find_name,
|
|
type = data.find_type,
|
|
limit = 300
|
|
}
|
|
local config = settings['global']
|
|
local available_bots = floor(data.logistic_cell.logistic_network.available_construction_robots - (data.logistic_cell.logistic_network.all_construction_robots * (config['nanobots-free-bots-per'].value / 100)))
|
|
local limit = -99999999999
|
|
if data.value < 0 and data.item_name then
|
|
limit = (data.logistic_cell.logistic_network.get_contents()[data.item_name] or 0) + data.value
|
|
end
|
|
|
|
for _, item in pairs(surface.find_entities_filtered(filter)) do
|
|
if available_bots > 0 and (limit < 0) then
|
|
if not item.to_be_deconstructed(force) then
|
|
item.order_deconstruction(force)
|
|
available_bots = available_bots - 1
|
|
limit = limit + 1
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function has_resources(miner)
|
|
local _find = function(v, _)
|
|
return v.prototype.resource_category == 'basic-solid' and (v.amount > 0 or v.prototype.infinite_resource)
|
|
end
|
|
local filter = {area = Position.expand_to_area(miner.position, miner.prototype.mining_drill_radius), type = 'resource'}
|
|
if miner.mining_target then
|
|
return (miner.mining_target.amount or 0) > 0
|
|
else
|
|
return table.find(miner.surface.find_entities_filtered(filter), _find)
|
|
end
|
|
end
|
|
|
|
Queue.deconstruct_finished_miners = function(data)
|
|
if not game.active_mods['AutoDeconstruct'] then
|
|
if data.logistic_cell.valid and data.logistic_cell.construction_radius > 0 and data.logistic_cell.logistic_network then
|
|
local surface, force, position = get_entity_info(data.logistic_cell.owner)
|
|
local filter = {area = Position.expand_to_area(position, data.logistic_cell.construction_radius), type = data.find_type or 'error', force = force}
|
|
for _, miner in pairs(surface.find_entities_filtered(filter)) do
|
|
if not miner.to_be_deconstructed(force) and miner.minable and not miner.has_flag('not-deconstructable') and not has_resources(miner) then
|
|
miner.order_deconstruction(force)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function find_network_and_cell(interface)
|
|
local port = interface.surface.find_entities_filtered {name = 'roboport-interface-main', position = interface.position}[1]
|
|
if port and port.valid then
|
|
local network = port.logistic_network
|
|
local cell =
|
|
table.find(
|
|
port.logistic_cell.neighbours,
|
|
function(v)
|
|
return v.construction_radius > 0
|
|
end
|
|
) or port.logistic_cell
|
|
return network, cell
|
|
end
|
|
end
|
|
|
|
local function run_interface(interface)
|
|
local behaviour = interface.get_control_behavior()
|
|
if behaviour and behaviour.enabled then
|
|
local logistic_network, logistic_cell = find_network_and_cell(interface)
|
|
if logistic_network and logistic_network.available_construction_robots > logistic_network.all_construction_robots * (settings['global']['nanobots-free-bots-per'].value / 100) then
|
|
local tick_spacing = settings['global']['nanobots-cell-queue-rate'].value
|
|
local parameters = get_parameters(behaviour.parameters)
|
|
--game.print(serpent.block(parameters, {comment=false, sparse=false}))
|
|
-- If the closest roboport signal is present and > 0 then just run on the attached cell
|
|
local just_cell = (parameters['nano-signal-closest-roboport'] or 0) > 0 and logistic_cell and {logistic_cell} or nil
|
|
local fdata = global.forces[logistic_cell.owner.force.name]
|
|
local next_tick = queue:next(fdata._next_cell_tick or game.tick, tick_spacing, true)
|
|
for param_name, param_table in pairs(params_to_check) do
|
|
if (parameters[param_name] or 0) ~= 0 then
|
|
for _, cell in pairs(just_cell or logistic_network.cells) do
|
|
local hash = queue:get_hash(cell.owner)
|
|
if not cell.mobile and cell.construction_radius > 0 and queue:count() < 5000 and not (hash and hash[param_table.action]) then
|
|
local data = {
|
|
position = cell.owner.position,
|
|
logistic_cell = cell,
|
|
entity = cell.owner,
|
|
logistic_network = logistic_network,
|
|
name = param_name,
|
|
action = param_table.action,
|
|
find_type = param_table.find_type,
|
|
find_name = param_table.find_name,
|
|
item_name = param_table.item_name,
|
|
value = parameters[param_name],
|
|
unit_number = cell.owner.unit_number
|
|
}
|
|
queue:insert(data, next_tick())
|
|
end
|
|
end
|
|
end
|
|
end
|
|
fdata._next_cell_tick = queue:count() > 0 and next_tick() or game.tick
|
|
end
|
|
end
|
|
end
|
|
|
|
local function execute_interface_queue(event)
|
|
queue:execute(event)
|
|
end
|
|
Event.register(defines.events.on_tick, execute_interface_queue)
|
|
|
|
--[Roboport Interface Scanner]--
|
|
local function kill_or_remove_interface_parts(event, destroy)
|
|
if event.entity.name == 'roboport-interface-main' then
|
|
destroy = destroy or event.mod == 'creative-mode'
|
|
local interface = event.entity
|
|
for _, entity in pairs(interface.surface.find_entities_filtered {position = interface.position, force = interface.force}) do
|
|
if entity ~= interface and entity.name:find('^roboport%-interface') then
|
|
_ = (destroy and entity.destroy()) or entity.die()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_entity_died, kill_or_remove_interface_parts)
|
|
Event.register(
|
|
Event.mined_events,
|
|
function(event)
|
|
kill_or_remove_interface_parts(event, true)
|
|
end
|
|
)
|
|
|
|
--Build the interface, after built check the area around it for interface components to revive or create.
|
|
local function build_roboport_interface(event)
|
|
local interface = event.created_entity or event.entity
|
|
if interface and interface.name == 'roboport-interface-main' then
|
|
local pos, force = interface.position, interface.force
|
|
local cc, ra = {}, {} -- Don't listen the masses.... a little gc churn later is two less type() calls now.
|
|
for _, entity in pairs(interface.surface.find_entities_filtered {position = pos, force = force}) do
|
|
if entity ~= interface then
|
|
--If we have ghosts either via blueprint or something killed them
|
|
if entity.name == 'entity-ghost' then
|
|
if entity.ghost_name == 'roboport-interface-cc' then
|
|
_, cc = entity.revive()
|
|
elseif entity.ghost_name == 'roboport-interface-scanner' then
|
|
_, ra = entity.revive()
|
|
end
|
|
elseif entity.name == 'roboport-interface-cc' then
|
|
cc = entity
|
|
elseif entity.name == 'roboport-interface-scanner' then
|
|
ra = entity
|
|
end
|
|
end
|
|
end
|
|
--If neither CC or RA are valid at this point then let us create them.
|
|
if not cc.valid then
|
|
cc = interface.surface.create_entity {name = 'roboport-interface-cc', position = pos, force = force}
|
|
end
|
|
if not ra.valid then
|
|
ra = interface.surface.create_entity {name = 'roboport-interface-scanner', position = pos, force = force}
|
|
end
|
|
|
|
--roboports start with a buffer of energy. Lets take that away!
|
|
interface.energy = 0
|
|
--Use the same backer name for the interface and radar
|
|
ra.backer_name = interface.backer_name
|
|
cc.direction = defines.direction.north
|
|
cc.destructible = false
|
|
ra.destructible = false
|
|
end
|
|
end
|
|
Event.register(Event.build_events, build_roboport_interface)
|
|
|
|
local function on_sector_scanned(event)
|
|
if event.radar.name == 'roboport-interface-scanner' then
|
|
local entity = event.radar
|
|
local interface = entity.surface.find_entities_filtered {name = 'roboport-interface-cc', position = entity.position, limit = 1}[1]
|
|
if interface and interface.valid then
|
|
run_interface(interface)
|
|
end
|
|
end
|
|
end
|
|
Event.register(defines.events.on_sector_scanned, on_sector_scanned)
|
|
|
|
local function on_init()
|
|
global.cell_queue = Queue()
|
|
queue = global.cell_queue
|
|
end
|
|
Event.register(Event.core_events.init, on_init)
|
|
|
|
local function on_load()
|
|
queue = Queue(global.cell_queue)
|
|
end
|
|
Event.register(Event.core_events.load, on_load)
|
|
|
|
local function reset_cell_queue()
|
|
global.cell_queue = nil
|
|
queue = nil
|
|
global.cell_queue = Queue()
|
|
queue = global.cell_queue
|
|
for _, fdata in pairs(global.forces) do
|
|
fdata._next_cell_tick = game and game.tick or 0
|
|
end
|
|
end
|
|
Event.register(Event.generate_event_name('reset_cell_queue'), reset_cell_queue)
|