1 local auto_research_config = {}
3 function getConfig(force, config_changed)
4 -- Disable Research Queue popup
5 if remote.interfaces.RQ and remote.interfaces.RQ["popup"] then
6 remote.call("RQ", "popup", false)
9 if not auto_research_config[force.name] then
10 auto_research_config[force.name] = {
11 prioritized_techs = {}, -- "prioritized" is "queued". kept for backwards compatability (because i'm lazy and don't want migration code)
12 deprioritized_techs = {} -- "deprioritized" is "blacklisted". kept for backwards compatability (because i'm lazy and don't want migration code)
14 -- Enable Auto Research
15 setAutoResearch(force, true)
17 -- Disable queued only
18 setQueuedOnly(force, false)
20 -- Allow switching research
21 setAllowSwitching(force, true)
23 -- Print researched technology
24 setAnnounceCompletedResearch(force, true)
27 -- set research strategy
28 auto_research_config[force.name].research_strategy = auto_research_config[force.name].research_strategy or "balanced"
30 if config_changed or not auto_research_config[force.name].allowed_ingredients or not auto_research_config[force.name].infinite_research then
31 -- remember any old ingredients
32 local old_ingredients = {}
33 if auto_research_config[force.name].allowed_ingredients then
34 for name, enabled in pairs(auto_research_config[force.name].allowed_ingredients) do
35 old_ingredients[name] = enabled
38 -- find all possible tech ingredients
39 -- also scan for research that are infinite: techs that have no successor and tech.research_unit_count_formula is not nil
40 auto_research_config[force.name].allowed_ingredients = {}
41 auto_research_config[force.name].infinite_research = {}
42 local finite_research = {}
43 for _, tech in pairs(force.technologies) do
44 for _, ingredient in pairs(tech.research_unit_ingredients) do
45 auto_research_config[force.name].allowed_ingredients[ingredient.name] = (old_ingredients[ingredient.name] == nil or old_ingredients[ingredient.name])
47 if tech.research_unit_count_formula then
48 auto_research_config[force.name].infinite_research[tech.name] = tech
50 for _, pretech in pairs(tech.prerequisites) do
51 if pretech.enabled and not pretech.researched then
52 finite_research[pretech.name] = true
56 for techname, _ in pairs(finite_research) do
57 auto_research_config[force.name].infinite_research[techname] = nil
61 return auto_research_config[force.name]
64 function setAutoResearch(force, enabled)
68 local config = getConfig(force)
69 config.enabled = enabled
73 startNextResearch(force)
77 function setQueuedOnly(force, enabled)
81 getConfig(force).prioritized_only = enabled
84 startNextResearch(force)
87 function setAllowSwitching(force, enabled)
91 getConfig(force).allow_switching = enabled
94 startNextResearch(force)
97 function setAnnounceCompletedResearch(force, enabled)
101 getConfig(force).announce_completed = enabled
104 function setDeprioritizeInfiniteTech(force, enabled)
108 getConfig(force).deprioritize_infinite_tech = enabled
110 -- start new research
111 startNextResearch(force)
114 function getPretechs(tech)
116 pretechs[#pretechs + 1] = tech
118 while (index <= #pretechs) do
119 for _, pretech in pairs(pretechs[index].prerequisites) do
120 if pretech.enabled and not pretech.researched then
121 pretechs[#pretechs + 1] = pretech
129 function canResearch(force, tech, config)
130 if not tech or tech.researched or not tech.enabled or tech.prototype.hidden then
133 for _, pretech in pairs(tech.prerequisites) do
134 if not pretech.researched then
138 for _, ingredient in pairs(tech.research_unit_ingredients) do
139 if not config.allowed_ingredients[ingredient.name] then
143 for _, deprioritized in pairs(config.deprioritized_techs) do
144 if tech.name == deprioritized then
151 function startNextResearch(force, override_spam_detection)
152 local config = getConfig(force)
153 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
156 config.last_research_finish_tick = game.tick -- if multiple research finish same tick for same force, the user probably enabled all techs
158 -- function for calculating tech effort
159 local calcEffort = function(tech)
160 local ingredientCount = function(ingredients)
161 local tech_ingredients = 0
162 for _, ingredient in pairs(tech.research_unit_ingredients) do
163 tech_ingredients = tech_ingredients + ingredient.amount
165 return tech_ingredients
168 if config.research_strategy == "fast" then
169 effort = math.max(tech.research_unit_energy, 1) * math.max(tech.research_unit_count, 1)
170 elseif config.research_strategy == "slow" then
171 effort = math.max(tech.research_unit_energy, 1) * math.max(tech.research_unit_count, 1) * -1
172 elseif config.research_strategy == "cheap" then
173 effort = math.max(ingredientCount(tech.research_unit_ingredients), 1) * math.max(tech.research_unit_count, 1)
174 elseif config.research_strategy == "expensive" then
175 effort = math.max(ingredientCount(tech.research_unit_ingredients), 1) * math.max(tech.research_unit_count, 1) * -1
176 elseif config.research_strategy == "balanced" then
177 effort = math.max(tech.research_unit_count, 1) * math.max(tech.research_unit_energy, 1) * math.max(ingredientCount(tech.research_unit_ingredients), 1)
179 effort = math.random(1, 999)
181 if (config.deprioritize_infinite_tech and config.infinite_research[tech.name]) then
182 return effort * (effort > 0 and 1000 or -1000)
188 -- see if there are some techs we should research first
189 local next_research = nil
190 local least_effort = nil
191 for _, techname in pairs(config.prioritized_techs) do
192 local tech = force.technologies[techname]
193 if tech and not next_research then
194 local pretechs = getPretechs(tech)
195 for _, pretech in pairs(pretechs) do
196 local effort = calcEffort(pretech)
197 if (not least_effort or effort < least_effort) and canResearch(force, pretech, config) then
198 next_research = pretech.name
199 least_effort = effort
205 -- if no queued tech should be researched then research the "least effort" tech not researched yet
206 if not config.prioritized_only and not next_research then
207 for techname, tech in pairs(force.technologies) do
208 if tech.enabled and not tech.researched then
209 local effort = calcEffort(tech)
210 if (not least_effort or effort < least_effort) and canResearch(force, tech, config) then
211 next_research = techname
212 least_effort = effort
218 -- keep queue, just put next_research at the start.
219 if next_research then
221 table.insert(rq, next_research)
224 if force.research_queue[i] == nil then break end
225 table.insert(rq, force.research_queue[i].name)
228 force.research_queue = rq
232 function onResearchFinished(event)
233 local force = event.research.force
234 local config = getConfig(force)
235 -- remove researched stuff from prioritized_techs and deprioritized_techs
236 for i = #config.prioritized_techs, 1, -1 do
237 local tech = force.technologies[config.prioritized_techs[i]]
238 if not tech or tech.researched then
239 table.remove(config.prioritized_techs, i)
242 for i = #config.deprioritized_techs, 1, -1 do
243 local tech = force.technologies[config.deprioritized_techs[i]]
244 if not tech or tech.researched then
245 table.remove(config.deprioritized_techs, i)
248 -- announce completed research
249 if config.announce_completed and config.no_announce_this_tick ~= game.tick then
250 if config.last_research_finish_tick == game.tick then
251 config.no_announce_this_tick = game.tick
254 if event.research.research_unit_count_formula then
255 level = (event.research.researched and event.research.level) or (event.research.level - 1)
257 force.print{"auto_research.announce_completed", event.research.localised_name, level}
261 startNextResearch(event.research.force)
266 toggleGui = function(player)
267 if player.gui.top.auto_research_gui then
268 player.gui.top.auto_research_gui.destroy()
270 local force = player.force
271 local config = getConfig(force)
272 local frame = player.gui.top.add{
274 name = "auto_research_gui",
275 direction = "vertical",
276 caption = {"auto_research_gui.title"}
278 local frameflow = frame.add{
280 style = "auto_research_list_flow",
282 direction = "vertical"
286 frameflow.add{type = "checkbox", name = "auto_research_enabled", caption = {"auto_research_gui.enabled"}, tooltip = {"auto_research_gui.enabled_tooltip"}, state = config.enabled or false}
287 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}
288 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}
289 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}
290 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}
295 style = "auto_research_header_label",
296 caption = {"auto_research_gui.research_strategy"}
298 local research_strategies_outer = frameflow.add{
300 style = "auto_research_tech_flow",
301 name = "research_strategies_outer",
302 direction = "horizontal"
304 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"}
305 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"}
306 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"}
307 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"}
308 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"}
309 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"}
311 research_strategies_outer.style.horizontal_spacing = 6
313 -- allowed ingredients
316 style = "auto_research_header_label",
317 caption = {"auto_research_gui.allowed_ingredients_label"}
319 local allowed_ingredients = frameflow.add{
321 style = "auto_research_list_flow",
322 name = "allowed_ingredients",
323 direction = "vertical"
325 gui.updateAllowedIngredientsList(player.gui.top.auto_research_gui.flow.allowed_ingredients, player, config)
330 style = "auto_research_header_label",
331 caption = {"auto_research_gui.prioritized_label"}
333 local prioritized = frameflow.add{
334 type = "scroll-pane",
335 name = "prioritized",
336 horizontal_scroll_policy = "never",
337 vertical_scroll_policy = "auto"
339 prioritized.style.top_padding = 5
340 prioritized.style.bottom_padding = 5
341 prioritized.style.maximal_height = 127
342 prioritized.style.minimal_width = 440
343 -- draw prioritized tech list
344 gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.prioritized, config.prioritized_techs, player, true)
346 -- deprioritized techs
349 style = "auto_research_header_label",
350 caption = {"auto_research_gui.deprioritized_label"}
352 local deprioritized = frameflow.add{
353 type = "scroll-pane",
354 name = "deprioritized",
355 horizontal_scroll_policy = "never",
356 vertical_scroll_policy = "auto"
358 deprioritized.style.top_padding = 5
359 deprioritized.style.bottom_padding = 5
360 deprioritized.style.maximal_height = 127
361 deprioritized.style.minimal_width = 440
363 -- draw deprioritized tech list
364 gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.deprioritized, config.deprioritized_techs, player)
367 local searchflow = frameflow.add{
370 style = "auto_research_tech_flow",
371 direction = "horizontal"
375 style = "auto_research_header_label",
376 caption = {"auto_research_gui.search_label"}
380 name = "auto_research_search_text",
381 tooltip = {"auto_research_gui.search_tooltip"}
385 name = "auto_research_ingredients_filter_search_results",
386 caption = {"auto_research_gui.ingredients_filter_search_results"},
387 tooltip = {"auto_research_gui.ingredients_filter_search_results_tooltip"},
388 state = config.filter_search_results or false
390 searchflow.style.horizontal_spacing = 6
391 searchflow.style.vertical_align = "center"
393 local search = frameflow.add{
394 type = "scroll-pane",
396 horizontal_scroll_policy = "never",
397 vertical_scroll_policy = "auto"
399 search.style.top_padding = 5
400 search.style.bottom_padding = 5
401 search.style.maximal_height = 127
402 search.style.minimal_width = 440
404 -- draw search result list
405 gui.updateSearchResult(player, "")
409 onCheckboxClick = function(event)
410 local player = game.players[event.player_index]
411 local force = player.force
412 local name = event.element.name
413 if name == "auto_research_enabled" then
414 setAutoResearch(force, event.element.state)
415 elseif name == "auto_research_queued_only" then
416 setQueuedOnly(force, event.element.state)
417 elseif name == "auto_research_allow_switching" then
418 setAllowSwitching(force, event.element.state)
419 elseif name == "auto_research_announce_completed" then
420 setAnnounceCompletedResearch(force, event.element.state)
421 elseif name == "auto_research_deprioritize_infinite_tech" then
422 setDeprioritizeInfiniteTech(force, event.element.state)
423 elseif name == "auto_research_ingredients_filter_search_results" then
424 local config = getConfig(force)
425 config.filter_search_results = event.element.state
426 gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
430 onClick = function(event)
431 local player = game.players[event.player_index]
432 local force = player.force
433 local config = getConfig(force)
434 local name = event.element.name
435 if name == "auto_research_search_text" then
436 if event.button == defines.mouse_button_type.right then
437 player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text = ""
438 gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
440 elseif string.find(name, "auto_research_research") then
441 config.research_strategy = string.match(name, "^auto_research_research_(.*)$")
442 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_fast.state = (config.research_strategy == "fast")
443 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_cheap.state = (config.research_strategy == "cheap")
444 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_balanced.state = (config.research_strategy == "balanced")
445 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_slow.state = (config.research_strategy == "slow")
446 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_expensive.state = (config.research_strategy == "expensive")
447 player.gui.top.auto_research_gui.flow.research_strategies_outer.auto_research_research_random.state = (config.research_strategy == "random")
448 -- start new research
449 startNextResearch(force)
451 local prefix, name = string.match(name, "^auto_research_([^-]*)-(.*)$")
452 if prefix == "allow_ingredient" then
453 config.allowed_ingredients[name] = not config.allowed_ingredients[name]
454 gui.updateAllowedIngredientsList(player.gui.top.auto_research_gui.flow.allowed_ingredients, player, config)
455 if player.gui.top.auto_research_gui.flow.searchflow.auto_research_ingredients_filter_search_results.state then
456 gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
458 startNextResearch(force)
459 elseif name and force.technologies[name] then
460 -- remove tech from prioritized list
461 for i = #config.prioritized_techs, 1, -1 do
462 if config.prioritized_techs[i] == name then
463 table.remove(config.prioritized_techs, i)
466 -- and from deprioritized list
467 for i = #config.deprioritized_techs, 1, -1 do
468 if config.deprioritized_techs[i] == name then
469 table.remove(config.deprioritized_techs, i)
472 if prefix == "queue_top" then
473 -- add tech to top of prioritized list
474 table.insert(config.prioritized_techs, 1, name)
475 elseif prefix == "queue_bottom" then
476 -- add tech to bottom of prioritized list
477 table.insert(config.prioritized_techs, name)
478 elseif prefix == "blacklist" then
479 -- add tech to list of deprioritized techs
480 table.insert(config.deprioritized_techs, name)
482 gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.prioritized, config.prioritized_techs, player, true)
483 gui.updateTechnologyList(player.gui.top.auto_research_gui.flow.deprioritized, config.deprioritized_techs, player)
484 gui.updateSearchResult(player, player.gui.top.auto_research_gui.flow.searchflow.auto_research_search_text.text)
486 -- start new research
487 startNextResearch(force)
492 updateAllowedIngredientsList = function(flow, player, config)
494 while flow["flow" .. counter] do
495 flow["flow" .. counter].destroy()
496 counter = counter + 1
499 for ingredientname, allowed in pairs(config.allowed_ingredients) do
500 local flowname = "flow" .. math.floor(counter / 10) + 1
501 local ingredientflow = flow[flowname]
502 if not ingredientflow then
503 ingredientflow = flow.add {
505 style = "auto_research_tech_flow",
507 direction = "horizontal"
510 local sprite = "auto_research_tool_" .. ingredientname
511 if not helpers.is_valid_sprite_path(sprite) then
512 sprite = "auto_research_unknown"
514 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}
515 counter = counter + 1
519 updateTechnologyList = function(scrollpane, technologies, player, show_queue_buttons)
520 if scrollpane.flow then
521 scrollpane.flow.destroy()
523 local flow = scrollpane.add{
525 style = "auto_research_list_flow",
527 direction = "vertical"
529 if #technologies > 0 then
530 for _, techname in pairs(technologies) do
531 local tech = player.force.technologies[techname]
533 local entryflow = flow.add{type = "flow", style = "auto_research_tech_flow", direction = "horizontal"}
534 if show_queue_buttons then
535 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_top-" .. techname, sprite = "auto_research_prioritize_top"}
536 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_bottom-" .. techname, sprite = "auto_research_prioritize_bottom"}
538 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_delete-" .. techname, sprite = "auto_research_delete"}
539 entryflow.add{type = "label", style = "auto_research_tech_label", caption = tech.localised_name}
540 for _, ingredient in pairs(tech.research_unit_ingredients) do
541 local sprite = "auto_research_tool_" .. ingredient.name
542 if not helpers.is_valid_sprite_path(sprite) then
543 sprite = "auto_research_unknown"
545 entryflow.add{type = "sprite", style = "auto_research_sprite", sprite = sprite}
550 local entryflow = flow.add{type = "flow", direction = "horizontal"}
551 entryflow.add{type = "label", caption = {"auto_research_gui.none"}}
555 updateSearchResult = function(player, text)
556 local scrollpane = player.gui.top.auto_research_gui.flow.search
557 if scrollpane.flow then
558 scrollpane.flow.destroy()
560 local flow = scrollpane.add{
562 style = "auto_research_list_flow",
564 direction = "vertical"
566 local ingredients_filter = player.gui.top.auto_research_gui.flow.searchflow.auto_research_ingredients_filter_search_results.state
567 local config = getConfig(player.force)
569 text = string.lower(text)
570 -- NOTICE: localised name matching does not work at present, pending unlikely changes to Factorio API
571 for name, tech in pairs(player.force.technologies) do
572 if not tech.researched and tech.enabled then
573 local showtech = false
574 if string.find(string.lower(name), text, 1, true) then
575 -- show techs that match by name
577 -- elseif string.find(string.lower(game.technology_prototypes[name].localised_name), text, 1, true) then
578 -- -- show techs that match by localised name
581 for _, effect in pairs(tech.prototype.effects) do
582 if string.find(effect.type, text, 1, true) then
583 -- show techs that match by effect type
585 elseif effect.type == "unlock-recipe" then
586 if string.find(effect.recipe, text, 1, true) then
587 -- show techs that match by unlocked recipe name
589 -- elseif string.find(string.lower(game.recipe_prototypes[effect.recipe].localised_name), text, 1, true) then
590 -- -- show techs that match by unlocked recipe localised name
593 for _, product in pairs(prototypes.recipe[effect.recipe].products) do
594 if string.find(product.name, text, 1, true) then
595 -- show techs that match by unlocked recipe product name
597 -- elseif string.find(string.lower(game.item_prototypes[product.name].localised_name), text, 1, true) then
598 -- -- show techs that match by unlocked recipe product localised name
601 local prototype = prototypes.item[product.name]
603 if prototype.place_result then
604 if string.find(prototype.place_result.name, text, 1, true) then
605 -- show techs that match by unlocked recipe product placed entity name
607 -- elseif string.find(string.lower(game.entity_prototypes[prototype.place_result.name].localised_name), text, 1, true) then
608 -- -- show techs that match by unlocked recipe product placed entity localised name
611 elseif prototype.place_as_equipment_result then
612 if string.find(prototype.place_as_equipment_result.name, text, 1, true) then
613 -- show techs that match by unlocked recipe product placed equipment name
615 -- elseif string.find(string.lower(game.equipment_prototypes[prototype.place_as_equipment_result.name].localised_name), text, 1, true) then
616 -- -- show techs that match by unlocked recipe product placed equipment localised name
619 elseif prototype.place_as_tile_result then
620 if string.find(prototype.place_as_tile_result.result.name, text, 1, true) then
621 -- show techs that match by unlocked recipe product placed tile name
623 -- elseif string.find(string.lower(prototype.place_as_tile_result.result.localised_name), text, 1, true) then
624 -- -- show techs that match by unlocked recipe product placed tile localised name
635 if showtech and config.prioritized_techs then
636 for _, queued_tech in pairs(config.prioritized_techs) do
637 if name == queued_tech then
643 if showtech and config.deprioritized_techs then
644 for _, blacklisted_tech in pairs(config.deprioritized_techs) do
645 if name == blacklisted_tech then
651 if showtech and ingredients_filter then
652 for _, ingredient in pairs(tech.research_unit_ingredients) do
653 if not config.allowed_ingredients[ingredient.name] then
654 -- filter out techs that require disallowed ingredients (optional)
661 local entryflow = flow.add{type = "flow", style = "auto_research_tech_flow", direction = "horizontal"}
662 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_top-" .. name, sprite = "auto_research_prioritize_top"}
663 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_queue_bottom-" .. name, sprite = "auto_research_prioritize_bottom"}
664 entryflow.add{type = "sprite-button", style = "auto_research_sprite_button", name = "auto_research_blacklist-" .. name, sprite = "auto_research_deprioritize"}
665 entryflow.add{type = "label", style = "auto_research_tech_label", name = name, caption = tech.localised_name}
666 for _, ingredient in pairs(tech.research_unit_ingredients) do
667 local sprite = "auto_research_tool_" .. ingredient.name
668 if not helpers.is_valid_sprite_path(sprite) then
669 sprite = "auto_research_unknown"
671 entryflow.add{type = "sprite", style = "auto_research_sprite", sprite = sprite}
680 script.on_configuration_changed(function()
681 for _, force in pairs(game.forces) do
682 getConfig(force, true) -- triggers initialization of force config
685 script.on_event(defines.events.on_player_created, function(event)
686 local force = game.players[event.player_index].force
687 local config = getConfig(force) -- triggers initialization of force config
688 -- set any default queued/blacklisted techs
689 local queued_tech = settings.get_player_settings(game.players[event.player_index])["queued-tech-setting"].value
690 for tech in string.gmatch(queued_tech, "[^,$]+") do
691 tech = string.gsub(tech, "%s+", "")
692 if force.technologies[tech] and force.technologies[tech].enabled and not force.technologies[tech].researched then
693 table.insert(config.prioritized_techs, tech)
696 local blacklisted_tech = settings.get_player_settings(game.players[event.player_index])["blacklisted-tech-setting"].value
697 for tech in string.gmatch(blacklisted_tech, "[^,$]+") do
698 tech = string.gsub(tech, "%s+", "")
699 if force.technologies[tech] and force.technologies[tech].enabled and not force.technologies[tech].researched then
700 table.insert(config.deprioritized_techs, tech)
703 startNextResearch(force, true)
705 script.on_event(defines.events.on_force_created, function(event)
706 getConfig(event.force) -- triggers initialization of force config
708 script.on_event(defines.events.on_research_finished, onResearchFinished)
709 script.on_event(defines.events.on_gui_checked_state_changed, gui.onCheckboxClick)
710 script.on_event(defines.events.on_gui_click, gui.onClick)
711 script.on_event(defines.events.on_gui_text_changed, function(event)
712 if event.element.name ~= "auto_research_search_text" then
715 gui.updateSearchResult(game.players[event.player_index], event.element.text)
719 script.on_event("auto_research_toggle", function(event)
720 local player = game.players[event.player_index]
721 gui.toggleGui(player)
724 -- Add remote interfaces for enabling/disabling Auto Research
725 remote.add_interface("auto_research", {
726 enabled = function(forcename, value) setAutoResearch(game.forces[forcename], value) end,
727 queued_only = function(forcename, value) setQueuedOnly(game.forces[forcename], value) end,
728 allow_switching = function(forcename, value) setAllowSwitching(game.forces[forcename], value) end,
729 announce_completed = function(forcename, value) setAnnounceCompletedResearch(game.forces[forcename], value) end,
730 deprioritize_infinite_tech = function(forcename, value) setDeprioritizeInfiniteTech(game.forces[forcename], value) end