848 lines
34 KiB
Lua
848 lines
34 KiB
Lua
require("util")
|
|
local compound_entities = require("prototypes.compound_entities.main_list")
|
|
|
|
return function (mod_name)
|
|
local common = {}
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Get mod name and path to mod
|
|
common.modName = script and script.mod_name or mod_name
|
|
common.modRoot = "__" .. common.modName .. "__"
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Greatly improved version check for mods (thanks to eradicator!)
|
|
common.Version = {}
|
|
do
|
|
local V = common.Version
|
|
|
|
local function parse_version(vstr) -- string "Major.Minor.Patch"
|
|
local err = function()
|
|
error('Invalid Version String: <' .. tostring(vstr) .. '>')
|
|
end
|
|
local r = {vstr:match('^(%d+)%.(%d+)%.(%d+)$')}
|
|
|
|
if #r ~= 3 then
|
|
err()
|
|
end
|
|
|
|
for i=1, 3 do
|
|
r[i] = tonumber(r[i])
|
|
end
|
|
|
|
return r
|
|
end
|
|
|
|
V.gtr = function(verA, verB)
|
|
local a, b, c = unpack(parse_version(verA))
|
|
local x, y, z = unpack(parse_version(verB))
|
|
return (a > x) or (a == x and b > y) or (a == x and b == y and c > z)
|
|
end
|
|
local map = {
|
|
['=' ] = function(A, B) return not (V.gtr(A, B) or V.gtr(B, A)) end,
|
|
['>' ] = V.gtr,
|
|
['!='] = function(A, B) return (V.gtr(A, B) or V.gtr(B, A)) end,
|
|
['<='] = function(A, B) return V.gtr(B, A) or (not V.gtr(A, B)) end,
|
|
['>='] = function(A, B) return V.gtr(A, B) or (not V.gtr(B, A)) end,
|
|
['~='] = function(A, B) return (V.gtr(A, B) or V.gtr(B, A)) end,
|
|
['<' ] = function(A, B) return V.gtr(B, A) end,
|
|
}
|
|
|
|
--~ common.Version.compare = function(mod_name, operator, need_version)
|
|
common.check_version = function(mod_name, operator, need_version)
|
|
local mod_version = (mods and mods[mod_name]) or (script and script.active_mods[mod_name])
|
|
return map[operator](mod_version, need_version)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Sane values for collision masks
|
|
-- Default: {"item-layer", "object-layer", "rail-layer", "floor-layer", "water-tile"}
|
|
--~ common.RAIL_BRIDGE_MASK = {"floor-layer", "object-layer", "consider-tile-transitions"}
|
|
common.RAIL_BRIDGE_MASK = {"object-layer", "consider-tile-transitions"}
|
|
|
|
-- "Transport Drones" removes "object-layer" from rails, so if bridges have only
|
|
-- {"object-layer"}, there collision mask will be empty, and they can be built even
|
|
-- over cliffs. So we need to add another layer to bridges ("floor-layer").
|
|
-- As of Factorio 1.1.0, rails need to have "rail-layer" in their mask. This will work
|
|
-- alright, but isn't available in earlier versions of Factorio, so we will use
|
|
-- "floor-layer" there instead.
|
|
local need = common.check_version("base", ">=", "1.1.0") and "rail-layer" or "floor-layer"
|
|
table.insert(common.RAIL_BRIDGE_MASK, need)
|
|
|
|
-- Rails use basically the same mask as rail bridges, ...
|
|
common.RAIL_MASK = util.table.deepcopy(common.RAIL_BRIDGE_MASK)
|
|
-- ... we just need to add some layers so our rails have the same mask as vanilla rails.
|
|
table.insert(common.RAIL_MASK, "item-layer")
|
|
table.insert(common.RAIL_MASK, "water-tile")
|
|
--~ log("common.RAIL_BRIDGE_MASK: " .. serpent.block(common.RAIL_BRIDGE_MASK))
|
|
--~ log("common.RAIL_MASK: " .. serpent.block(common.RAIL_MASK))
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Set maximum_wire_distance of Power-to-rail connectors
|
|
common.POWER_TO_RAIL_WIRE_DISTANCE = 4
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- List of compound entities
|
|
-- Key: name of the base entity
|
|
-- tab: name of the global table where data of these entity are stored
|
|
-- hidden: table containing the hidden entities needed by this entity
|
|
-- (Key: name under which the hidden entity will be stored in the table;
|
|
-- Value: name of the entity that should be placed)
|
|
common.compound_entities = compound_entities.get_HE_list()
|
|
|
|
-- Map the short handles of hidden entities (e.g. "pole") to real prototype types
|
|
-- (e.g. "electric-pole")
|
|
common.HE_map = compound_entities.HE_map
|
|
-- Reverse lookup
|
|
common.HE_map_reverse = compound_entities.HE_map_reverse
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- There may be trees for which we don't want to create variations. These patterns
|
|
-- are used to build a list of trees we want to ignore.
|
|
common.ignore_name_patterns = {
|
|
-- Ignore our own trees
|
|
"bio%-tree%-.+%-%d",
|
|
-- Tree prototypes created by "Robot Tree Farm" or "Tral's Robot Tree Farm"
|
|
"rtf%-.+%-%d+",
|
|
}
|
|
|
|
|
|
-- Get list of tree prototypes that we want to ignore
|
|
common.get_tree_ignore_list = function()
|
|
--~ log("Entered function get_tree_ignore_list!")
|
|
local ignore = {}
|
|
local trees = game and
|
|
game.get_filtered_entity_prototypes({{filter = "type", type = "tree"}}) or
|
|
data.raw.tree
|
|
for tree_name, tree in pairs(trees) do
|
|
--~ log("tree_name: " .. tree_name)
|
|
for p, pattern in ipairs(common.ignore_name_patterns) do
|
|
--~ log("Check for match against pattern " .. pattern)
|
|
if tree_name:match(pattern) then
|
|
--~ log("Pattern matches!")
|
|
ignore[tree_name] = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
--~ log("Tree ignore list (" .. table_size(ignore) .. "): " .. serpent.block(ignore))
|
|
return ignore
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Enable writing to log file until startup options are set, so debugging output
|
|
-- from the start of a game session can be logged. This depends on a locally
|
|
-- installed dummy mod to allow debugging output during development without
|
|
-- spamming real users.
|
|
-- If the "_debug" dummy mod is active, debugging will always be on. If you don't
|
|
-- have this dummy mod but want to turn on logging anyway, set the default value
|
|
-- to "true"!
|
|
local default = false
|
|
|
|
common.is_debug = ( (mods and mods["_debug"]) or
|
|
(script and script.active_mods["_debug"])) and
|
|
true or default
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- DEBUGGING FUNCTIONS --
|
|
------------------------------------------------------------------------------------
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Output debugging text
|
|
common.writeDebug = function(msg, tab, print_line)
|
|
local args = {}
|
|
-- Use serpent.line instead of serpent.block if this is true!
|
|
local line = print_line and
|
|
(string.lower(print_line) == "line" or string.lower(print_line) == "l") and
|
|
true or false
|
|
|
|
if common.is_debug then
|
|
if type(tab) ~= "table" then
|
|
tab = { tab }
|
|
end
|
|
local v
|
|
for k = 1, #tab do
|
|
v = tab[k]
|
|
-- NIL
|
|
if v == nil then
|
|
args[#args + 1] = "NIL"
|
|
-- TABLE
|
|
elseif type(v) == "table" then
|
|
args[#args + 1] = line and serpent.line(table.deepcopy(v)) or
|
|
serpent.block(table.deepcopy(v))
|
|
-- OTHER VALUE
|
|
else
|
|
args[#args + 1] = v
|
|
end
|
|
end
|
|
if #args == 0 then
|
|
args[1] = "nil"
|
|
end
|
|
args.n = #args
|
|
|
|
-- Print the message text to log and game
|
|
log(string.format(tostring(msg), table.unpack(args)))
|
|
|
|
if game then
|
|
game.print(string.format(tostring(msg), table.unpack(args)))
|
|
end
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Simple helper to show a single value with descriptive text
|
|
common.show = function(desc, term)
|
|
if common.is_debug then
|
|
common.writeDebug(tostring(desc) .. ": %s", type(term) == "table" and { term } or term)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Print "entityname (id)"
|
|
common.print_name_id = function(entity)
|
|
local id
|
|
local name = "unknown entity"
|
|
|
|
if entity and entity.valid then
|
|
-- Stickers don't have an index or unit_number!
|
|
id = (entity.type == "sticker" and entity.type) or
|
|
entity.unit_number or entity.type
|
|
|
|
name = entity.name
|
|
end
|
|
|
|
--~ return name .. " (" .. tostring(id) .. ")"
|
|
return string.format("%s (%s)", name, id or "nil")
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Print "entityname"
|
|
common.print_name = function(entity)
|
|
return entity and entity.valid and entity.name or ""
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Throw an error if a wrong argument has been passed to a function
|
|
common.arg_err = function(arg, arg_type)
|
|
error(string.format(
|
|
"Wrong argument! %s is not %s!",
|
|
(arg or "nil"), (arg_type and "a valid " .. arg_type or "valid")
|
|
)
|
|
)
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Rudimentary check of the arguments passed to a function
|
|
common.check_args = function(arg, arg_type, desc)
|
|
if not (arg and type(arg) == arg_type) then
|
|
common.arg_err(arg or "nil", desc or arg_type or "nil")
|
|
end
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- MOD SPECIFIC --
|
|
------------------------------------------------------------------------------------
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Are tiles from Alien Biomes available? (Returns true or false)
|
|
common.AB_tiles = function()
|
|
|
|
local ret = false
|
|
|
|
if game then
|
|
local AB = game.item_prototypes["fertilizer"].place_as_tile_result.result.name
|
|
-- In data stage, place_as_tile is only changed to Alien Biomes tiles if
|
|
-- both "vegetation-green-grass-1" and "vegetation-green-grass-3" exist. Therefore,
|
|
-- we only need to check for one tile in the control stage.
|
|
ret = (AB == "vegetation-green-grass-3") and true or false
|
|
else
|
|
ret = data.raw.tile["vegetation-green-grass-1"] and
|
|
data.raw.tile["vegetation-green-grass-3"] and true or false
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function for removing individual entities
|
|
common.remove_entity = function(entity)
|
|
if entity and entity.valid then
|
|
--~ entity.destroy()
|
|
entity.destroy{raise_destroy = true}
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function for removing invalid prototypes from list of compound entities
|
|
common.rebuild_compound_entity_list = function()
|
|
local f_name = "rebuild_compound_entity_list"
|
|
common.writeDebug("Entered function %s()", {f_name})
|
|
|
|
local ret = {}
|
|
local h_type
|
|
|
|
for c_name, c_data in pairs(common.compound_entities) do
|
|
common.show("base_name", c_name)
|
|
common.show("data", c_data)
|
|
-- Is the base entity in the game?
|
|
if c_data.base and c_data.base.name and game.entity_prototypes[c_data.base.name] then
|
|
-- Make a copy of the compound-entity data
|
|
common.writeDebug("%s exists -- copying data", {c_name})
|
|
ret[c_name] = util.table.deepcopy(c_data)
|
|
|
|
-- Check hidden entities
|
|
for h_key, h_data in pairs(ret[c_name].hidden) do
|
|
--~ h_type = common.HE_map[h_key]
|
|
common.writeDebug("h_key: %s\th_data: %s", {h_key, h_data})
|
|
-- Remove hidden entity if it doesn't exist
|
|
if not game.entity_prototypes[h_data.name] then
|
|
common.writeDebug("Removing %s (%s) from list of hidden entities!", {h_data.name, h_key})
|
|
ret[c_name].hidden[h_key] = nil
|
|
end
|
|
end
|
|
|
|
-- Clean table
|
|
else
|
|
local tab = c_data.tab
|
|
if tab then
|
|
-- Remove main table from global
|
|
common.writeDebug("Removing %s (%s obsolete entries)", {tab, #tab})
|
|
global[tab] = nil
|
|
end
|
|
|
|
-- If this compound entity requires additional tables in global, initialize
|
|
-- them now!
|
|
local related_tables = c_data.add_global_tables
|
|
if related_tables then
|
|
for t, tab in ipairs(related_tables or {}) do
|
|
common.writeDebug("Removing global[%s] (%s values)", {tab, table_size(global[tab])})
|
|
global[tab] = nil
|
|
end
|
|
end
|
|
|
|
-- If this compound entity requires additional values in global, remove them!
|
|
local related_vars = c_data.add_global_values
|
|
if related_vars then
|
|
for var_name, value in pairs(related_vars or {}) do
|
|
common.writeDebug("Removing global[%s] (was: %s)", {var_name, global[var_name]})
|
|
global[var_name] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
common.show("ret", ret)
|
|
return ret
|
|
end
|
|
------------------------------------------------------------------------------------
|
|
-- Function to add all optional values for a compound entity to the table entry.
|
|
common.add_optional_data = function(base)
|
|
local f_name = "add_optional_data"
|
|
common.writeDebug("Entered function %s(%s)", {f_name, common.print_name_id(base)})
|
|
if not (base and base.valid and global.compound_entities[base.name]) then
|
|
common.arg_err(base, "base of a compound entity")
|
|
end
|
|
|
|
-- Add optional values to global table
|
|
local data = global.compound_entities[base.name]
|
|
common.show("data", data)
|
|
local tab = data.tab
|
|
common.show("tab", tab)
|
|
common.show("global[tab]", global[tab] or "nil")
|
|
|
|
local entry = global[tab][base.unit_number]
|
|
|
|
for k, v in pairs(data.optional or {}) do
|
|
if entry[k] then
|
|
common.writeDebug("%s already exists: %s", {k, entry[k]})
|
|
else
|
|
entry[k] = v
|
|
common.writeDebug("Added data to %s: %s = %s", {common.print_name_id(base), k, v})
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function for removing all parts of invalid compound entities
|
|
common.clean_global_compounds_table = function(entity_name)
|
|
local f_name = "clean_table"
|
|
common.writeDebug("Entered function %s(%s)", {f_name, entity_name or "nil"})
|
|
common.writeDebug("Entries in common.compound_entities[%s]: %s", {entity_name, table_size(global.compound_entities[entity_name])})
|
|
|
|
--~ local entity_table = global[common.compound_entities[entity_name].tab]
|
|
--~ local hidden_entities = common.compound_entities[entity_name].hidden
|
|
local entity_table = global.compound_entities[entity_name]
|
|
common.show("entity_table", entity_table and entity_table.tab)
|
|
entity_table = entity_table and entity_table.tab and global[entity_table.tab]
|
|
common.writeDebug("entity_table: %s", {entity_table}, "line")
|
|
local hidden_entities = global.compound_entities[entity_name].hidden
|
|
common.show("hidden_entities", hidden_entities)
|
|
local removed = 0
|
|
-- Scan the whole table
|
|
for c, compound in pairs(entity_table) do
|
|
common.writeDebug ("c: %s\tcompound: %s", {c, compound})
|
|
-- No or invalid base entity!
|
|
if not (compound.base and compound.base.valid) then
|
|
common.writeDebug("%s (%s) has no valid base entity -- removing entry!", {entity_name, c})
|
|
|
|
for h_name, h_entity in pairs(hidden_entities) do
|
|
common.writeDebug("Removing %s (%s)", {h_name, h_entity.name})
|
|
common.remove_entity(compound[h_name])
|
|
end
|
|
entity_table[c] = nil
|
|
removed = removed + 1
|
|
common.writeDebug("Removed %s %s", {entity_name, c})
|
|
end
|
|
end
|
|
common.show("Removed entities", removed)
|
|
common.show("Pruned list size", table_size(entity_table))
|
|
--~ common.show("Pruned list", entity_table)
|
|
return removed
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function to resore missing parts of compound entities
|
|
common.restore_missing_entities = function(entity_name)
|
|
local f_name = "restore_missing_entities"
|
|
common.writeDebug("Entered function %s(%s)", {f_name, entity_name or "nil"})
|
|
--~ common.writeDebug("global.compound_entities[%s]: %s", {entity_name, global.compound_entities[entity_name]})
|
|
common.writeDebug("global.compound_entities[%s]: %s entries", {entity_name, table_size(global.compound_entities[entity_name])})
|
|
|
|
local check = global.compound_entities[entity_name]
|
|
local entity_table = check and global[check.tab] or {}
|
|
local hidden_entities = check and check.hidden or {}
|
|
|
|
local checked = 0
|
|
local restored = 0
|
|
-- Scan the whole table
|
|
for c, compound in pairs(entity_table) do
|
|
--~ common.writeDebug("c: %s\tcompound: %s", {c, compound})
|
|
-- Base entity is valid!
|
|
if (compound.base and compound.base.valid) then
|
|
common.writeDebug("%s is valid -- checking hidden entities!", {common.print_name_id(compound.base)})
|
|
for h_name, h_entity in pairs(hidden_entities) do
|
|
--~ common.writeDebug("h_name: %s\th_entity: %s", {h_name, h_entity})
|
|
-- Hidden entity is missing
|
|
if compound[h_name] and compound[h_name].valid then
|
|
common.writeDebug("%s: OK", {h_name})
|
|
else
|
|
common.writeDebug("%s: MISSING!", {h_name})
|
|
common.create_entities(entity_table, compound.base, {[h_name] = h_entity.name})
|
|
restored = restored + 1
|
|
common.writeDebug("Created %s (%s) for %s",
|
|
{h_name, h_entity.name, common.print_name_id(compound.base)})
|
|
end
|
|
end
|
|
checked = checked + 1
|
|
--~ common.writeDebug("Restored %s %s", {entity_name, c})
|
|
end
|
|
end
|
|
common.writeDebug("Checked %s compound entities", {checked})
|
|
common.writeDebug("Restored %s entities", {restored})
|
|
--~ common.show("Fixed list", entity_table)
|
|
return {checked = checked, restored = restored}
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function to find all unregistered compound entities of a particular type
|
|
common.register_in_compound_entity_tab = function(compound_name)
|
|
local f_name = "register_in_compound_entity_tab"
|
|
common.writeDebug("Entered function %s(%s)", {f_name, compound_name})
|
|
|
|
local cnt = 0
|
|
local h_cnt = 0
|
|
local data = global.compound_entities[compound_name]
|
|
if not data then
|
|
common.arg_err(compound_name, "name of a compound entity")
|
|
end
|
|
|
|
local g_tab = global[data.tab]
|
|
local found, h_found ,created
|
|
|
|
-- Scan all surfaces
|
|
for s, surface in pairs(game.surfaces) do
|
|
-- Check the bases of all compound entities on the surface
|
|
found = surface.find_entities_filtered({name = compound_name})
|
|
for b, base in ipairs(found) do
|
|
-- Base entity isn't registered yet!
|
|
if not g_tab[base.unit_number] then
|
|
common.writeDebug("Found unregistered entity: %s!", {common.print_name_id(base)})
|
|
-- Create an entry in the global table
|
|
g_tab[base.unit_number] = {base = base}
|
|
-- Add optional data to the table, if there are any
|
|
common.add_optional_data(base)
|
|
|
|
|
|
-- Check if it already has any hidden entities
|
|
for h_name, h_data in pairs(data.hidden) do
|
|
h_found = surface.find_entities_filtered({
|
|
name = h_data.name,
|
|
type = h_data.type,
|
|
position = common.offset_position(base.position, h_data.base_offset),
|
|
})
|
|
|
|
-- Check for multiple hidden entities of the same type in the same position!
|
|
if #h_found > 1 then
|
|
local cnt = 0
|
|
for duplicate = 2, #h_found do
|
|
h_found[duplicate].destroy({raise_destroy = true})
|
|
cnt = cnt + 1
|
|
end
|
|
common.writeDebug("Removed %s duplicate entities (%s)!", {cnt, h_data.name})
|
|
end
|
|
|
|
-- There still is one hidden entity left. Add it to the table!
|
|
if next(h_found) then
|
|
common.writeDebug("Found %s -- adding it to the table.", {common.print_name_id(base)})
|
|
g_tab[base.unit_number][h_name] = h_found[1]
|
|
|
|
-- Create hidden entity! This will automatically add it to the table.
|
|
else
|
|
created = common.create_entities(g_tab, base, {[h_name] = h_data})
|
|
common.writeDebug("Created hidden %s: %s",
|
|
{h_name, created and common.print_name_id(created) or "nil"})
|
|
h_cnt = h_cnt + 1
|
|
end
|
|
end
|
|
cnt = cnt + 1
|
|
end
|
|
end
|
|
end
|
|
common.writeDebug("Registered %s compound entities and created %s hidden entities", {cnt, h_cnt})
|
|
return cnt
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function to find all unregistered compound entities
|
|
common.find_unregistered_entities = function()
|
|
local f_name = "find_unregistered_entities"
|
|
common.writeDebug("Entered function %s()", {f_name})
|
|
|
|
local cnt = 0
|
|
for compound_entity, c in pairs(global.compound_entities) do
|
|
cnt = cnt + common.register_in_compound_entity_tab(compound_entity)
|
|
end
|
|
--~ common.writeDebug("Registered %s compound entities", {cnt})
|
|
common.writeDebug("Registered %s compound entities.", {cnt})
|
|
return cnt
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Function to normalize positions
|
|
common.normalize_position = function(pos)
|
|
if pos and type(pos) == "table" and table_size(pos) == 2 then
|
|
local x = pos.x or pos[1]
|
|
local y = pos.y or pos[2]
|
|
if x and y and type(x) == "number" and type(y) == "number" then
|
|
return { x = x, y = y }
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Calculate the offset position of a hidden entity
|
|
common.offset_position = function(base_pos, offset)
|
|
common.check_args(base_pos, "table", "position")
|
|
offset = offset or {x = 0, y = 0}
|
|
common.check_args(offset, "table", "position")
|
|
|
|
base_pos = common.normalize_position(base_pos)
|
|
offset = common.normalize_position(offset)
|
|
|
|
common.show("base_pos", base_pos)
|
|
common.show("offset", offset)
|
|
common.show("new", {x = base_pos.x + offset.x, y = base_pos.y + offset.y})
|
|
return {x = base_pos.x + offset.x, y = base_pos.y + offset.y}
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Check if argument is a valid surface
|
|
common.is_surface = function(surface)
|
|
local t = type(surface)
|
|
surface = (t == "number" or t == "string" and game.surfaces[surface]) or
|
|
(t == "table" and surface.object_name and
|
|
surface.object_name == "LuaSurface" and surface)
|
|
return surface
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Make hidden entities unminable and indestructible
|
|
local function make_unminable(entities)
|
|
for e, entity in ipairs(entities or {}) do
|
|
if entity.valid then
|
|
entity.minable = false
|
|
entity.destructible = false
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------
|
|
-- Create and register hidden entities
|
|
--~ common.create_entities = function(g_table, base_entity, hidden_entity_names, position, ...)
|
|
common.create_entities = function(g_table, base_entity, hidden_entities)
|
|
local f_name = "create_entities"
|
|
common.writeDebug("Entered function %s(%s, %s, %s)",
|
|
{f_name, "g_table", base_entity, hidden_entities})
|
|
common.show("#g_table", g_table and table_size(g_table))
|
|
--~ common.show("hidden_entities", hidden_entities)
|
|
|
|
common.check_args(g_table, "table")
|
|
common.check_args(base_entity, "table")
|
|
|
|
if not base_entity.valid then
|
|
common.arg_err(base_entity, "base entity")
|
|
-- A table is required, but it may be empty! (This is needed for the
|
|
-- bio gardens, which only have a hidden pole if the "Easy Gardens"
|
|
-- setting is enabled.)
|
|
elseif not (hidden_entities and type(hidden_entities) == "table") then
|
|
common.arg_err(hidden_entities, "array of hidden-entity names")
|
|
end
|
|
local base_pos = common.normalize_position(base_entity.position) or
|
|
common.arg_err(position or "nil", "position")
|
|
|
|
local entity, offset, pos
|
|
|
|
-- Initialize entry in global table
|
|
g_table[base_entity.unit_number] = g_table[base_entity.unit_number] or {}
|
|
g_table[base_entity.unit_number].base = base_entity
|
|
|
|
-- Create hidden entities
|
|
local data
|
|
for key, tab in pairs(hidden_entities) do
|
|
common.writeDebug("key: %s\tname: %s", {key, tab})
|
|
--~ data = common.compound_entities[base_entity.name].hidden[key]
|
|
data = global.compound_entities[base_entity.name].hidden[key]
|
|
--~ common.show("common.compound_entities[base_entity.name].hidden",
|
|
--~ common.compound_entities[base_entity.name].hidden)
|
|
common.show("data", data)
|
|
entity = base_entity.surface.create_entity({
|
|
name = data.name,
|
|
type = data.type,
|
|
position = common.offset_position(base_pos, data.base_offset),
|
|
force = base_entity.force,
|
|
})
|
|
-- Raise the event manually, so we can pass on extra data!
|
|
script.raise_event(defines.events.script_raised_built, {
|
|
entity = entity,
|
|
base_entity = base_entity
|
|
})
|
|
|
|
-- Make hidden entity unminable/undestructible
|
|
make_unminable({entity})
|
|
|
|
-- Add hidden entity to global table
|
|
g_table[base_entity.unit_number][key] = entity
|
|
end
|
|
|
|
-- Add optional values to global table
|
|
--~ local optional = global.compound_entities[base_entity.name].optional
|
|
--~ for k, v in pairs(optional or {}) do
|
|
--~ g_table[base_entity.unit_number][k] = v
|
|
--~ end
|
|
common.add_optional_data(base_entity)
|
|
common.writeDebug("g_table[%s]: %s", {base_entity.unit_number, g_table[base_entity.unit_number]})
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------
|
|
-- Make a list of the pole types that Bio gardens may connect to
|
|
common.get_garden_pole_connectors = function()
|
|
--~ local ret = {}
|
|
local ret
|
|
if common.get_startup_setting("BI_Easy_Bio_Gardens") then
|
|
common.writeDebug("\"Easy gardens\": Compiling list of poles they can connect to!" )
|
|
ret = {}
|
|
local poles = game.get_filtered_entity_prototypes({
|
|
{filter = "type", type = "electric-pole"},
|
|
{filter = "name", name = {
|
|
-- Poles named here will be ignored!
|
|
"bi-bio-garden-hidden-pole"
|
|
}, invert = "true", mode = "and"
|
|
}
|
|
})
|
|
for p, pole in pairs(poles) do
|
|
ret[#ret + 1] = pole.name
|
|
end
|
|
else
|
|
common.writeDebug("\"Easy gardens\": Not active -- nothing to do!" )
|
|
end
|
|
return ret
|
|
end
|
|
|
|
--------------------------------------------------------------------
|
|
-- Connect hidden poles of Bio gardens!
|
|
-- (This function may be called for hidden poles that have not been
|
|
-- added to the table yet if the pole has just been built. In this
|
|
-- case, we pass on the new pole explicitly!)
|
|
common.connect_garden_pole = function(base, new_pole)
|
|
local compound_entity = global.compound_entities["bi-bio-garden"]
|
|
--~ local pole_type = "electric-pole"
|
|
--~ local pole = global[compound_entity.tab][base.unit_number] and
|
|
--~ global[compound_entity.tab][base.unit_number][pole_type] or
|
|
--~ new_pole
|
|
local pole = global[compound_entity.tab][base.unit_number] and
|
|
global[compound_entity.tab][base.unit_number].pole or
|
|
new_pole
|
|
|
|
--~ if pole and pole.valid then
|
|
--~ local wire_reach = game.entity_prototypes[compound_entity.hidden[pole_type]] and
|
|
--~ game.entity_prototypes[compound_entity.hidden[pole_type]].max_wire_distance
|
|
if pole and pole.valid and compound_entity.hidden and
|
|
compound_entity.hidden.pole and
|
|
compound_entity.hidden.pole.name then
|
|
local wire_reach = game.entity_prototypes[compound_entity.hidden.pole.name] and
|
|
game.entity_prototypes[compound_entity.hidden.pole.name].max_wire_distance
|
|
if not wire_reach then
|
|
error("Prototype for hidden pole of Bio gardens doesn't exist!")
|
|
end
|
|
|
|
pole.disconnect_neighbour()
|
|
|
|
-- Each pole can only have 5 connections. Let's connect to other hidden
|
|
-- poles first!
|
|
local connected
|
|
local neighbours = pole.surface.find_entities_filtered({
|
|
position = pole.position,
|
|
radius = wire_reach,
|
|
type = "electric-pole",
|
|
name = compound_entity.hidden.pole.name
|
|
})
|
|
common.writeDebug("Pole %g has %s neighbours", {pole.unit_number, #neighbours - 1})
|
|
|
|
for n, neighbour in pairs(neighbours or{}) do
|
|
if pole ~= neighbour then
|
|
connected = pole.connect_neighbour(neighbour)
|
|
common.writeDebug("Connected pole %g to %s %g: %s",
|
|
{pole.unit_number, neighbour.name, neighbour.unit_number, connected})
|
|
end
|
|
end
|
|
|
|
--~ -- Connect hidden poles to other poles that may be in reach.
|
|
--~ common.garden_pole_connectors = common.garden_pole_connectors and next() or
|
|
--~ common.get_garden_pole_connectors()
|
|
--~ common.show("Poles hidden bio-garden poles may connect to", global.mod_settings.garden_pole_connectors)
|
|
|
|
-- Look for other poles around this one
|
|
neighbours = pole.surface.find_entities_filtered({
|
|
position = pole.position,
|
|
radius = wire_reach,
|
|
type = "electric-pole",
|
|
name = global.mod_settings.garden_pole_connectors,
|
|
})
|
|
common.writeDebug("Pole %g has %s neighbours", {pole.unit_number, #neighbours})
|
|
for n, neighbour in pairs(neighbours or{}) do
|
|
connected = pole.connect_neighbour(neighbour)
|
|
common.writeDebug("Connected pole %g to neighbour %s (%g): %s",
|
|
{pole.unit_number, neighbour.name, neighbour.unit_number, connected})
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------
|
|
-- Connect hidden poles of powered rails -- this is also used in
|
|
-- migration scripts, so make it a function in common.lua!
|
|
-- (This function may be called for hidden poles that have not been
|
|
-- added to the table yet if the pole has just been built. In this
|
|
-- case, we pass on the new pole explicitly!)
|
|
common.connect_power_rail = function(base, new_pole)
|
|
--~ local pole_type = "electric-pole"
|
|
|
|
local pole = global.bi_power_rail_table[base.unit_number].pole or new_pole
|
|
if pole and pole.valid then
|
|
-- Remove all copper wires from new pole
|
|
pole.disconnect_neighbour()
|
|
common.writeDebug("Removed all wires from %s %g", {pole.name, pole.unit_number})
|
|
|
|
-- Look for connecting rails at front and back of the new rail
|
|
for s, side in ipairs( {"front", "back"} ) do
|
|
common.writeDebug("Looking for rails at %s", {side})
|
|
local neighbour
|
|
-- Look in all three directions
|
|
for d, direction in ipairs( {"left", "straight", "right"} ) do
|
|
common.writeDebug("Looking for rails in %s direction", {direction})
|
|
neighbour = base.get_connected_rail{
|
|
rail_direction = defines.rail_direction[side],
|
|
rail_connection_direction = defines.rail_connection_direction[direction]
|
|
}
|
|
common.writeDebug("Rail %s of %s (%s): %s (%s)", {direction, base.name, base.unit_number, (neighbour and neighbour.name or "nil"), (neighbour and neighbour.unit_number or "nil")})
|
|
|
|
-- Only make a connection if found rail is a powered rail
|
|
-- (We'll know it's the right type if we find it in our table!)
|
|
neighbour = neighbour and neighbour.valid and global.bi_power_rail_table[neighbour.unit_number]
|
|
if neighbour and neighbour.pole and neighbour.pole.valid then
|
|
pole.connect_neighbour(neighbour.pole)
|
|
common.writeDebug("Connected poles!")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Look for Power-rail connectors
|
|
local connector = base.surface.find_entities_filtered{
|
|
position = base.position,
|
|
radius = common.POWER_TO_RAIL_WIRE_DISTANCE, -- maximum_wire_distance of Power-to-rail-connectors
|
|
name = "bi-power-to-rail-pole"
|
|
}
|
|
-- Connect to first Power-rail connector we've found
|
|
if connector and next(connector) then
|
|
pole.connect_neighbour(connector[1])
|
|
common.writeDebug("Connected " .. pole.name .. " (" .. pole.unit_number ..
|
|
") to " .. connector[1].name .. " (" .. connector[1].unit_number .. ")")
|
|
common.writeDebug("Connected %s (%g) to %s (%g)", {pole.name, pole.unit_number, connector[1].name, connector[1].unit_number})
|
|
end
|
|
common.writeDebug("Stored %s (%g) in global table", {base.name, base.unit_number})
|
|
end
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Get the value of a startup setting
|
|
common.get_startup_setting = function(setting_name)
|
|
return settings.startup[setting_name] and settings.startup[setting_name].value
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- Add the "icons" property based on the value of "icon"
|
|
------------------------------------------------------------------------------------
|
|
common.BI_add_icons = function()
|
|
for tab_name, tab in pairs(data.raw) do
|
|
--~ common.writeDebug("Checking data.raw[%s]", {tab_name})
|
|
for proto_type_name, proto_type in pairs(data.raw[tab_name] or {}) do
|
|
--~ common.show("proto_type.BI_add_icon", proto_type.BI_add_icon or "nil" )
|
|
|
|
if proto_type.BI_add_icon then
|
|
proto_type.icons = {
|
|
{
|
|
icon = proto_type.icon,
|
|
icon_size = proto_type.icon_size,
|
|
icon_mipmaps = proto_type.icon_mipmaps
|
|
}
|
|
}
|
|
proto_type.BI_add_icon = nil
|
|
common.writeDebug("Added \"icons\" property to data.raw[\"%s\"][\"%s\"]: %s",
|
|
{tab_name, proto_type_name, proto_type.icons}, "line")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------
|
|
-- END OF FILE
|
|
------------------------------------------------------------------------------------
|
|
return common
|
|
end
|