mirror of
https://git.somenet.org/factorio/some-autoresearch.git
synced 2025-12-06 03:10:11 +00:00
745 lines
37 KiB
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
|
|
})
|