Files
factorio-autoresearch/control.lua

745 lines
37 KiB
Lua

function getConfig(force, config_changed)
if not storage.auto_research_config then
storage.auto_research_config = {}
end
-- Disable Research Queue popup
if remote.interfaces.RQ and remote.interfaces.RQ["popup"] then
remote.call("RQ", "popup", false)
end
if not storage.auto_research_config[force.name] then
storage.auto_research_config[force.name] = {
prioritized_techs = {}, -- "prioritized" is "queued". kept for backwards compatability (because i'm lazy and don't want migration code)
deprioritized_techs = {} -- "deprioritized" is "blacklisted". kept for backwards compatability (because i'm lazy and don't want migration code)
}
-- Enable Auto Research
setAutoResearch(force, true)
-- Disable queued only
setQueuedOnly(force, false)
-- Allow switching research
setAllowSwitching(force, true)
-- Print researched technology
setAnnounceCompletedResearch(force, true)
end
-- set research strategy
storage.auto_research_config[force.name].research_strategy = storage.auto_research_config[force.name].research_strategy or "balanced"
if config_changed or not storage.auto_research_config[force.name].allowed_ingredients or not storage.auto_research_config[force.name].infinite_research then
-- remember any old ingredients
local old_ingredients = {}
if storage.auto_research_config[force.name].allowed_ingredients then
for name, enabled in pairs(storage.auto_research_config[force.name].allowed_ingredients) do
old_ingredients[name] = enabled
end
end
-- find all possible tech ingredients
-- also scan for research that are infinite: techs that have no successor and tech.research_unit_count_formula is not nil
storage.auto_research_config[force.name].allowed_ingredients = {}
storage.auto_research_config[force.name].infinite_research = {}
local finite_research = {}
for _, tech in pairs(force.technologies) do
for _, ingredient in pairs(tech.research_unit_ingredients) do
storage.auto_research_config[force.name].allowed_ingredients[ingredient.name] = (old_ingredients[ingredient.name] == nil or old_ingredients[ingredient.name])
end
if tech.research_unit_count_formula then
storage.auto_research_config[force.name].infinite_research[tech.name] = tech
end
for _, pretech in pairs(tech.prerequisites) do
if pretech.enabled and not pretech.researched then
finite_research[pretech.name] = true
end
end
end
for techname, _ in pairs(finite_research) do
storage.auto_research_config[force.name].infinite_research[techname] = nil
end
end
return storage.auto_research_config[force.name]
end
function setAutoResearch(force, enabled)
if not force then
return
end
local config = getConfig(force)
config.enabled = enabled
if enabled then
-- start new research
startNextResearch(force)
end
end
function setQueuedOnly(force, enabled)
if not force then
return
end
getConfig(force).prioritized_only = enabled
-- start new research
startNextResearch(force)
end
function setAllowSwitching(force, enabled)
if not force then
return
end
getConfig(force).allow_switching = enabled
-- start new research
startNextResearch(force)
end
function setAnnounceCompletedResearch(force, enabled)
if not force then
return
end
getConfig(force).announce_completed = enabled
end
function setDeprioritizeInfiniteTech(force, enabled)
if not force then
return
end
getConfig(force).deprioritize_infinite_tech = enabled
-- start new research
startNextResearch(force)
end
function getPretechs(tech)
local pretechs = {}
pretechs[#pretechs + 1] = tech
local index = 1
while (index <= #pretechs) do
for _, pretech in pairs(pretechs[index].prerequisites) do
if pretech.enabled and not pretech.researched then
pretechs[#pretechs + 1] = pretech
end
end
index = index + 1
end
return pretechs
end
function canResearch(force, tech, config)
if not tech or tech.researched or not tech.enabled or tech.prototype.hidden then
return false
end
for _, pretech in pairs(tech.prerequisites) do
if not pretech.researched then
return false
end
end
if #tech.research_unit_ingredients == 0 then
return false
end
for _, ingredient in pairs(tech.research_unit_ingredients) do
if not config.allowed_ingredients[ingredient.name] then
return false
end
end
for _, deprioritized in pairs(config.deprioritized_techs) do
if tech.name == deprioritized then
return false
end
end
return true
end
function startNextResearch(force, override_spam_detection)
local config = getConfig(force)
if not config.enabled or (force.current_research and not config.allow_switching) or (not override_spam_detection and config.last_research_finish_tick == game.tick) then
return
end
config.last_research_finish_tick = game.tick -- if multiple research finish same tick for same force, the user probably enabled all techs
-- function for calculating tech effort
local calcEffort = function(tech)
local ingredientCount = function(ingredients)
local tech_ingredients = 0
for _, ingredient in pairs(tech.research_unit_ingredients) do
tech_ingredients = tech_ingredients + ingredient.amount
end
return tech_ingredients
end
local effort = 0
if config.research_strategy == "fast" then
effort = math.max(tech.research_unit_energy, 1) * math.max(tech.research_unit_count, 1)
elseif config.research_strategy == "slow" then
effort = math.max(tech.research_unit_energy, 1) * math.max(tech.research_unit_count, 1) * -1
elseif config.research_strategy == "cheap" then
effort = math.max(ingredientCount(tech.research_unit_ingredients), 1) * math.max(tech.research_unit_count, 1)
elseif config.research_strategy == "expensive" then
effort = math.max(ingredientCount(tech.research_unit_ingredients), 1) * math.max(tech.research_unit_count, 1) * -1
elseif config.research_strategy == "balanced" then
effort = math.max(tech.research_unit_count, 1) * math.max(tech.research_unit_energy, 1) * math.max(ingredientCount(tech.research_unit_ingredients), 1)
else
effort = math.random(1, 999)
end
if (config.deprioritize_infinite_tech and config.infinite_research[tech.name]) then
return effort * (effort > 0 and 1000 or -1000)
else
return effort
end
end
-- see if there are some techs we should research first
local next_research = nil
local least_effort = nil
for _, techname in pairs(config.prioritized_techs) do
local tech = force.technologies[techname]
if tech and not next_research then
local pretechs = getPretechs(tech)
for _, pretech in pairs(pretechs) do
local effort = calcEffort(pretech)
if (not least_effort or effort < least_effort) and canResearch(force, pretech, config) then
next_research = pretech.name
least_effort = effort
end
end
end
end
-- if no queued tech should be researched then research the "least effort" tech not researched yet
if not config.prioritized_only and not next_research then
for techname, tech in pairs(force.technologies) do
if tech.enabled and not tech.researched then
local effort = calcEffort(tech)
if (not least_effort or effort < least_effort) and canResearch(force, tech, config) then
next_research = techname
least_effort = effort
end
end
end
end
-- keep queue, just put next_research at the start.
if next_research then
local rq = {}
-- manage last element of research queue
for i=1,7 do
if force.research_queue[i] == nil then break end
if i == (#force.research_queue) then
if not (force.current_research and config.allow_switching) then
table.insert(rq, force.research_queue[i].name)
end
else
table.insert(rq, force.research_queue[i].name)
end
end
table.insert(rq, next_research)
force.research_queue = rq
end
end
function onResearchFinished(event)
local force = event.research.force
local config = getConfig(force)
-- remove researched stuff from prioritized_techs and deprioritized_techs
for i = #config.prioritized_techs, 1, -1 do
local tech = force.technologies[config.prioritized_techs[i]]
if not tech or tech.researched then
table.remove(config.prioritized_techs, i)
end
end
for i = #config.deprioritized_techs, 1, -1 do
local tech = force.technologies[config.deprioritized_techs[i]]
if not tech or tech.researched then
table.remove(config.deprioritized_techs, i)
end
end
-- announce completed research
if config.announce_completed and config.no_announce_this_tick ~= game.tick then
if config.last_research_finish_tick == game.tick then
config.no_announce_this_tick = game.tick
else
local level = ""
if event.research.research_unit_count_formula then
level = (event.research.researched and event.research.level) or (event.research.level - 1)
end
force.print{"auto_research.announce_completed", event.research.localised_name, level}
end
end
startNextResearch(event.research.force)
end
-- user interface
gui = {
toggleGui = function(player)
if player.gui.top.auto_research_gui then
player.gui.top.auto_research_gui.destroy()
else
local force = player.force
local config = getConfig(force)
local frame = player.gui.top.add{
type = "frame",
name = "auto_research_gui",
direction = "vertical",
caption = {"auto_research_gui.title"}
}
local frameflow = frame.add{
type = "flow",
style = "auto_research_list_flow",
name = "flow",
direction = "vertical"
}
-- checkboxes
frameflow.add{type = "checkbox", name = "auto_research_enabled", caption = {"auto_research_gui.enabled"}, tooltip = {"auto_research_gui.enabled_tooltip"}, state = config.enabled or false}
frameflow.add{type = "checkbox", name = "auto_research_queued_only", caption = {"auto_research_gui.prioritized_only"}, tooltip = {"auto_research_gui.prioritized_only_tooltip"}, state = config.prioritized_only or false}
frameflow.add{type = "checkbox", name = "auto_research_allow_switching", caption = {"auto_research_gui.allow_switching"}, tooltip = {"auto_research_gui.allow_switching_tooltip"}, state = config.allow_switching or false}
frameflow.add{type = "checkbox", name = "auto_research_announce_completed", caption = {"auto_research_gui.announce_completed"}, tooltip = {"auto_research_gui.announce_completed_tooltip"}, state = config.announce_completed or false}
frameflow.add{type = "checkbox", name = "auto_research_deprioritize_infinite_tech", caption = {"auto_research_gui.deprioritize_infinite_tech"}, tooltip = {"auto_research_gui.deprioritize_infinite_tech_tooltip"}, state = config.deprioritize_infinite_tech or false}
-- research strategy
frameflow.add{
type = "label",
style = "auto_research_header_label",
caption = {"auto_research_gui.research_strategy"}
}
local research_strategies_outer = frameflow.add{
type = "flow",
style = "auto_research_tech_flow",
name = "research_strategies_outer",
direction = "horizontal"
}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_fast", caption = {"auto_research_gui.research_fast"}, tooltip = {"auto_research_gui.research_fast_tooltip"}, state = config.research_strategy == "fast"}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_slow", caption = {"auto_research_gui.research_slow"}, tooltip = {"auto_research_gui.research_slow_tooltip"}, state = config.research_strategy == "slow"}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_cheap", caption = {"auto_research_gui.research_cheap"}, tooltip = {"auto_research_gui.research_cheap_tooltip"}, state = config.research_strategy == "cheap"}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_expensive", caption = {"auto_research_gui.research_expensive"}, tooltip = {"auto_research_gui.research_expensive_tooltip"}, state = config.research_strategy == "expensive"}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_balanced", caption = {"auto_research_gui.research_balanced"}, tooltip = {"auto_research_gui.research_balanced_tooltip"}, state = config.research_strategy == "balanced"}
research_strategies_outer.add{type = "radiobutton", name = "auto_research_research_random", caption = {"auto_research_gui.research_random"}, tooltip = {"auto_research_gui.research_random_tooltip"}, state = config.research_strategy == "random"}
research_strategies_outer.style.horizontal_spacing = 6
-- allowed ingredients
frameflow.add{
type = "label",
style = "auto_research_header_label",
caption = {"auto_research_gui.allowed_ingredients_label"}
}
local allowed_ingredients = frameflow.add{
type = "flow",
style = "auto_research_list_flow",
name = "allowed_ingredients",
direction = "vertical"
}
gui.updateAllowedIngredientsList(player.gui.top.auto_research_gui.flow.allowed_ingredients, player, config)
-- prioritized techs
frameflow.add{
type = "label",
style = "auto_research_header_label",
caption = {"auto_research_gui.prioritized_label"}
}
local prioritized = frameflow.add{
type = "scroll-pane",
name = "prioritized",
horizontal_scroll_policy = "never",
vertical_scroll_policy = "auto"
}
prioritized.style.top_padding = 5
prioritized.style.bottom_padding = 5
prioritized.style.maximal_height = 127
prioritized.style.minimal_width = 440
-- draw prioritized tech list
gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.prioritized, config.prioritized_techs, player, true)
-- deprioritized techs
frameflow.add{
type = "label",
style = "auto_research_header_label",
caption = {"auto_research_gui.deprioritized_label"}
}
local deprioritized = frameflow.add{
type = "scroll-pane",
name = "deprioritized",
horizontal_scroll_policy = "never",
vertical_scroll_policy = "auto"
}
deprioritized.style.top_padding = 5
deprioritized.style.bottom_padding = 5
deprioritized.style.maximal_height = 127
deprioritized.style.minimal_width = 440
-- draw deprioritized tech list
gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.deprioritized, config.deprioritized_techs, player)
-- search for techs
local searchflow = frameflow.add{
type = "flow",
name = "searchflow",
style = "auto_research_tech_flow",
direction = "horizontal"
}
searchflow.add{
type = "label",
style = "auto_research_header_label",
caption = {"auto_research_gui.search_label"}
}
searchflow.add{
type = "textfield",
name = "auto_research_search_text",
tooltip = {"auto_research_gui.search_tooltip"}
}
searchflow.add{
type = "checkbox",
name = "auto_research_ingredients_filter_search_results",
caption = {"auto_research_gui.ingredients_filter_search_results"},
tooltip = {"auto_research_gui.ingredients_filter_search_results_tooltip"},
state = config.filter_search_results or false
}
searchflow.style.horizontal_spacing = 6
searchflow.style.vertical_align = "center"
local search = frameflow.add{
type = "scroll-pane",
name = "search",
horizontal_scroll_policy = "never",
vertical_scroll_policy = "auto"
}
search.style.top_padding = 5
search.style.bottom_padding = 5
search.style.maximal_height = 127
search.style.minimal_width = 440
-- draw search result list
gui.updateSearchResult(player, "")
end
end,
onCheckboxClick = function(event)
local player = game.players[event.player_index]
local force = player.force
local name = event.element.name
if name == "auto_research_enabled" then
setAutoResearch(force, event.element.state)
elseif name == "auto_research_queued_only" then
setQueuedOnly(force, event.element.state)
elseif name == "auto_research_allow_switching" then
setAllowSwitching(force, event.element.state)
elseif name == "auto_research_announce_completed" then
setAnnounceCompletedResearch(force, event.element.state)
elseif name == "auto_research_deprioritize_infinite_tech" then
setDeprioritizeInfiniteTech(force, event.element.state)
elseif name == "auto_research_ingredients_filter_search_results" then
local config = getConfig(force)
config.filter_search_results = event.element.state
gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
end
end,
onClick = function(event)
local player = game.players[event.player_index]
local force = player.force
local config = getConfig(force)
local name = event.element.name
if name == "auto_research_search_text" then
if event.button == defines.mouse_button_type.right then
player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text = ""
gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
end
elseif string.find(name, "auto_research_research") then
config.research_strategy = string.match(name, "^auto_research_research_(.*)$")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_fast.state = (config.research_strategy == "fast")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_cheap.state = (config.research_strategy == "cheap")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_balanced.state = (config.research_strategy == "balanced")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_slow.state = (config.research_strategy == "slow")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_expensive.state = (config.research_strategy == "expensive")
player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_random.state = (config.research_strategy == "random")
-- start new research
startNextResearch(force)
else
local prefix, name = string.match(name, "^auto_research_([^-]*)-(.*)$")
if prefix == "allow_ingredient" then
config.allowed_ingredients[name] = not config.allowed_ingredients[name]
gui.updateAllowedIngredientsList(player.gui.top.auto_research_gui.flow.allowed_ingredients, player, config)
if player.gui.top.auto_research_gui.flow.searchflow.auto_research_ingredients_filter_search_results.state then
gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
end
startNextResearch(force)
elseif name and force.technologies[name] then
-- remove tech from prioritized list
for i = #config.prioritized_techs, 1, -1 do
if config.prioritized_techs[i] == name then
table.remove(config.prioritized_techs, i)
end
end
-- and from deprioritized list
for i = #config.deprioritized_techs, 1, -1 do
if config.deprioritized_techs[i] == name then
table.remove(config.deprioritized_techs, i)
end
end
if prefix == "queue_top" then
-- add tech to top of prioritized list
table.insert(config.prioritized_techs, 1, name)
elseif prefix == "queue_bottom" then
-- add tech to bottom of prioritized list
table.insert(config.prioritized_techs, name)
elseif prefix == "blacklist" then
-- add tech to list of deprioritized techs
table.insert(config.deprioritized_techs, name)
end
gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.prioritized, config.prioritized_techs, player, true)
gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.deprioritized, config.deprioritized_techs, player)
gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
-- start new research
startNextResearch(force)
end
end
end,
updateAllowedIngredientsList = function(flow, player, config)
local counter = 1
while flow["flow" .. counter] do
flow["flow" .. counter].destroy()
counter = counter + 1
end
counter = 1
for ingredientname, allowed in pairs(config.allowed_ingredients) do
local flowname = "flow" .. math.floor(counter / 10) + 1
local ingredientflow = flow[flowname]
if not ingredientflow then
ingredientflow = flow.add {
type = "flow",
style = "auto_research_tech_flow",
name = flowname,
direction = "horizontal"
}
end
local sprite = "auto_research_tool_" .. ingredientname
if not helpers.is_valid_sprite_path(sprite) then
sprite = "auto_research_unknown"
end
ingredientflow.add{type = "sprite-button", style = "auto_research_sprite_button_toggle" .. (allowed and "_pressed" or ""), name = "auto_research_allow_ingredient-" .. ingredientname, tooltip = {"item-name." .. ingredientname}, sprite = sprite}
counter = counter + 1
end
end,
updateTechnologyList = function(scrollpane, technologies, player, show_queue_buttons)
if scrollpane.flow then
scrollpane.flow.destroy()
end
local flow = scrollpane.add{
type = "flow",
style = "auto_research_list_flow",
name = "flow",
direction = "vertical"
}
if #technologies > 0 then
for _, techname in pairs(technologies) do
local tech = player.force.technologies[techname]
if tech then
local entryflow = flow.add{type = "flow", style = "auto_research_tech_flow", direction = "horizontal"}
if show_queue_buttons then
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_top-" .. techname, sprite = "auto_research_prioritize_top"}
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_bottom-" .. techname, sprite = "auto_research_prioritize_bottom"}
end
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_delete-" .. techname, sprite = "auto_research_delete"}
entryflow.add{type = "label", style = "auto_research_tech_label", caption = tech.localised_name}
for _, ingredient in pairs(tech.research_unit_ingredients) do
local sprite = "auto_research_tool_" .. ingredient.name
if not helpers.is_valid_sprite_path(sprite) then
sprite = "auto_research_unknown"
end
entryflow.add{type = "sprite", style = "auto_research_sprite", sprite = sprite}
end
end
end
else
local entryflow = flow.add{type = "flow", direction = "horizontal"}
entryflow.add{type = "label", caption = {"auto_research_gui.none"}}
end
end,
updateSearchResult = function(player, text)
local scrollpane = player.gui.top.auto_research_gui.flow.search
if scrollpane.flow then
scrollpane.flow.destroy()
end
local flow = scrollpane.add{
type = "flow",
style = "auto_research_list_flow",
name = "flow",
direction = "vertical"
}
local ingredients_filter = player.gui.top.auto_research_gui.flow.searchflow.auto_research_ingredients_filter_search_results.state
local config = getConfig(player.force)
local shown = 0
text = string.lower(text)
-- NOTICE: localised name matching does not work at present, pending unlikely changes to Factorio API
for name, tech in pairs(player.force.technologies) do
if not tech.researched and tech.enabled and #tech.research_unit_ingredients > 0 then
local showtech = false
if string.find(string.lower(name), text, 1, true) then
-- show techs that match by name
showtech = true
-- elseif string.find(string.lower(game.technology_prototypes[name].localised_name), text, 1, true) then
-- -- show techs that match by localised name
-- showtech = true
else
for _, effect in pairs(tech.prototype.effects) do
if string.find(effect.type, text, 1, true) then
-- show techs that match by effect type
showtech = true
elseif effect.type == "unlock-recipe" then
if string.find(effect.recipe, text, 1, true) then
-- show techs that match by unlocked recipe name
showtech = true
-- elseif string.find(string.lower(game.recipe_prototypes[effect.recipe].localised_name), text, 1, true) then
-- -- show techs that match by unlocked recipe localised name
-- showtech = true
else
for _, product in pairs(prototypes.recipe[effect.recipe].products) do
if string.find(product.name, text, 1, true) then
-- show techs that match by unlocked recipe product name
showtech = true
-- elseif string.find(string.lower(game.item_prototypes[product.name].localised_name), text, 1, true) then
-- -- show techs that match by unlocked recipe product localised name
-- showtech = true
else
local prototype = prototypes.item[product.name]
if prototype then
if prototype.place_result then
if string.find(prototype.place_result.name, text, 1, true) then
-- show techs that match by unlocked recipe product placed entity name
showtech = true
-- elseif string.find(string.lower(game.entity_prototypes[prototype.place_result.name].localised_name), text, 1, true) then
-- -- show techs that match by unlocked recipe product placed entity localised name
-- showtech = true
end
elseif prototype.place_as_equipment_result then
if string.find(prototype.place_as_equipment_result.name, text, 1, true) then
-- show techs that match by unlocked recipe product placed equipment name
showtech = true
-- elseif string.find(string.lower(game.equipment_prototypes[prototype.place_as_equipment_result.name].localised_name), text, 1, true) then
-- -- show techs that match by unlocked recipe product placed equipment localised name
-- showtech = true
end
elseif prototype.place_as_tile_result then
if string.find(prototype.place_as_tile_result.result.name, text, 1, true) then
-- show techs that match by unlocked recipe product placed tile name
showtech = true
-- elseif string.find(string.lower(prototype.place_as_tile_result.result.localised_name), text, 1, true) then
-- -- show techs that match by unlocked recipe product placed tile localised name
-- showtech = true
end
end
end
end
end
end
end
end
end
if showtech and config.prioritized_techs then
for _, queued_tech in pairs(config.prioritized_techs) do
if name == queued_tech then
showtech = false
break
end
end
end
if showtech and config.deprioritized_techs then
for _, blacklisted_tech in pairs(config.deprioritized_techs) do
if name == blacklisted_tech then
showtech = false
break
end
end
end
if showtech and ingredients_filter then
for _, ingredient in pairs(tech.research_unit_ingredients) do
if not config.allowed_ingredients[ingredient.name] then
-- filter out techs that require disallowed ingredients (optional)
showtech = false
end
end
end
if showtech then
shown = shown + 1
local entryflow = flow.add{type = "flow", style = "auto_research_tech_flow", direction = "horizontal"}
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_top-" .. name, sprite = "auto_research_prioritize_top"}
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_bottom-" .. name, sprite = "auto_research_prioritize_bottom"}
entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_blacklist-" .. name, sprite = "auto_research_deprioritize"}
entryflow.add{type = "label", style = "auto_research_tech_label", name = name, caption = tech.localised_name}
for _, ingredient in pairs(tech.research_unit_ingredients) do
local sprite = "auto_research_tool_" .. ingredient.name
if not helpers.is_valid_sprite_path(sprite) then
sprite = "auto_research_unknown"
end
entryflow.add{type = "sprite", style = "auto_research_sprite", sprite = sprite}
end
end
end
end
end
}
-- event hooks
script.on_configuration_changed(function()
for _, force in pairs(game.forces) do
getConfig(force, true) -- triggers initialization of force config
end
end)
script.on_event(defines.events.on_player_created, function(event)
local force = game.players[event.player_index].force
local config = getConfig(force) -- triggers initialization of force config
-- set any default queued/blacklisted techs
local queued_tech = settings.get_player_settings(game.players[event.player_index])["queued-tech-setting"].value
for tech in string.gmatch(queued_tech, "[^,$]+") do
tech = string.gsub(tech, "%s+", "")
if force.technologies[tech] and force.technologies[tech].enabled and not force.technologies[tech].researched then
table.insert(config.prioritized_techs, tech)
end
end
local blacklisted_tech = settings.get_player_settings(game.players[event.player_index])["blacklisted-tech-setting"].value
for tech in string.gmatch(blacklisted_tech, "[^,$]+") do
tech = string.gsub(tech, "%s+", "")
if force.technologies[tech] and force.technologies[tech].enabled and not force.technologies[tech].researched then
table.insert(config.deprioritized_techs, tech)
end
end
startNextResearch(force, true)
end)
script.on_event(defines.events.on_force_created, function(event)
getConfig(event.force) -- triggers initialization of force config
end)
script.on_event(defines.events.on_research_finished, onResearchFinished)
script.on_event(defines.events.on_gui_checked_state_changed, gui.onCheckboxClick)
script.on_event(defines.events.on_gui_click, gui.onClick)
script.on_event(defines.events.on_gui_text_changed, function(event)
if event.element.name ~= "auto_research_search_text" then
return
end
gui.updateSearchResult(game.players[event.player_index], event.element.text)
end)
-- keybinding hooks
script.on_event("auto_research_toggle", function(event)
local player = game.players[event.player_index]
gui.toggleGui(player)
end)
-- Add remote interfaces for enabling/disabling Auto Research
remote.add_interface("auto_research", {
enabled = function(forcename, value) setAutoResearch(game.forces[forcename], value) end,
queued_only = function(forcename, value) setQueuedOnly(game.forces[forcename], value) end,
allow_switching = function(forcename, value) setAllowSwitching(game.forces[forcename], value) end,
announce_completed = function(forcename, value) setAnnounceCompletedResearch(game.forces[forcename], value) end,
deprioritize_infinite_tech = function(forcename, value) setDeprioritizeInfiniteTech(game.forces[forcename], value) end
})