476 lines
19 KiB
Lua
476 lines
19 KiB
Lua
local BioInd = require("__" .. script.mod_name .. "__.common")(script.mod_name)
|
|
local settings_changed = require("settings_changed")
|
|
|
|
if BioInd.get_startup_setting("BI_Enable_gvv_support") then
|
|
BioInd.writeDebug("Activating support for gvv!")
|
|
require("__gvv__/gvv")()
|
|
end
|
|
|
|
|
|
-- We can't just check if Alien Biomes is active, because we need to know if
|
|
-- the tiles we need from it exist in the game! To check this, we must call
|
|
-- game.get_tile_prototypes(), but this will crash in script.on_load(). So,
|
|
-- let's just declare the variable here and fill it later.
|
|
local AlienBiomes
|
|
|
|
--~ local Event = require('__stdlib__/stdlib/event/event').set_protected_mode(true)
|
|
local Event = require('__stdlib__/stdlib/event/event').set_protected_mode(false)
|
|
require ("util")
|
|
require ("libs/util_ext")
|
|
require ("control_tree")
|
|
|
|
-- Generate a look-up table with the names of our trees
|
|
local function get_bi_trees()
|
|
local list = {}
|
|
|
|
local trees = game.get_filtered_entity_prototypes({{filter = "type", type = "tree"}})
|
|
for tree_name, tree in pairs(trees) do
|
|
if tree_name:match("^bio%-tree%-.+%-%d$") then
|
|
BioInd.show("Found matching tree", tree_name)
|
|
list[tree_name] = true
|
|
end
|
|
end
|
|
|
|
return list
|
|
end
|
|
|
|
|
|
-- Generate a look-up table with the names of tiles that can't be changed by fertilizer
|
|
local tile_patterns = {
|
|
".*concrete.*",
|
|
".*stone%-path.*",
|
|
"^bi%-solar%-mat$",
|
|
"^bi%-wood%-floor$",
|
|
}
|
|
local function get_fixed_tiles()
|
|
local list = {}
|
|
|
|
for tile_name, tile in pairs(game.tile_prototypes) do
|
|
for p, pattern in ipairs(tile_patterns) do
|
|
if tile_name:match(pattern) then
|
|
BioInd.show("Found matching tile", tile_name)
|
|
-- If a tile is minable and fertilizer is used on it, we must deduct the mined
|
|
-- tiles from the player/robot again!
|
|
list[tile_name] = tile.mineable_properties.products or true
|
|
end
|
|
end
|
|
end
|
|
BioInd.show("Forbidden tiles", list)
|
|
return list
|
|
end
|
|
--------------------------------------------------------------------
|
|
local function init()
|
|
BioInd.writeDebug("Entered init!")
|
|
if BioInd.is_debug then
|
|
game.check_prototype_translations()
|
|
end
|
|
|
|
global = global or {}
|
|
|
|
--------------------------------------------------------------------
|
|
-- Settings
|
|
--------------------------------------------------------------------
|
|
-- Global table for storing the last state of certain mod settings
|
|
global.mod_settings = global.mod_settings or {}
|
|
if BioInd.get_startup_setting("BI_Easy_Bio_Gardens") then
|
|
global.mod_settings.garden_pole_connectors = BioInd.get_garden_pole_connectors()
|
|
else
|
|
global.mod_settings.garden_pole_connectors = nil
|
|
end
|
|
|
|
-- Global table for storing the data of compound entities. They may change between
|
|
-- saves (e.g. Bio gardens only need hidden poles when the "Easy gardens" setting
|
|
-- is active).
|
|
--~ global.compound_entities = global.compound_entities or BioInd.compound_entities
|
|
global.compound_entities = BioInd.rebuild_compound_entity_list()
|
|
|
|
|
|
--------------------------------------------------------------------
|
|
-- Tree stuff!
|
|
--------------------------------------------------------------------
|
|
global.bi = global.bi or {}
|
|
global.bi.tree_growing = global.bi.tree_growing or {}
|
|
for i = 1, 4 do
|
|
global.bi["tree_growing_stage_" .. i] = global.bi["tree_growing_stage_" .. i] or {}
|
|
end
|
|
|
|
-- List of tree prototypes created by BI
|
|
global.bi.trees = get_bi_trees()
|
|
|
|
-- List of tile prototypes that can't be fertilized
|
|
global.bi.barren_tiles = get_fixed_tiles()
|
|
|
|
--------------------------------------------------------------------
|
|
-- Compound entities
|
|
--------------------------------------------------------------------
|
|
-- Check what global tables we need for compound entities
|
|
local compound_entity_tables = {}
|
|
--~ for compound, compound_data in pairs(BioInd.compound_entities) do
|
|
for compound, compound_data in pairs(global.compound_entities) do
|
|
-- BioInd.compound_entities contains entries that point to the same table
|
|
-- (e.g. straight/curved rails, or overlay entities), so we just overwrite
|
|
-- them to remove duplicates
|
|
compound_entity_tables[compound_data.tab] = compound
|
|
end
|
|
BioInd.show("Need to check these tables in global", compound_entity_tables)
|
|
|
|
-- Prepare global tables storing data of compound entities
|
|
local result
|
|
for compound_tab, compound_name in pairs(compound_entity_tables) do
|
|
-- Init table
|
|
global[compound_tab] = global[compound_tab] or {}
|
|
BioInd.writeDebug("Initialized global[%s] (%s entities stored)",
|
|
{compound_name, table_size(global[compound_tab])})
|
|
-- If this compound entity requires additional tables in global, initialize
|
|
-- them now!
|
|
local related_tables = global.compound_entities[compound_name].add_global_tables
|
|
if related_tables then
|
|
for t, tab in ipairs(related_tables or {}) do
|
|
global[tab] = global[tab] or {}
|
|
BioInd.writeDebug("Initialized global[%s] (%s values)", {tab, table_size(global[tab])})
|
|
end
|
|
end
|
|
-- If this compound entity requires additional values in global, initialize
|
|
-- them now!
|
|
local related_vars = global.compound_entities[compound_name].add_global_values
|
|
if related_vars then
|
|
for var_name, value in pairs(related_vars or {}) do
|
|
global[var_name] = global[var_name] or value
|
|
BioInd.writeDebug("Set global[%s] to %s", {var_name, global[var_name]})
|
|
end
|
|
end
|
|
|
|
-- Clean up global tables (We can skip this for empty tables!)
|
|
if next(global[compound_tab]) then
|
|
-- Remove invalid entities
|
|
result = BioInd.clean_global_compounds_table(compound_name)
|
|
BioInd.writeDebug("Removed %s invalid entries from global[%s]!",
|
|
{result, compound_tab})
|
|
-- Restore missing hidden entities
|
|
result = BioInd.restore_missing_entities(compound_name)
|
|
BioInd.writeDebug("Checked %s compound entities and restored %s missing hidden entries for global[\"%s\"]!",
|
|
{result.checked, result.restored, compound_tab})
|
|
end
|
|
end
|
|
-- Search all surfaces for unregistered compound entities
|
|
result = BioInd.find_unregistered_entities()
|
|
BioInd.writeDebug("Registered %s forgotten entities!", {result})
|
|
--------------------------------------------------------------------
|
|
-- Compatibility with other mods
|
|
--------------------------------------------------------------------
|
|
global.compatible = global.compatible or {}
|
|
global.compatible.AlienBiomes = BioInd.AB_tiles()
|
|
|
|
|
|
-- enable researched recipes
|
|
for i, force in pairs(game.forces) do
|
|
BioInd.writeDebug("Reset technology effects for force %s.", {force.name})
|
|
force.reset_technology_effects()
|
|
end
|
|
end
|
|
--------------------------------------------------------------------
|
|
local function On_Load()
|
|
log("Entered On_Load!")
|
|
end
|
|
--------------------------------------------------------------------
|
|
local function On_Config_Change(ConfigurationChangedData)
|
|
BioInd.writeDebug("On Configuration changed: %s", {ConfigurationChangedData})
|
|
-- Re-initialize global tables etc.
|
|
init()
|
|
|
|
-- We've made a list of the tree prototypes that are currently available. Now we
|
|
-- need to make sure that the lists of growing trees don't contain removed tree
|
|
-- prototypes! (This fix is needed when "Alien Biomes" has been removed; it should
|
|
-- work with all other mods that create trees as well.)
|
|
local trees = global.bi.trees
|
|
local tab
|
|
-- Growing stages
|
|
for i = 1, 4 do
|
|
tab = global.bi["tree_growing_stage_" .. i]
|
|
BioInd.writeDebug("Number of trees in growing stage %s: %s", {i, table_size(tab)})
|
|
for t, tree in pairs(tab) do
|
|
if not trees[tree.tree_name] then
|
|
BioInd.writeDebug("Removing invalid tree %s (%s)", {t, tree.tree_name})
|
|
tab[t] = nil
|
|
end
|
|
end
|
|
-- Removing trees will create gaps in the table, but we need it as a continuous
|
|
-- list. (Trees need to be sorted by growing time, and we always look at the
|
|
-- tree with index 1 when checking if a tree has completed the growing stage, so
|
|
-- lets sort the table after all invalid trees have been removed!)
|
|
table.sort(tab, function(a, b) return a.time < b.time end)
|
|
BioInd.show("Final tree list", tab)
|
|
end
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------
|
|
--- Used for some compatibility with Angels Mods
|
|
Event.register(defines.events.on_player_joined_game, function(event)
|
|
local player = game.players[event.player_index]
|
|
local force = player.force
|
|
local techs = force.technologies
|
|
|
|
--~ if settings.startup["angels-use-angels-barreling"] and
|
|
--~ settings.startup["angels-use-angels-barreling"].value then
|
|
if BioInd.get_startup_setting("angels-use-angels-barreling") then
|
|
techs['fluid-handling'].researched = false
|
|
techs['bi-tech-fertilizer'].reload()
|
|
local _t = techs['angels-fluid-barreling'].researched
|
|
techs['angels-fluid-barreling'].researched = false
|
|
techs['angels-fluid-barreling'].researched = _t
|
|
end
|
|
end)
|
|
--------------------------------------------------------------------
|
|
local function On_Built(event)
|
|
local entity = event.created_entity or event.entity
|
|
if not (entity and entity.valid) then
|
|
BioInd.arg_err(entity or "nil", "entity")
|
|
end
|
|
|
|
local surface = BioInd.is_surface(entity.surface) or
|
|
BioInd.arg_err(entity.surface or "nil", "surface")
|
|
local position = BioInd.normalize_position(entity.position) or
|
|
BioInd.arg_err(entity.position or "nil", "position")
|
|
local force = entity.force
|
|
|
|
BioInd.writeDebug("Entered function On_Built with these data: " .. serpent.block(event))
|
|
--~ BioInd.writeDebug("Entity name: %s", {BioInd.print_name_id(entity)})
|
|
|
|
-- We can ignore ghosts -- if ghosts are revived, there will be
|
|
-- another event that triggers where actual entities are placed!
|
|
if entity.name == "entity-ghost" then
|
|
BioInd.writeDebug("Built ghost of %s -- return!", {entity.ghost_name})
|
|
return
|
|
end
|
|
|
|
BioInd.show("Built entity", BioInd.print_name_id(entity))
|
|
|
|
local base_entry = global.compound_entities[entity.name]
|
|
local base = base_entry and entity
|
|
|
|
-- We've found a compound entity!
|
|
if base then
|
|
-- Make sure we work with a copy of the original table! We don't want to
|
|
-- remove anything from it for real.
|
|
local hidden_entities = util.table.deepcopy(base_entry.hidden)
|
|
|
|
BioInd.writeDebug("%s (%s) is a compound entity. Need to create %s", {base.name, base.unit_number, hidden_entities})
|
|
BioInd.show("hidden_entities", hidden_entities)
|
|
--~ local new_base, new_base_name, optional
|
|
local new_base
|
|
local new_base_name = base_entry.new_base_name
|
|
-- If the base entity is only an overlay, we'll replace it with the real base
|
|
-- entity and raise an event. The hidden entities will be created in the second
|
|
-- pass (triggered by building the final entity).
|
|
BioInd.show("base_entry.new_base_name", base_entry.new_base_name)
|
|
BioInd.show("base_entry.new_base_name == base.name", base_entry.new_base_name == base.name)
|
|
BioInd.show("base_entry.optional", base_entry.optional)
|
|
--~ if new_base_name then
|
|
if new_base_name and new_base_name ~= base.name then
|
|
new_base = surface.create_entity({
|
|
name = new_base_name,
|
|
position = base.position,
|
|
direction = base.direction,
|
|
force = base.force,
|
|
raise_built = true
|
|
})
|
|
new_base.health = base.health
|
|
BioInd.show("Created final base entity", BioInd.print_name_id(new_base))
|
|
|
|
base.destroy({raise_destroy = true})
|
|
base = new_base
|
|
BioInd.writeDebug("Destroyed old base entity!")
|
|
|
|
-- Second pass: We've placed the final base entity now, so we can create the
|
|
-- the hidden entities!
|
|
else
|
|
BioInd.writeDebug("Second pass -- creating hidden entities!")
|
|
BioInd.show("base_entry", base_entry)
|
|
|
|
BioInd.writeDebug("global[%s]: %s", {base_entry.tab, global[base_entry.tab]})
|
|
BioInd.show("base.name", base.name)
|
|
BioInd.show("base.unit_number", base.unit_number)
|
|
BioInd.show("hidden_entities", hidden_entities)
|
|
|
|
-- We must call create_entities even if there are no hidden entities (e.g. if
|
|
-- the "Easy Gardens" setting is disabled and no hidden poles are required)
|
|
-- because the compound entity gets registered there!
|
|
BioInd.create_entities(global[base_entry.tab], base, hidden_entities)
|
|
BioInd.writeDebug("Stored %s in table: %s",
|
|
{BioInd.print_name_id(base), global[base_entry.tab][base.unit_number]})
|
|
end
|
|
|
|
-- The built entity isn't one of our compound entities.
|
|
else
|
|
BioInd.writeDebug("%s is not a compound entity!", {BioInd.print_name_id(entity)})
|
|
|
|
-- If one of our hidden entities has been built, we'll have raised this event
|
|
-- ourselves and have passed on the base entity.
|
|
base = event.base_entity
|
|
|
|
local entities = BioInd.compound_entities
|
|
BioInd.show("Base entity", BioInd.print_name_id(base))
|
|
|
|
-- The hidden entities are listed with a common handle ("pole", "panel" etc.). We
|
|
-- can get it from the reverse-lookup list via the entity type!
|
|
local h_key = BioInd.HE_map_reverse[entity.type]
|
|
BioInd.show("h_key", h_key or "nil")
|
|
|
|
-- Electric poles -- we need to take care that they don't hook up to hidden poles!
|
|
if entity.type == "electric-pole" then
|
|
local pole = entity
|
|
-- Make sure hidden poles of the Bio gardens are connected correctly!
|
|
if pole.name == entities["bi-bio-garden"].hidden[h_key].name and base then
|
|
BioInd.writeDebug("Bio garden!")
|
|
BioInd.connect_garden_pole(base, pole)
|
|
BioInd.writeDebug("Connected %s (%s)", {pole.name, pole.unit_number or "nil"})
|
|
end
|
|
|
|
-- A seedling has been planted
|
|
elseif entity.name == "seedling" then
|
|
seed_planted(event)
|
|
BioInd.writeDebug("Planted seedling!")
|
|
|
|
-- Something else has been built
|
|
else
|
|
BioInd.writeDebug("Nothing to do for %s!", {entity.name})
|
|
end
|
|
end
|
|
BioInd.writeDebug("End of function On_Built")
|
|
end
|
|
|
|
|
|
local function remove_plants(entity_position, tabl)
|
|
BioInd.writeDebug("Entered function remove_plants(%s, %s)", {entity_position or "nil", tabl or "nil"})
|
|
local e = BioInd.normalize_position(entity_position)
|
|
if not e then
|
|
BioInd.arg_err(entity_position or "nil", "position")
|
|
end
|
|
BioInd.check_args(tabl, "table")
|
|
|
|
local pos
|
|
|
|
for k, v in pairs(tabl or {}) do
|
|
pos = BioInd.normalize_position(v.position)
|
|
if pos and pos.x == e.x and pos.y == e.y then
|
|
BioInd.writeDebug("Removing entry %s from table: %s", {k, v})
|
|
table.remove(tabl, k)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------
|
|
local function On_Pre_Remove(event)
|
|
BioInd.writeDebug("Entered function On_Pre_Remove(%s)", {event})
|
|
local entity = event.entity
|
|
|
|
if not (entity and entity.valid) then
|
|
BioInd.writeDebug("No valid entity -- nothing to do!")
|
|
return
|
|
end
|
|
|
|
--~ local compound_entity = BioInd.compound_entities[entity.name]
|
|
local compound_entity = global.compound_entities[entity.name]
|
|
local base_entry = compound_entity and global[compound_entity.tab][entity.unit_number]
|
|
BioInd.show("entity.name", entity.name)
|
|
BioInd.show("entity.unit_number", entity.unit_number)
|
|
|
|
BioInd.show("compound_entity", compound_entity)
|
|
BioInd.show("base_entry", base_entry)
|
|
BioInd.show("compound_entity.tab", compound_entity and compound_entity.tab or "nil")
|
|
BioInd.writeDebug("global[%s]: %s", {compound_entity and compound_entity.tab or "nil", compound_entity and global[compound_entity.tab] or "nil"})
|
|
|
|
-- Found a compound entity from our list!
|
|
if base_entry then
|
|
BioInd.writeDebug("Found compound entity %s",
|
|
{base_entry.base and BioInd.print_name_id(base_entry.base)})
|
|
|
|
-- Default: Remove all hidden entities!
|
|
for hidden, h_name in pairs(compound_entity.hidden or {}) do
|
|
BioInd.show("hidden", hidden)
|
|
|
|
--~ BioInd.writeDebug("Removing hidden entity %s %s", {base_entry[hidden] and base_entry[hidden].valid and base_entry[hidden].name or "nil", base_entry[hidden] and base_entry[hidden].valid and base_entry[hidden].unit_number or "nil"})
|
|
BioInd.writeDebug("Removing hidden entity %s", {BioInd.print_name_id(base_entry[hidden])})
|
|
BioInd.remove_entity(base_entry[hidden])
|
|
base_entry[hidden] = nil
|
|
end
|
|
global[compound_entity.tab][entity.unit_number] = nil
|
|
|
|
-- Removed seedling
|
|
elseif entity.name == "seedling" then
|
|
BioInd.writeDebug("Seedling has been removed")
|
|
remove_plants(entity.position, global.bi.tree_growing)
|
|
|
|
-- Removed tree
|
|
elseif entity.type == "tree" and global.bi.trees[entity.name] then
|
|
BioInd.show("Removed tree", entity.name)
|
|
|
|
local tree_stage = entity.name:match('^.+%-(%d)$')
|
|
BioInd.writeDebug("Removed tree %s (grow stage: %s)", {entity.name, tree_stage or nil})
|
|
if tree_stage then
|
|
remove_plants(entity.position, global.bi["tree_growing_stage_" .. tree_stage])
|
|
else
|
|
error(string.format("Tree %s does not have a valid tree_stage: %s", entity.name, tree_stage or "nil"))
|
|
end
|
|
|
|
-- Removed something else
|
|
else
|
|
BioInd.writeDebug("%s has been removed -- nothing to do!", {entity.name})
|
|
end
|
|
end
|
|
--------------------------------------------------------------------
|
|
Event.register(Event.core_events.configuration_changed, On_Config_Change)
|
|
Event.register(Event.core_events.init, init)
|
|
Event.register(Event.core_events.load, On_Load)
|
|
|
|
|
|
Event.build_events = {
|
|
defines.events.on_built_entity,
|
|
defines.events.on_robot_built_entity,
|
|
defines.events.script_raised_built,
|
|
defines.events.script_raised_revive
|
|
}
|
|
Event.pre_remove_events = {
|
|
defines.events.on_pre_player_mined_item,
|
|
defines.events.on_robot_pre_mined,
|
|
defines.events.on_player_mined_entity,
|
|
defines.events.on_robot_mined_entity,
|
|
}
|
|
Event.death_events = {
|
|
defines.events.on_entity_died,
|
|
defines.events.script_raised_destroy
|
|
}
|
|
Event.tile_build_events = {
|
|
defines.events.on_player_built_tile,
|
|
defines.events.on_robot_built_tile
|
|
}
|
|
Event.tile_remove_events = {
|
|
defines.events.on_player_mined_tile,
|
|
defines.events.on_robot_mined_tile
|
|
}
|
|
Event.tile_script_action = {
|
|
defines.events.script_raised_set_tiles
|
|
}
|
|
|
|
Event.register(Event.build_events, On_Built)
|
|
Event.register(Event.pre_remove_events, On_Pre_Remove)
|
|
--Event.register(Event.death_events, On_Death)
|
|
------------------------------------------------------------------------------------
|
|
-- FIND LOCAL VARIABLES THAT ARE USED GLOBALLY --
|
|
-- (Thanks to eradicator!) --
|
|
------------------------------------------------------------------------------------
|
|
setmetatable(_ENV, {
|
|
__newindex = function (self, key, value) --locked_global_write
|
|
error('\n\n[ER Global Lock] Forbidden global *write*:\n'
|
|
.. serpent.line{key = key or '<nil>', value = value or '<nil>'} .. '\n')
|
|
end,
|
|
__index = function (self, key) --locked_global_read
|
|
if not (key == "game" or key == "mods") then
|
|
error('\n\n[ER Global Lock] Forbidden global *read*:\n'
|
|
.. serpent.line{key = key or '<nil>'} .. '\n')
|
|
end
|
|
end
|
|
}) |