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('__kry_stdlib__/stdlib/event/event').set_protected_mode(false) require("util") require("libs/util_ext") require("control_tree") require("control_arboretum") ---************** Used for Testing ----- --require ("Test_Spawn") ---************* local function Create_dummy_force() -- Create dummy force for musk floor if electric grid overlay should NOT be shown in map view local f = game.create_force(BioInd.MuskForceName) -- Set new force as neutral to every other force for name, force in pairs(game.forces) do if name ~= BioInd.MuskForceName then f.set_friend(force, false) f.set_cease_fire(force, true) end end -- New force won't share chart data with any other force f.share_chart = false BioInd.writeDebug("Created force: %s", { game.forces[BioInd.MuskForceName].name }) end -- Generate a look-up table with the names of our trees local function get_bi_trees() local list = {} local trees = prototypes.get_entity_filtered({ { 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(prototypes.tile) 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 -- Generate a look-up table with recipe ingredients, as other mods may have changed them local function get_arboretum_recipes() local list = {} local recipes = prototypes.recipe local name for i = 1, 5 do name = "bi-arboretum-r" .. i list[name] = {} list[name].items = {} list[name].fluids = {} for i, ingredient in pairs(recipes[name].ingredients) do if ingredient.type == "item" then list[name].items[ingredient.name] = ingredient.amount else list[name].fluids[ingredient.name] = ingredient.amount end end end BioInd.show("Terraformer recipes", list) return list end -------------------------------------------------------------------- local function init() BioInd.writeDebug("Entered init!") if BioInd.is_debug then game.check_prototype_translations() end storage = storage or {} -------------------------------------------------------------------- -- Settings -------------------------------------------------------------------- -- Global table for storing the last state of certain mod settings storage.mod_settings = storage.mod_settings or {} if BioInd.get_startup_setting("BI_Easy_Bio_Gardens") then storage.mod_settings.garden_pole_connectors = BioInd.get_garden_pole_connectors() else storage.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). storage.compound_entities = BioInd.rebuild_compound_entity_list() -------------------------------------------------------------------- -- Tree stuff! -------------------------------------------------------------------- storage.bi = storage.bi or {} storage.bi.tree_growing = storage.bi.tree_growing or {} for i = 1, 4 do storage.bi["tree_growing_stage_" .. i] = storage.bi["tree_growing_stage_" .. i] or {} end -- List of tree prototypes created by BI storage.bi.trees = get_bi_trees() -- List of tile prototypes that can't be fertilized storage.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(storage.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 storage[compound_tab] = storage[compound_tab] or {} BioInd.writeDebug("Initialized storage[%s] (%s entities stored)", { compound_name, table_size(storage[compound_tab]) }) -- If this compound entity requires additional tables in global, initialize -- them now! local related_tables = storage.compound_entities[compound_name].add_global_tables if related_tables then for t, tab in ipairs(related_tables or {}) do storage[tab] = storage[tab] or {} BioInd.writeDebug("Initialized storage[%s] (%s values)", { tab, table_size(storage[tab]) }) end end -- If this compound entity requires additional values in global, initialize -- them now! local related_vars = storage.compound_entities[compound_name].add_global_values if related_vars then for var_name, value in pairs(related_vars or {}) do storage[var_name] = storage[var_name] or value BioInd.writeDebug("Set storage[%s] to %s", { var_name, storage[var_name] }) end end -- Clean up global tables (We can skip this for empty tables!) if next(storage[compound_tab]) then -- Remove invalid entities result = BioInd.clean_global_compounds_table(compound_name) BioInd.writeDebug("Removed %s invalid entries from storage[%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 storage[\"%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 }) -------------------------------------------------------------------- -- Musk floor -------------------------------------------------------------------- storage.bi_musk_floor_table = storage.bi_musk_floor_table or {} storage.bi_musk_floor_table.tiles = storage.bi_musk_floor_table.tiles or {} storage.bi_musk_floor_table.forces = storage.bi_musk_floor_table.forces or {} -------------------------------------------------------------------- -- Arboretum -------------------------------------------------------------------- -- Global table for arboretum radars storage.bi_arboretum_radar_table = storage.bi_arboretum_radar_table or {} -- Global table of ingredients for terraformer recipes storage.bi_arboretum_recipe_table = get_arboretum_recipes() -------------------------------------------------------------------- -- Compatibility with other mods -------------------------------------------------------------------- storage.compatible = storage.compatible or {} storage.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 -- Create dummy force for musk floor if electric grid overlay should NOT be shown in map view if BioInd.UseMuskForce and not game.forces[BioInd.MuskForceName] then Create_dummy_force() 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() -- Has setting BI_Show_musk_floor_in_mapview changed? if ConfigurationChangedData.mod_startup_settings_changed then settings_changed.musk_floor() -- Has this been obsoleted by the new init process? Turn it off for now! end -- 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 = storage.bi.trees local tab -- Growing stages for i = 1, 4 do tab = storage.bi["tree_growing_stage_" .. i] BioInd.writeDebug("Number of trees in growing stage %s: %s", { i, table_size(tab) }) for t = #tab, 1, -1 do if not trees[tab[t].tree_name] then BioInd.writeDebug("Removing invalid tree %s (%s)", { t, tab[t].tree_name }) table.remove(tab, t) 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("Number of trees in final 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 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) --------------------------------------------- Event.register(defines.events.on_trigger_created_entity, function(event) --- Used for Seed-bomb local ent = event.entity local surface = ent.surface local position = ent.position -- 'AlienBiomes' is a bool value -- we don't want to read it again if it's false, -- but only if it hasn't been set yet! AlienBiomes = AlienBiomes ~= nil and AlienBiomes or BioInd.AB_tiles() -- Basic if ent.name == "seedling" then BioInd.writeDebug("Seed Bomb Activated - Basic") seed_planted_trigger(event) -- Standard elseif ent.name == "seedling-2" then BioInd.writeDebug("Seed Bomb Activated - Standard") local currTile = surface.get_tile(position).name if storage.bi.barren_tiles[currTile] then BioInd.writeDebug("Can't fertilize %s!", { currTile }) else BioInd.writeDebug("Using fertilizer!") local terrain_name_s = AlienBiomes and "vegetation-green-grass-3" or "grass-3" surface.set_tiles { { name = terrain_name_s, position = position } } end seed_planted_trigger(event) -- Advanced elseif ent.name == "seedling-3" then BioInd.writeDebug("Seed Bomb Activated - Advanced") local currTile = surface.get_tile(position).name if storage.bi.barren_tiles[currTile] then BioInd.writeDebug("Can't fertilize %s!", { currTile }) else BioInd.writeDebug("Using fertilizer!") local terrain_name_a = AlienBiomes and "vegetation-green-grass-1" or "grass-1" surface.set_tiles { { name = terrain_name_a, position = position } } end seed_planted_trigger(event) end end) -------------------------------------------------------------------- local function On_Built(event) BioInd.writeDebug("Entered function On_Built with these data: " .. serpent.block(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 -- 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 = storage.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 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 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("storage[%s]: %s", { base_entry.tab, storage[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(storage[base_entry.tab], base, hidden_entities) BioInd.writeDebug("Stored %s in table: %s", { BioInd.print_name_id(base), storage[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") -- Arboretum radar -- we need to add it to the table! if entity.type == "radar" and entity.name == entities["bi-arboretum-area"].hidden[h_key].name and base then storage.bi_arboretum_radar_table[entity.unit_number] = base.unit_number entity.backer_name = "" BioInd.writeDebug("Added %s to storage.bi_arboretum_radar_table", { BioInd.print_name_id(entity) }) -- Electric poles -- we need to take care that they don't hook up to hidden poles! elseif entity.type == "electric-pole" then local pole = entity -- Make sure hidden poles of the Bio gardens are connected correctly! local garden_names = { "bi-bio-garden", "bi-bio-garden-larger", "bi-bio-garden-huge" } for _, gname in ipairs(garden_names) do if entities[gname] and pole.name == entities[gname].hidden[h_key].name and base then BioInd.writeDebug("Bio garden (" .. gname .. ")!") BioInd.connect_garden_pole(base, pole) BioInd.writeDebug("Connected %s (%s)", { pole.name, pole.unit_number or "nil" }) break end 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 = storage.compound_entities[entity.name] local base_entry = compound_entity and storage[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("storage[%s]: %s", { compound_entity and compound_entity.tab or "nil", compound_entity and storage[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) }) -- Arboretum: Need to separately remove the entry from the radar table if entity.name == "bi-arboretum" and base_entry.radar and base_entry.radar.valid then storage.bi_arboretum_radar_table[base_entry.radar.unit_number] = nil BioInd.show("Removed arboretum radar! Table", storage.bi_arboretum_radar_table) end -- Power rails: Connections must be explicitely removed, otherwise the poles -- from the remaining rails will automatically connect and bridge the gap in -- the power supply! if entity.name:match("bi%-%a+%-rail%-power") and base_entry.pole and base_entry.pole.valid then BioInd.writeDebug("Before") BioInd.writeDebug("Disconnecting %s!", { BioInd.print_name_id(base_entry.pole) }) base_entry.pole.disconnect_neighbour() BioInd.writeDebug("After") end -- 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", { BioInd.print_name_id(base_entry[hidden]) }) BioInd.remove_entity(base_entry[hidden]) base_entry[hidden] = nil end storage[compound_entity.tab][entity.unit_number] = nil -- Rail-to-power: Connections must be explicitely removed, otherwise the poles -- from the different rail tracks hooked up to this connector will automatically -- keep the separate power networks connected! elseif entity.name == "bi-power-to-rail-pole" then BioInd.writeDebug("Rail-to-power connector has been removed") entity.disconnect_neighbour() BioInd.writeDebug("Removed copper wires from %s (%g)", { entity.name, entity.unit_number }) -- Removed seedling elseif entity.name == "seedling" then BioInd.writeDebug("Seedling has been removed") remove_plants(entity.position, storage.bi.tree_growing) -- Removed tree elseif entity.type == "tree" and storage.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, storage.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 -------------------------------------------------------------------- local function On_Damage(event) local f_name = "On_Damage" BioInd.writeDebug("Entered function %s(%s)", { f_name, event }) local entity = event.entity local final_health = event.final_health local arb = "bi-arboretum" local associated -- Base was damaged: Find the radar associated with it! if entity.name == arb then associated = storage.bi_arboretum_table[entity.unit_number].radar -- Radar was damaged: Find the base entity! elseif entity.name == storage.compound_entities[arb].hidden.radar.name then local base_id = storage.bi_arboretum_radar_table[entity.unit_number] associated = storage.bi_arboretum_table[base_id].base end if associated and associated.valid then associated.health = final_health BioInd.writeDebug("%s was damaged (%s). Reducing health of %s to %s!", { BioInd.print_name_id(entity), event.final_damage_amount, entity.name == arb and "associated radar" or "base", associated.health }) end end -------------------------------------------------------------------- local function On_Death(event) local f_name = "On_Death" BioInd.writeDebug("Entered function %s(%s)", { f_name, event }) local entity = event.entity if not entity then error("Something went wrong -- no entity data!") end if -- Table checks storage.compound_entities[entity.name] or storage.bi.trees[entity.name] or -- Entity checks entity.name == storage.compound_entities["bi-arboretum"].hidden.radar.name or entity.name == "bi-power-to-rail-pole" or entity.name == "seedling" then BioInd.writeDebug("Divert to On_Pre_Remove!") On_Pre_Remove(event) else BioInd.writeDebug("Nothing to do!") end end -------------------------------------------------------------------- -- Radar stuff -------------------------------------------------------------------- -- Robust sector scanned handler for Arboretum radar local function On_Sector_Scanned(event) -- defensive checks BioInd.writeDebug("On_Sector_Scanned fired") --game.print("On_Sector_Scanned fired") if not (event and event.radar) then return end local radar = event.radar if not (radar.valid and radar.unit_number) then return end -- Make sure compound-entity data is available before accessing it local arb_proto = BioInd.compound_entities and BioInd.compound_entities["bi-arboretum"] if not (arb_proto and arb_proto.hidden and arb_proto.hidden.radar and arb_proto.hidden.radar.name) then -- not ready yet (init not finished) — bail out safely return end -- Only handle scans from our arboretum radar type if radar.name ~= arb_proto.hidden.radar.name then return end -- Look up the base arboretum unit_number (stored when the hidden radar was created) local base_unit_number = storage.bi_arboretum_radar_table and storage.bi_arboretum_radar_table[radar.unit_number] if not base_unit_number then -- no mapping found -> nothing to do return end local arb_table = storage.bi_arboretum_table and storage.bi_arboretum_table[base_unit_number] if not arb_table then return end -- All good: call the arboretum recipe handler Get_Arboretum_Recipe(arb_table, event) end -------------------------------------------------------------------- -- Solar Mat stuff -------------------------------------------------------------------- -------------------------------------------------------------------- -- Solar mat was removed local function solar_mat_removed(event) BioInd.writeDebug("Entered solar_mat_removed (\"%s\")", { event }) local surface = game.surfaces[event.surface_index] local tiles = event.tiles local pos, x, y -- tiles contains an array of the old tiles and their position for t, tile in pairs(tiles) do if tile.old_tile and tile.old_tile.name == "bi-solar-mat" then pos = BioInd.normalize_position(tile.position) x, y = pos.x, pos.y BioInd.writeDebug("Looking for hidden entities to remove") for _, o in pairs(surface.find_entities_filtered { name = { 'bi-musk-mat-hidden-pole', 'bi-musk-mat-hidden-panel' }, position = { x + 0.5, y + 0.5 } } or {}) do BioInd.show("Removing", o.name) o.destroy() end -- Remove tile from global tables local force_name = storage.bi_musk_floor_table.tiles and storage.bi_musk_floor_table.tiles[x] and storage.bi_musk_floor_table.tiles[x][y] if force_name then BioInd.writeDebug("Removing Musk floor tile from tables!") storage.bi_musk_floor_table.tiles[x][y] = nil if not next(storage.bi_musk_floor_table.tiles[x]) then storage.bi_musk_floor_table.tiles[x] = nil end if storage.bi_musk_floor_table.forces[force_name] and storage.bi_musk_floor_table.forces[force_name][x] then storage.bi_musk_floor_table.forces[force_name][x][y] = nil if not next(storage.bi_musk_floor_table.forces[force_name][x]) then storage.bi_musk_floor_table.forces[force_name][x] = nil end end end end end BioInd.writeDebug("bi-solar-mat: removed %g tiles", { table_size(tiles) }) end -------------------------------------------------------------------- -- A solar mat must be placed local function place_musk_floor(force, position, surface) BioInd.check_args(force, "string") position = BioInd.normalize_position(position) or BioInd.arg_err(position, "position") surface = BioInd.is_surface(surface) or BioInd.arg_err(surface, "surface") local x, y = position.x, position.y local created for n, name in ipairs({ "bi-musk-mat-hidden-pole", "bi-musk-mat-hidden-panel" }) do created = surface.create_entity({ name = name, position = { x + 0.5, y + 0.5 }, force = force }) created.minable = false created.destructible = false BioInd.writeDebug("Created %s: %s", { name, created.unit_number }) end -- Add to global tables! storage.bi_musk_floor_table.tiles[x] = storage.bi_musk_floor_table.tiles[x] or {} storage.bi_musk_floor_table.tiles[x][y] = force storage.bi_musk_floor_table.forces[force] = storage.bi_musk_floor_table.forces[force] or {} storage.bi_musk_floor_table.forces[force][x] = storage.bi_musk_floor_table.forces[force][x] or {} storage.bi_musk_floor_table.forces[force][x][y] = true end -------------------------------------------------------------------- -- Solar mat was built local function solar_mat_built(event) BioInd.show("Entered function \"solar_mat_built\"", event) -- Called from player, bot and script-raised events, so event may -- contain "robot" or "player_index" local tile = event.tile local surface = game.surfaces[event.surface_index] local player = event.player_index and game.players[event.player_index] local robot = event.robot local force = (BioInd.UseMuskForce and BioInd.MuskForceName) or (event.player_index and game.players[event.player_index].force.name) or (event.robot and event.robot.force.name) or event.force.name BioInd.show("Force.name", force) -- Item that was used to place the tile local item = event.item local old_tiles = event.tiles local position --, x, y -- Musk floor has been built -- create hidden entities! if tile.name == "bi-solar-mat" then BioInd.writeDebug("Solar Mat has been built -- must create hidden entities!") BioInd.show("Tile data", tile) for index, t in pairs(old_tiles or { tile }) do BioInd.show("Read old_tile inside loop", t) -- event.tiles will also contain landscape tiles like "grass-1", and it will always -- contain at least one tile position = BioInd.normalize_position(t.position) -- If we got here by a call from script_raised_built, force may be stored -- with the tile force = force or t.force BioInd.show("Got force from tile data", t.force or "false") BioInd.writeDebug("Building solar mat for force %s at position %s", { tostring(type(force) == "table" and force.name or force), position }) place_musk_floor(force, position, surface) end -- Fertilizer/Advanced fertilizer has been used. Check if the tile was valid -- (no Musk floor, no wooden floor, no concrete etc.) elseif item and (item.name == "fertilizer" or item.name == "bi-adv-fertilizer") then local restore_tiles = {} local products, remove_this for index, t in pairs(old_tiles or { tile }) do BioInd.show("index", index) BioInd.show("t.old_tile.name", t.old_tile.name) -- We want to restore removed tiles if nothing is supposed to grow on them! if storage.bi.barren_tiles[t.old_tile.name] then BioInd.writeDebug("%s was used on forbidden ground (%s)!", { item.name, t.old_tile.name }) restore_tiles[#restore_tiles + 1] = { name = t.old_tile.name, position = t.position } -- Is that tile minable? products = storage.bi.barren_tiles[t.old_tile.name] if type(products) == "table" then for p, product in ipairs(products) do remove_this = { name = product.name, count = product.amount } if player then BioInd.writeDebug("Removing %s (%s) from player %s", { product.name, product.amount, player.name }) player.remove_item(remove_this) elseif robot then BioInd.writeDebug("Removing %s (%s) from robot %s", { product.name, product.amount, robot.unit_number }) robot.remove_item(remove_this) end end end end end BioInd.show("restore_tiles", restore_tiles) if restore_tiles then surface.set_tiles( restore_tiles, true, -- correct_tiles true, -- remove_colliding_entities true, -- remove_colliding_decoratives true -- raise_event ) end -- Some other tile has been built -- check if it replaced musk floor! else local test local removed_tiles = {} for index, t in pairs(old_tiles or { tile }) do position = BioInd.normalize_position(t.position) test = storage.bi_musk_floor_table and storage.bi_musk_floor_table.tiles and storage.bi_musk_floor_table.tiles[position.x] and storage.bi_musk_floor_table.tiles[position.x][position.y] if test then removed_tiles[#removed_tiles + 1] = { old_tile = { name = "bi-solar-mat" }, position = position } end end if next(removed_tiles) then solar_mat_removed({ surface_index = event.surface_index, tiles = removed_tiles }) else BioInd.writeDebug("%s has been built -- nothing to do!", { tile.name }) end end end -------------------------------------------------------------------- -- A tille has been changed local function Tile_Changed(event) local f_name = "Tile_Changed" BioInd.writeDebug("Entered function %s(%s)", { f_name, event }) -- The event gives us only a list of the new tiles that have been placed. -- So let's check if any Musk floor has been built! local new_musk_floor_tiles = {} local old_musk_floor_tiles = {} local remove_musk_floor_tiles = {} local pos, old_tile, force local tile_force for t, tile in ipairs(event.tiles) do BioInd.show("t", t) pos = BioInd.normalize_position(tile.position) tile_force = storage.bi_musk_floor_table.tiles[pos.x] and storage.bi_musk_floor_table.tiles[pos.x][pos.y] BioInd.show("Placed tile", tile.name) -- Musk floor was placed if tile.name == "bi-solar-mat" then BioInd.writeDebug("Musk floor tile was placed!") new_musk_floor_tiles[#new_musk_floor_tiles + 1] = { old_tile = { name = tile.name }, position = pos, force = tile_force or BioInd.UseMuskForce and BioInd.MuskForceName or "neutral" } -- Other tile was placed -- by one of our fertilizers? elseif tile.name:match("^vegetation%-green%-grass%-[13]$") or tile.name:match("^green%-grass%-[13]$") then BioInd.writeDebug("Fertilizer was used!") -- Fertilizer was used on a Musk floor tile -- restore the tile! BioInd.show("Musk floor tile in position", tile_force) if tile_force then old_musk_floor_tiles[#old_musk_floor_tiles + 1] = { old_tile = { name = "bi-solar-mat" }, position = pos, force = tile_force } end -- Other tile was placed on a Musk floor tile -- remove Musk floor from lists! elseif tile_force then remove_musk_floor_tiles[#remove_musk_floor_tiles + 1] = { old_tile = { name = "bi-solar-mat" }, position = pos, } end end BioInd.show("new_musk_floor_tiles", new_musk_floor_tiles) BioInd.show("old_musk_floor_tiles", old_musk_floor_tiles) BioInd.show("remove_musk_floor_tiles", remove_musk_floor_tiles) if next(new_musk_floor_tiles) then solar_mat_built({ surface_index = event.surface_index, tile = { name = "bi-solar-mat" }, force = BioInd.MuskForceName, tiles = new_musk_floor_tiles }) end if next(old_musk_floor_tiles) then solar_mat_built({ surface_index = event.surface_index, tile = { name = "bi-solar-mat" }, tiles = old_musk_floor_tiles }) end if next(remove_musk_floor_tiles) then solar_mat_removed({ surface_index = event.surface_index, tiles = remove_musk_floor_tiles }) end BioInd.show("End of function", f_name) 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) Event.register(Event.tile_build_events, solar_mat_built) Event.register(Event.tile_remove_events, solar_mat_removed) Event.register(defines.events.on_entity_damaged, On_Damage, function(event) -- A function is needed for event filtering with stdlib! local entity = event.entity -- Ignore damage without effect (invulnerable/resistant entities) if event.final_damage_amount ~= 0 and -- Terraformer/Terraformer radar was damaged (storage.bi_arboretum_table[entity.unit_number] or storage.bi_arboretum_radar_table[entity.unit_number]) then return true end end) -- Radar scan Event.register(defines.events.on_sector_scanned, On_Sector_Scanned, function(event) -- A function is needed for event filtering with stdlib! if event.radar.name == BioInd.compound_entities["bi-arboretum"].hidden.radar.name then return true end end) -- Tile changed Event.register(Event.tile_script_action, Tile_Changed) ------------------------------------------------------------------------------------ -- 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 '', value = value or '' } .. '\n') end, __index = function(self, key) --locked_global_read if not (key == "game" or key == "mods" or key == "storage") then error('\n\n[ER Global Lock] Forbidden global *read*:\n' .. serpent.line { key = key or '' } .. '\n') end end })