1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2024-12-30 23:17:53 +02:00
ComfyFactorio/modules/autofill.lua
2021-03-24 16:46:00 +01:00

550 lines
15 KiB
Lua

local Color = require 'utils.color_presets'
local Event = require 'utils.event'
local Global = require 'utils.global'
local this = {
refill_turrets = {},
refill_chests = {index = 1, placed = 0},
full_turrets = {},
valid_chest = {
['iron-chest'] = {valid = true, limit = 4}
},
valid_turrets = {
['gun-turret'] = true,
['artillery-turret'] = true
},
valid_ammo = {
['firearm-magazine'] = {valid = true, priority = 1},
['piercing-rounds-magazine'] = {valid = true, priority = 2},
['uranium-rounds-magazine'] = {valid = true, priority = 3}
},
message_limit = {},
player_settings = {},
globally_enabled = false
}
Global.register(
this,
function(t)
this = t
end
)
local Public = {}
local insert = table.insert
local autofill_amount = 10
local valid_chest = this.valid_chest
local valid_turrets = this.valid_turrets
local valid_ammo = this.valid_ammo
local function validate_entity(entity)
if not entity then
return false
end
if not entity.valid then
return false
end
return true
end
local function fast_remove(tbl, index)
local count = #tbl
if index > count then
return
elseif index < count then
tbl[index] = tbl[count]
end
tbl[count] = nil
end
local function get_player_data(player, remove_user_data)
if this.globally_enabled then
return
end
if remove_user_data then
if this.player_settings[player.index] then
this.player_settings[player.index] = nil
end
end
if not this.player_settings[player.index] then
this.player_settings[player.index] = {
placed = 0,
chests = {},
turrets = {},
enabled = true
}
end
return this.player_settings[player.index]
end
local function contains(table, entity)
if not table then
return
end
for k, turret in pairs(table) do
if not validate_entity(turret) then
return false
end
if not validate_entity(entity) then
return false
end
if turret.unit_number == entity.unit_number then
return true
end
end
end
local function get_highest(table)
local highest = -math.huge
local item
local count
for k, v in pairs(table) do
if (k and valid_ammo[k] and valid_ammo[k].priority > highest) then
item = k
count = v
end
end
if not item or not count then
return false
end
return item, count
end
local function get_valid_chest()
local chests = {}
if this.globally_enabled then
local refill_chests = this.refill_chests
if not next(refill_chests) then
return
end
local chest
for i = 1, #refill_chests do
chest = refill_chests[i]
if chest then
chests[#chests + 1] = chest
end
if not chest.valid then
fast_remove(refill_chests, i)
refill_chests.placed = refill_chests.placed - 1
if refill_chests.placed <= 0 then
refill_chests.placed = 0
end
return false
end
end
return chests
end
local player_data = this.player_settings
if not next(player_data) then
return
end
local chest
for i = 1, #player_data do
local player = game.get_player(i)
if player and player.valid then
local p_data = get_player_data(player)
local p_chests = p_data.chests
if not next(p_chests) then
return
end
for t = 1, #p_chests do
chest = p_chests[t]
if chest then
chests[#chests + 1] = chest
end
if not chest.valid then
fast_remove(p_data.chests, i)
p_data.placed = p_data.placed - 1
if p_data.placed <= 0 then
p_data.placed = 0
end
return
end
end
end
end
return chests
end
local function get_ammo(entity_turret)
local turret = entity_turret.get_inventory(defines.inventory.turret_ammo)
local contents = turret.get_contents()
local c = 0
for item, count in pairs(contents) do
if valid_ammo[item] and valid_ammo[item].valid and count >= 1 then
c = count
return item, c
end
end
return false, c
end
local function get_items(chest)
local contents = chest.get_contents()
local item, count = get_highest(contents)
if valid_ammo[item] and valid_ammo[item].valid and count >= 1 then
return item, count
end
end
local function remove_ammo(chest, entity_turret)
local turret = entity_turret.get_inventory(defines.inventory.turret_ammo)
local current_ammo
if not chest or not chest.valid then
return
end
local contents = turret.get_contents()
for item, count in pairs(contents) do
if count >= 1 then
local t = {name = item, count = count}
if chest.can_insert(t) then
local c = chest.insert(t)
current_ammo = item
turret.remove({name = item, count = c})
return current_ammo
end
end
end
end
local function refill(entity_turret, entity_chest)
local turret = entity_turret
for _, chests in next, entity_chest do
local chest = chests.get_inventory(defines.inventory.chest)
local item, count = get_items(chest)
local turret_inv = turret.get_inventory(defines.inventory.turret_ammo)
if valid_ammo[item] and valid_ammo[item].valid and count >= 1 then
local ammo_name, ammo_count = get_ammo(turret)
if ammo_name and valid_ammo[ammo_name].priority < valid_ammo[item].priority then
remove_ammo(chest, turret)
end
if ammo_count and ammo_count >= 10 then
goto continue
end
local t = {name = item, count = 1}
local c = turret_inv.insert(t)
if (c > 0) then
chest.remove({name = item, count = c})
end
::continue::
end
end
end
local function do_refill_turrets()
local chest = get_valid_chest()
if not chest then
return
end
if this.globally_enabled then
local turrets = this.refill_turrets
if not next(turrets) then
return
end
for i = 1, #turrets do
local turret = turrets[i]
if not turret then
return
end
if not turret.valid then
fast_remove(turrets, i)
else
refill(turret, chest)
end
end
return
end
local player_data = this.player_settings
if not next(player_data) then
return
end
for p, _ in next, player_data do
local player = game.get_player(p)
if player and player.valid then
local p_data = get_player_data(player)
if not p_data then
return
end
local turrets = p_data.turrets
if not next(turrets) then
return
end
for key, turret in next, turrets do
if not turret then
return
end
if not turret.valid then
fast_remove(turrets, key)
else
refill(turret, chest)
end
end
end
end
end
local function show_text(msg, pos, color, surface)
if color == nil then
surface.create_entity({name = 'flying-text', position = pos, text = msg})
else
surface.create_entity({name = 'flying-text', position = pos, text = msg, color = color})
end
end
local function move_items(source, destination, stack)
if (source.get_item_count(stack.name) == 0) then
return -1
end
if (not destination.can_insert(stack)) then
return -2
end
local itemsRemoved = source.remove(stack)
stack.count = itemsRemoved
return destination.insert(stack)
end
local function move_multiple(source, destination, stack, amount)
local ret = 0
for _, itemName in pairs(stack) do
ret = move_items(source, destination, {name = itemName, count = amount})
if (ret > 0) then
return ret
end
end
return ret
end
local function auto_insert_into_turret(player, turret)
local inventory = player.get_main_inventory()
if (inventory == nil) then
return
end
local ret = move_multiple(inventory, turret, {'artillery-shell', 'uranium-rounds-magazine', 'piercing-rounds-magazine', 'firearm-magazine'}, autofill_amount)
if (ret > 1) then
show_text('[Autofill] Inserted ' .. ret .. '!', turret.position, Color.info, player.surface)
elseif (ret == -1) then
show_text('[Autofill] Out of ammo!', turret.position, Color.red, player.surface)
elseif (ret == -2) then
show_text('[Autofill] Autofill ERROR! - Report this bug!', turret.position, Color.red, player.surface)
end
end
local function auto_insert_into_vehicle(player, vehicle)
local inventory = player.get_main_inventory()
if (inventory == nil) then
return
end
if ((vehicle.name == 'car') or (vehicle.name == 'tank') or (vehicle.name == 'locomotive')) then
move_multiple(inventory, vehicle, {'nuclear-fuel', 'rocket-fuel', 'solid-fuel', 'coal', 'wood'}, 50)
end
if ((vehicle.name == 'car') or (vehicle.name == 'tank')) then
move_multiple(inventory, vehicle, {'uranium-rounds-magazine', 'piercing-rounds-magazine', 'firearm-magazine'}, autofill_amount)
end
if (vehicle.name == 'tank') then
move_multiple(inventory, vehicle, {'explosive-uranium-cannon-shell', 'uranium-cannon-shell', 'explosive-cannon-shell', 'cannon-shell'}, autofill_amount)
end
end
local function on_entity_built(event)
local player = game.players[event.player_index]
if not (player and player.valid) then
return
end
local ce = event.created_entity
if not (ce and ce.valid) then
return
end
if (valid_chest[ce.name] and valid_chest[ce.name].valid) then
if this.globally_enabled then
if (this.refill_chests.placed < valid_chest[ce.name].limit) then
if this.message_limit[player.index] then
this.message_limit[player.index] = nil
end
Public.add_chest_to_refill_callback(nil, ce)
else
if not this.message_limit[player.index] then
this.message_limit[player.index] = true
player.print('[Autofill] Chest limit reached.', Color.warning)
end
end
else
local player_data = get_player_data(player)
if (player_data.placed < valid_chest[ce.name].limit) then
if this.message_limit[player.index] then
this.message_limit[player.index] = nil
end
Public.add_chest_to_refill_callback(player, ce)
else
if not this.message_limit[player.index] then
this.message_limit[player.index] = true
player.print('[Autofill] Chest limit reached.', Color.warning)
end
end
end
end
if (valid_turrets[ce.name]) then
if this.globally_enabled then
Public.refill_turret_callback(nil, ce)
else
Public.refill_turret_callback(player, ce)
end
auto_insert_into_turret(player, ce)
end
if ((ce.name == 'car') or (ce.name == 'tank') or (ce.name == 'locomotive')) then
auto_insert_into_vehicle(player, ce)
end
end
local function on_pre_player_mined_item(event)
local player = game.get_player(event.player_index)
if not validate_entity(player) then
return
end
local entity = event.entity
if not validate_entity(entity) then
return
end
if not valid_turrets[entity.name] then
return
end
if this.globally_enabled then
local chest = get_valid_chest()
if not chest then
return
end
local refill_turrets = this.refill_turrets
local full_turrets = this.full_turrets
if contains(refill_turrets, entity) or contains(full_turrets, entity) then
remove_ammo(chest, entity)
end
return
end
local chest = get_valid_chest(player)
if not chest then
return
end
local refill_turrets = this.refill_turrets
local full_turrets = this.full_turrets
if contains(refill_turrets, entity) or contains(full_turrets, entity) then
remove_ammo(chest, entity)
end
end
local function on_tick()
do_refill_turrets()
end
Public.refill_turret_callback = function(player, turret)
if this.globally_enabled then
local refill_turrets = this.refill_turrets
if turret and turret.valid then
refill_turrets[#refill_turrets + 1] = turret
end
return
end
if turret and turret.valid then
local player_data = get_player_data(player)
local turrets = player_data.turrets
insert(turrets, turret)
end
end
Public.add_chest_to_refill_callback = function(player, entity)
if entity and entity.valid then
if this.globally_enabled then
local refill_chests = this.refill_chests
refill_chests[#refill_chests + 1] = entity
refill_chests.placed = refill_chests.placed + 1
else
local player_data = get_player_data(player)
local chest_placed = player_data.placed
local chests = player_data.chests
insert(chests, entity)
player_data.placed = chest_placed + 1
end
rendering.draw_text {
text = '',
surface = entity.surface,
target = entity,
target_offset = {0, -0.5},
scale = 1.5,
color = {r = 0, g = 0.6, b = 1},
alignment = 'center'
}
end
end
Public.globally_enabled = function(value)
if value then
this.globally_enabled = value
else
this.globally_enabled = false
end
return this.globally_enabled
end
Event.add(defines.events.on_built_entity, on_entity_built)
Event.add(defines.events.on_pre_player_mined_item, on_pre_player_mined_item)
Event.on_nth_tick(50, on_tick)
return Public