--- For working with surfaces. -- Surfaces are the "domain" of the world. -- @module Surface -- @usage local Surface = require('stdlib/area/surface') -- @see LuaSurface local Surface = {_module_name = 'Surface'} setmetatable(Surface, {__index = require('stdlib/core')}) local Is = require('stdlib/utils/is') local Area = require('stdlib/area/area') --- Flexible and safe lookup function for surfaces. -- -- @tparam ?|nil|string|{string,...}|LuaSurface|{LuaSurface,...} surface the surfaces to look up -- @treturn {nil|LuaSurface,...} an array of all valid surfaces or nil otherwise function Surface.lookup(surface) if not surface then return {} end if type(surface) == 'string' or type(surface) == 'number' then local lookup = game.surfaces[surface] if lookup then return {lookup} end return {} end if type(surface) == 'table' and surface['__self'] then return Surface.lookup(surface.name) end local results = {} for _, surface_item in pairs(surface) do if type(surface_item) == 'string' then if game.surfaces[surface_item] then table.insert(results, game.surfaces[surface_item]) end elseif type(surface_item) == 'table' and surface_item['__self'] then table.insert(results, surface_item) end end return results end --- Given a @{search_criteria|search criteria}, find all entities that match the criteria. -- -- @usage -- surface.find_all_entities({ type = 'unit', surface = 'nauvis', area = {{-1000,20},{-153,2214}}) -- -- returns a list containing all unit entities on the nauvis surface in the given area -- @param search_criteria (@{search_criteria}) a table used to search for entities -- @treturn {nil|LuaEntity,...} an array of all entities that matched the criteria **OR** *nil* if there were no matches function Surface.find_all_entities(search_criteria) Is.Assert.Table(search_criteria, 'missing search_criteria argument') if search_criteria.name == nil and search_criteria.type == nil and search_criteria.force == nil and search_criteria.area == nil then error('Missing search criteria field: name or type or force or area of entity', 2) end local surface_list = Surface.lookup(search_criteria.surface) if search_criteria.surface == nil then surface_list = game.surfaces end local results = {} for _, surface in pairs(surface_list) do local entities = surface.find_entities_filtered( { area = search_criteria.area, name = search_criteria.name, type = search_criteria.type, force = search_criteria.force } ) for _, entity in pairs(entities) do table.insert(results, entity) end end return results end --- -- This table should be passed into @{find_all_entities} function to find entities that match the criteria. -- @tfield[opt] string name internal name of an entity — (example: "locomotive") -- @tfield[opt] string type type of an entity — (example: "unit") -- @tfield[opt] string|LuaForce force the force of an entity — (examples: "neutral", "enemy") -- @tfield[opt] ?|nil|string|{string,...}|LuaSurface|{LuaSurface,...} surface the surface to search — (example: "nauvis") -- @tfield[opt] Concepts.BoundingBox area the area to search -- @table search_criteria --- Gets the area which covers the entirety of a given surface. -- This function is useful if you wish to compare the total number of chunks against the number of chunks within the entire area of a given surface. -- @tparam LuaSurface surface the surface for which to get the area -- @treturn Concepts.BoundingBox the area of a given surface function Surface.get_surface_bounds(surface) Is.Assert(surface, 'missing surface value') local x1, y1, x2, y2 = 0, 0, 0, 0 for chunk in surface.get_chunks() do if chunk.x < x1 then x1 = chunk.x elseif chunk.x > x2 then x2 = chunk.x end if chunk.y < y1 then y1 = chunk.y elseif chunk.y > y2 then y2 = chunk.y end end return Area.construct(x1 * 32, y1 * 32, x2 * 32, y2 * 32) end return Surface