mohsh86 wrote: Sun May 07, 2023 8:27 am
question remaining is, how do I populate tech_names with relevant technologies, based on items/buildings the force/team has
You could copy this and paste it into the chat console:
Code: Select all
/c
forces = {}
items = {}
craft_items = {}
item_recipes = {}
prerequisites = {}
player_inventories = {
defines.inventory.character_main,
defines.inventory.character_guns,
defines.inventory.character_ammo,
defines.inventory.character_armor,
defines.inventory.character_trash
}
for f_name, force in pairs(game.forces) do
if next(force.players) then
forces[f_name] = { items = {}, recipes = {}, research_this = {} }
for p, player in pairs(force.players) do
char = player.character
for i, id in pairs(char and char.valid and player_inventories or {}) do
inv = char.get_inventory(id)
for item, i in pairs(inv and inv.valid and inv.get_contents() or {}) do
forces[f_name].items[item] = true
items[item] = true
end
end
end
end
end
for s_name, surface in pairs(game.surfaces) do
for e, entity in pairs(surface.find_entities()) do
if entity.valid and entity.last_user then
player = type(entity.last_user) == "table" and entity.last_user or
game.players[entity.last_user]
force = player.force
for i, item in pairs(entity.prototype.items_to_place_this or {}) do
forces[force.name].items[item.name] = true
items[item.name] = true
end
if entity.has_items_inside() then
for id = 1, entity.get_max_inventory_index() do
inv = entity.get_inventory(id)
for item, i in pairs(inv and inv.valid and inv.get_contents() or {}) do
forces[force.name].items[item] = true
items[item] = true
end
end
end
end
end
end
for r_name, recipe in pairs(game.recipe_prototypes) do
for p, product in pairs(recipe.products) do
if product.type == "item" then
item_recipes[r_name] = true
craft_items[product.name] = craft_items[product.name] or {}
table.insert(craft_items[product.name], r_name)
end
end
end
for i_name, i in pairs(items) do
if not craft_items[i_name] then
for f_name, f_data in pairs(forces) do
f_data.items[i_name] = nil
end
items[i_name] = nil
else
for f_name, f_data in pairs(forces) do
for r, recipe in pairs(craft_items[i_name]) do
f_data.recipes[recipe] = true
end
end
end
end
function find_prerequisites(tech_name, list)
tech = game.technology_prototypes[tech_name]
list = list or {}
for p_name, prerequisite in pairs(tech.prerequisites) do
if not list[p_name] then
list[p_name] = true
find_prerequisites(p_name, list)
end
end
return list
end
for t_name, tech in pairs(game.technology_prototypes) do
for e, effect in pairs(tech.effects) do
if effect.type == "unlock-recipe" and item_recipes[effect.recipe] then
for f_name, f_data in pairs(forces) do
if f_data.recipes[effect.recipe] then
f_data.research_this[t_name] = true
prerequisites[t_name] = prerequisites[t_name] or find_prerequisites(t_name)
end
end
end
end
end
for f_name, f_data in pairs(forces) do
research = {}
for t_name, t in pairs(f_data.research_this) do
for p_name, p in pairs(prerequisites[t_name] or {}) do
research[p_name] = true
end
research[t_name] = true
end
force = game.forces[f_name]
for t_name, t in pairs(research) do
force.technologies[t_name].researched = true
end
end
This is basically the same code, but commented, so it should be easier to read:
Code: Select all
local forces = {}
local items = {} -- List of all items we'll find
local craft_items = {} -- List of items that can be produced by a recipe
local item_recipes = {} -- Recipes that produce an item
local prerequisites = {} -- List of all prerequisite techs required by a tech
local player_inventories = {
defines.inventory.character_main,
defines.inventory.character_guns,
defines.inventory.character_ammo,
defines.inventory.character_armor,
defines.inventory.character_trash
}
local char, inv
-- Find all forces with at least one player
for f_name, force in pairs(game.forces) do
if next(force.players) then
forces[f_name] = { items = {}, recipes = {}, research_this = {} }
-- Store names of items found in player inventories with force
for p, player in pairs(force.players) do
char = player.character
for i, id in pairs(char and char.valid and player_inventories or {}) do
inv = char.get_inventory(id)
for item, i in pairs(inv and inv.valid and inv.get_contents() or {}) do
forces[f_name].items[item] = true
items[item] = true
end
end
end
end
end
-- Find all entities on all surfaces
local force, player, items
for s_name, surface in pairs(game.surfaces) do
for e, entity in pairs(surface.find_entities()) do
-- Get force this entity belongs to (must have been placed by a player)
if entity.valid and entity.last_user then
player = type(entity.last_user) == "table" and entity.last_user or
game.players[entity.last_user]
force = player.force
-- Add names of items used to place this entity to item list of force
for i, item in pairs(entity.prototype.items_to_place_this or {}) do
forces[force.name].items[item.name] = true
items[item.name] = true
end
-- Add names of items found inside the entity to item list of force
if entity.has_items_inside() then
for id = 1, entity.get_max_inventory_index() do
inv = entity.get_inventory(id)
for item, i in pairs(inv and inv.valid and inv.get_contents() or {}) do
forces[force.name].items[item] = true
items[item] = true
end
end
end
end
end
end
-- Find all recipes that produce items
for r_name, recipe in pairs(game.recipe_prototypes) do
for p, product in pairs(recipe.products) do
-- Ignore fluids!
if product.type == "item" then
item_recipes[r_name] = true
craft_items[product.name] = craft_items[product.name] or {}
table.insert(craft_items[product.name], r_name)
end
end
end
-- Update force data
for i_name, i in pairs(items) do
-- Remove all items that can't be crafted from force data
if not craft_items[i_name] then
for f_name, f_data in pairs(forces) do
f_data.items[i_name] = nil
end
items[i_name] = nil
-- If force has this item, store names of all recipes producing it with force data
else
for f_name, f_data in pairs(forces) do
for r, recipe in pairs(craft_items[i_name]) do
f_data.recipes[recipe] = true
end
end
end
end
function find_prerequisites(tech_name, list)
local tech = game.technology_prototypes[tech_name]
list = list or {}
for p_name, prerequisite in pairs(tech.prerequisites) do
if not list[p_name] then
list[p_name] = true
find_prerequisites(p_name, list)
end
end
return list
end
-- Find all techs that unlock any of these recipes
for t_name, tech in pairs(game.technology_prototypes) do
for e, effect in pairs(tech.effects) do
if effect.type == "unlock-recipe" and item_recipes[effect.recipe] then
-- Store this tech for all forces that have the unlock recipe in their data
for f_name, f_data in pairs(forces) do
if f_data.recipes[effect.recipe] then
f_data.research_this[t_name] = true
-- If this is the first force that needs this tech, store all technologies
-- required to unlock the tech!
prerequisites[t_name] = prerequisites[t_name] or find_prerequisites(t_name)
end
end
end
end
end
-- Research techs and their prerequisites!
for f_name, f_data in pairs(forces) do
research = {}
-- One technology may be prerequisite of several other techs. We want to research
-- as little as possible as each finished research will raise an event, so we
-- compile a list where each tech will be listed just once.
for t_name, t in pairs(f_data.research_this) do
for p_name, p in pairs(prerequisites[t_name]) do
research[p_name] = true
end
-- Add the tech that was actually needed, it may be prerequisite of another tech!
research[t_name] = true
end
force = game.forces[f_name]
for t_name, t in pairs(research) do
force.technologies[t_name].researched = true
end
end
It will look for the names of items in player inventories and in the inventories of any entity on any surface. It also will keep track of items used to place down an entity. Then it will look for the recipes that create items, filter out the recipes unlocked by research, and store these techs along with their prerequisite technologies. Based on what item names are stored with a given force, it will then research the technologies.