From 6cb7b3ac0293f09a19e0a59c3cc362023910d466 Mon Sep 17 00:00:00 2001 From: Brevven Date: Tue, 7 Jan 2025 04:44:09 -0800 Subject: [PATCH] up --- control-util.lua | 257 ++++++++++++++++++- data-util.lua | 639 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 742 insertions(+), 154 deletions(-) diff --git a/control-util.lua b/control-util.lua index cd2b0f2..d744561 100644 --- a/control-util.lua +++ b/control-util.lua @@ -2,6 +2,8 @@ local me = require("me") local util = {} util.me = me +local regenerate_command = "bz-regenerate" +local list_command = "bz-list" function decode(data) if type(data) == "string" then return data end @@ -12,8 +14,22 @@ function decode(data) return table.concat(str, "") end -function util.get_list() - local p = game.item_prototypes[me.name.."-list"] +function util.check_fluid_mining() + if me.fluid_mining then + for i, force in pairs(game.forces) do + if ( + (force.technologies["uranium-processing"] and force.technologies["uranium-processing"].researched) or + (force.technologies["titanium-processing"] and force.technologies["titanium-processing"].researched) or + false + ) then + force.technologies["fluid-mining"].researched = true + end + end + end +end + +function get_list() + local p = prototypes.item[me.name.."-list"] if p then data = p.localised_description return decode(data) @@ -26,4 +42,241 @@ function util.force_enable_recipe(event, recipe_name) end end +function list(event) + if event.command and string.lower(event.command) == "bz-list" then + local player = game.players[event.player_index] + if player and player.connected then + local list = get_list() + if list and #list>0 then + local filename = util.me.name..".txt" + helpers.write_file(filename, list, false, event.player_index) + player.print("Wrote recipes to script-output/"..filename) + else + player.print("Please change your mod startup setting for this mod's modified recipes list.") + end + end + end +end + +function util.add_list_command_handler() + script.on_event(defines.events.on_console_command, list) + + if not commands.commands[list_command] then + commands.add_command(list_command, "", function() end) + end +end + + +function util.warptorio2_expansion_helper() + if script.active_mods["warptorio2_expansion"] then + function check_container_for_items(container,items) + local has_all =true + for k=1,#items do + if container.get_item_count(items[k].name) [ ] + planet must be an internal name like nauvis + resource must be an internal name like lead-ore or titanium-ore + frequency, size, and richness are optional, but all or none must be provided, and each should be a number between 0.166 and 6, where 1 is default setting. +Regenerates ore patches. If frequency/size/richness are provided, the planet will use those settings from now on, as well. + - Separate arguments with spaces, do not use < >, [ ], quotes or other symbols + - This action can take a while for larger maps! + - Ores can sometimes overlap on regeneration. This can sometimes hide ore patches. If none seem to be made for a resource, regenerate just that resource and tweak frequency/size. +]] +function util.add_regenerate_command_handler() + script.on_event(defines.events.on_console_command, regenerate_ore) + + if not commands.commands[regenerate_command] then + commands.add_command( regenerate_command, usage_regenerate, function() end) + end +end + +function regenerate_ore(event) + if event.command == regenerate_command then + local params = {} + for w in event.parameters:gmatch("%S+") do table.insert(params, w) end + if #params == 1 and params[1] == "all" then + for _, resource in pairs(me.resources) do + game.print("Regenerating "..resource) + game.regenerate_entity(resource) + end + return + end + if not (#params == 2 or #params == 5) then + game.print(usage_regenerate) + return + end + local planet = params[1] + for _, resource in pairs(me.resources) do + if not game.surfaces[planet] then + game.print("Could not find surface for "..planet..". May not exist, or may not yet be explored.") + return + end + if resource == params[2] then + if #params == 5 then + local settings = {frequency=params[3], size=params[4], richness=params[5]} + local map_gen_settings = game.surfaces[planet].map_gen_settings + map_gen_settings.autoplace_controls[resource] = settings + map_gen_settings.autoplace_settings.entity.settings[resource] = settings + game.surfaces[planet].map_gen_settings = map_gen_settings + game.print("Set "..resource.." on "..planet.." to "..serpent.line(settings)) + end + game.print("Regenerating "..resource) + game.surfaces[planet].regenerate_entity(resource) + end + end + end +end + +function util.ore_fix() + ore_fix("nauvis") + if game.surfaces.tenebris then + ore_fix("tenebris") + end +end + +function ore_fix(surface_name) + for _, resource in pairs(me.resources) do + local map_gen_settings = game.surfaces[surface_name].map_gen_settings + if map_gen_settings.autoplace_controls[resource] == nil then + map_gen_settings.autoplace_controls[resource] = {} + end + if map_gen_settings.autoplace_settings.entity.settings[resource] == nil then + map_gen_settings.autoplace_settings.entity.settings[resource] = {} + end + game.surfaces[surface_name].map_gen_settings = map_gen_settings + end +end + + +-- A workaround for generating ores until this bug is fixed: +-- https://forums.factorio.com/viewtopic.php?f=7&t=124996&p=655013#p655013 +function util.ore_workaround(event) + for i, ore in pairs(util.me.ores_for_workaround) do + if ( + event.surface and + event.surface.map_gen_settings and + event.surface.map_gen_settings.autoplace_controls and + event.surface.map_gen_settings.autoplace_controls["titanium-ore"] + ) then + return + end + if event.surface.name ~= "nauvis" then return end + if math.random() < settings.global[util.me.name.."-ore-workaround-probability"].value then + util.generate_ore(event, ore.name, ore.amount, ore.tiles) + end + end +end + +-- The majority of this function was written by Eradicator, see https://forums.factorio.com/viewtopic.php?t=72723 +function util.generate_ore(event, name, amount, tiles) + local biases = {[0] = {[0] = 1}} + local t = 1 + + repeat + t = t + util.grow(biases,t,tiles) + until t >= tiles + + local pos = {x=event.position.x*32, y=event.position.y*32} + local multiplier = math.max(math.abs(event.position.x), math.abs(event.position.y)) + if multiplier < 10 then return end -- don't generate too close to start + local total_bias = 0 + for x,_ in pairs(biases) do for y,bias in pairs(_) do + total_bias = total_bias + bias + end end + + for x,_ in pairs(biases) do for y,bias in pairs(_) do + local entity = { + name = name, + amount = amount * (bias/total_bias) * multiplier, + force = 'neutral', + position = {pos.x+x,pos.y+y}, + } + if event.surface.can_place_entity(entity) then + event.surface.create_entity(entity) + end + end end + +end + +-- The majority of this function was written by Eradicator, see https://forums.factorio.com/viewtopic.php?t=72723 +function util.grow(grid,t,tiles) + local w_max = 256 + local h_max = 256 + local abs = math.abs + local old = {} + local new_count = 0 + for x,_ in pairs(grid) do for y,__ in pairs(_) do + table.insert(old,{x,y}) + end end + for _,pos in pairs(old) do + local x,y = pos[1],pos[2] + local bias = grid[x][y] + for dx=-1,1,1 do for dy=-1,1,1 do + local a,b = x+dx, y+dy + if (math.random() > 0.9) and (abs(a) < w_max) and (abs(b) < h_max) then + grid[a] = grid[a] or {} + if not grid[a][b] then + grid[a][b] = 1 - (t/tiles) + new_count = new_count + 1 + if (new_count+t) == tiles then return new_count end + end + end + end end + end + return new_count + end + + + return util diff --git a/data-util.lua b/data-util.lua index 0c58ecd..788a86e 100644 --- a/data-util.lua +++ b/data-util.lua @@ -11,6 +11,10 @@ util.get_setting = util.me.get_setting util.titanium_plate = "" util.titanium_processing = "" +util.A = {{"automation-science-pack", 1}} +util.AL = {{"automation-science-pack", 1}, {"logistic-science-pack", 1}} +util.ALC = {{"automation-science-pack", 1}, {"logistic-science-pack", 1}, {"chemical-science-pack", 1}} + if mods["FactorioExtended-Plus-Core"] then util.titanium_plate = "titanium-alloy" else @@ -23,6 +27,28 @@ else util.titanium_processing = "titanium-processing" end +util.vacuum_icon = { icon="__base__/graphics/icons/fluid/steam.png", tint={r=.1, g=.1, b=.5, a=.5} } +util.vacuum_icon_small = { icon="__base__/graphics/icons/fluid/steam.png", tint={r=.1, g=.1, b=.5, a=.5}, scale=0.25, shift={-8,-8}, } +util.vacuum_vis = {r=.1, g=.1, b=.5} + +function util.item(item, quantity, probability) + if not quantity then + quantity = 1 + end + if probability then + return {type="item", name=item, amount=quantity, probability=probability} + else + return {type="item", name=item, amount=quantity} + end +end + +function util.fluid(fluid, quantity) + if not quantity then + quantity = 10 + end + return {type="fluid", name=fluid, amount=quantity} +end + function util.se6() return mods["space-exploration"] and mods["space-exploration"] >= "0.6" end @@ -91,6 +117,268 @@ function util.contains(table, sought) return false end +-- Add the gleba rock. If it exists, still add resource to mine from it +function util.add_gleba_rock(resource, amount_min, amount_max) + if (not data.raw.planet.gleba or + not data.raw.planet.gleba.map_gen_settings or -- attempted compatibility fixes + not data.raw.planet.gleba.map_gen_settings.autoplace_settings or + not data.raw.planet.gleba.map_gen_settings.autoplace_settings.entity or + not data.raw.planet.gleba.map_gen_settings.autoplace_settings.entity.settings + ) then return end + if not data.raw["simple-entity"]["gleba-rock"] then + local autoplace_utils = require("autoplace_utils") + local hit_effects = require ("__base__.prototypes.entity.hit-effects") + local sounds = require ("__base__.prototypes.entity.sounds") + local decorative_trigger_effects = require("__base__.prototypes.decorative.decorative-trigger-effects") + data.raw.planet.gleba.map_gen_settings.autoplace_settings.entity.settings["gleba-rock"] = {} + data:extend({ + { + type = "simple-entity", + name = "gleba-rock", + localised_name = {"entity-name.big-rock"}, + flags = {"placeable-neutral", "placeable-off-grid"}, + icon = "__base__/graphics/icons/big-sand-rock.png", + subgroup = "grass", + order = "b[decorative]-l[rock]-a[big]", + deconstruction_alternative = "big-rock", + collision_box = {{-0.75, -0.75}, {0.75, 0.75}}, + selection_box = {{-1.0, -1.0}, {1.0, 0.75}}, + damaged_trigger_effect = hit_effects.rock(), + render_layer = "object", + max_health = 500, + autoplace = { + control = "gleba_plants", + order = "z[gleba]-a[rock]-b[big]", + probability_expression = "max(main_probability, invasion_tall_probability)", + richness_expression = "random_penalty_at(3, 1)", + tile_restriction = { + "highland-yellow-rock", + "highland-dark-rock", + "highland-dark-rock-2", + }, + local_expressions = { + main_box = "gleba_select(gleba_moisture, 0, 0.25, 0.01, -10, 1) - 1", + main_probability = "min(0.08, 0.15 * (main_box + gleba_plants_noise_b - 0.45) * control:gleba_plants:size)", -- bigger patches, denser + invasion_tall_box = "gleba_select(gleba_moisture, 0, 0.35, 0.01, -10, 1) - 1", + invasion_tall_probability = "min(0.05, 0.15 * (invasion_tall_box + gleba_plants_noise_b - 0.4) * control:gleba_plants:size)", -- smaller patches, sparser + } + }, + + dying_trigger_effect = decorative_trigger_effects.big_rock(), + minable = + { + mining_particle = "stone-particle", + mining_time = 2, + results = { + {type = "item", name = "stone", amount_min = 5, amount_max = 10}, + } + }, + resistances = + { + { + type = "fire", + percent = 100 + } + }, + map_color = {129, 105, 78}, + count_as_rock_for_filtered_deconstruction = true, + mined_sound = sounds.deconstruct_bricks(1.0), + impact_category = "stone", + pictures = + { + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-01.png", + width = 209, + height = 138, + shift = {0.304688, -0.4}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-02.png", + width = 165, + height = 129, + shift = {0.0, 0.0390625}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-03.png", + width = 151, + height = 139, + shift = {0.151562, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-04.png", + width = 216, + height = 110, + shift = {0.390625, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-05.png", + width = 154, + height = 147, + shift = {0.328125, 0.0703125}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-06.png", + width = 154, + height = 132, + shift = {0.16875, -0.1}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-07.png", + width = 193, + height = 130, + shift = {0.3, -0.2}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-08.png", + width = 136, + height = 117, + shift = {0.0, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-09.png", + width = 157, + height = 115, + shift = {0.1, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-10.png", + width = 198, + height = 153, + shift = {0.325, -0.1}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-11.png", + width = 190, + height = 115, + shift = {0.453125, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-12.png", + width = 229, + height = 126, + shift = {0.539062, -0.015625}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-13.png", + width = 151, + height = 125, + shift = {0.0703125, 0.179688}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-14.png", + width = 137, + height = 117, + shift = {0.160938, 0.0}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-15.png", + width = 201, + height = 141, + shift = {0.242188, -0.195312}, + scale = 0.5 + }, + { + filename = "__base__/graphics/decorative/sand-rock/big-sand-rock-16.png", + width = 209, + height = 154, + shift = {0.351562, -0.1}, + scale = 0.5 + } + } + }, + }) + local probability = data.raw["simple-entity"]["gleba-rock"].autoplace.probability_expression + -- A lot more common near starting point when aps gleba + local factor = (mods["any-planet-start"] and me.get_setting("aps-planet") == "gleba" and 20) or 1 + data.raw["simple-entity"]["gleba-rock"].autoplace.probability_expression = probability..[[* + if(distance_from_nearest_point{x = x, y = y, points = starting_positions} < 200, ]]..factor..[[, + if(distance_from_nearest_point{x = x, y = y, points = starting_positions} < 700, + 100/(distance_from_nearest_point{x = x, y = y, points = starting_positions} - 100), 0.17)) + ]] + + end + if data.raw.item[resource] then + amount_min = (amount_min or 10) * ((mods["any-planet-start"] and me.get_setting("aps-planet") == "gleba" and 4) or 1) + amount_max = (amount_max or 20) * ((mods["any-planet-start"] and me.get_setting("aps-planet") == "gleba" and 4) or 1) + util.add_minable_result( + "simple-entity", "gleba-rock", + {type="item", name=resource, amount_min=amount_min, amount_max=amount_max}) + end +end + +-- Replace 'uranium-mining' tech with 'fluid-mining', defaulting to same costs +function util.add_fluid_mining() + if data.raw.technology["fluid-mining"] then return end + data:extend({ + { + type = "technology", + name = "fluid-mining", + icon = "__"..util.me.name.."__/graphics/technology/fluid-mining.png", + icon_size = 256, + effects = + { + { + type = "mining-with-fluid", + modifier = true + } + }, + prerequisites = {"chemical-science-pack", "concrete"}, + unit = + { + count = 100, + ingredients = + { + {"automation-science-pack", 1}, + {"logistic-science-pack", 1}, + {"chemical-science-pack", 1} + }, + time = 30, + } + } + }) +end + +-- Final fix to make sure nothing uses "uranium-mining" +function util.use_fluid_mining_final() + for i, tech in pairs(data.raw.technology) do + if tech.prerequisites then + for j, pre in pairs(tech.prerequisites) do + if pre == "uranium-mining" then + util.add_prerequisite(tech.name, "fluid-mining") + util.remove_prerequisite(tech.name, "uranium-mining") + break + end + end + end + end + util.remove_raw("technology", "uranium-mining") +end + +-- If Hot metals mod is enabled, mark these metals as hot +function util.add_hot_metals(metals) + if HotMetals and HotMetals.items then + for _, metal in pairs(metals) do + if data.raw.item[metal] or (metal.name and data.raw.item[metal.name]) then + table.insert(HotMetals.items, metal) + end + end + end +end + -- se landfill -- params: ore, icon_size @@ -298,15 +586,12 @@ function util.se_matter(params) end end +-- deprecated -- Get the normal prototype for a recipe -- either .normal or the recipe itself function util.get_normal(recipe_name) if data.raw.recipe[recipe_name] then recipe = data.raw.recipe[recipe_name] - if recipe.normal and recipe.normal.ingredients then - return recipe.normal - elseif recipe.ingredients then - return recipe - end + return recipe end end @@ -415,41 +700,68 @@ end function util.set_tech_recipe(technology_name, ingredients) local technology = data.raw.technology[technology_name] if technology then + if not technology.unit then + -- set a sane unit just in case + technology.unit = {time = 30, count = 50} + end technology.unit.ingredients = ingredients + technology.research_trigger = nil + end +end + +-- Set technology trigger +function util.set_tech_trigger(technology_name, trigger) + local technology = data.raw.technology[technology_name] + if technology then + technology.unit = nil + technology.research_trigger = trigger end end function util.set_enabled(recipe_name, enabled) if data.raw.recipe[recipe_name] then - if data.raw.recipe[recipe_name].normal then data.raw.recipe[recipe_name].normal.enabled = enabled end - if data.raw.recipe[recipe_name].expensive then data.raw.recipe[recipe_name].expensive.enabled = enabled end - if not data.raw.recipe[recipe_name].normal then data.raw.recipe[recipe_name].enabled = enabled end + data.raw.recipe[recipe_name].enabled = enabled end end function util.set_hidden(recipe_name) if data.raw.recipe[recipe_name] then - if data.raw.recipe[recipe_name].normal then data.raw.recipe[recipe_name].normal.hidden = true end - if data.raw.recipe[recipe_name].expensive then data.raw.recipe[recipe_name].expensive.hidden = true end - if not data.raw.recipe[recipe_name].normal then data.raw.recipe[recipe_name].hidden = true end + data.raw.recipe[recipe_name].hidden = true end end +-- adds a crafting category if it doesn't exist, also optionally allowing handcrafting +function util.add_new_crafting_category(category, by_hand) + if not data.raw["recipe-category"][category] then + data:extend({{ + type="recipe-category", + name=category, + }}) + end + if by_hand then + for i, character in pairs(data.raw.character) do + if character.crafting_categories then + table.insert(character.crafting_categories, category) + end + end + end +end + + -- Add a given quantity of ingredient to a given recipe function util.add_or_add_to_ingredient(recipe_name, ingredient, quantity, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] and data.raw.item[ingredient] then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) add_or_add_to_ingredient(data.raw.recipe[recipe_name], ingredient, quantity) - add_or_add_to_ingredient(data.raw.recipe[recipe_name].normal, ingredient, quantity) - add_or_add_to_ingredient(data.raw.recipe[recipe_name].expensive, ingredient, quantity) end end function add_or_add_to_ingredient(recipe, ingredient, quantity) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == ingredient or existing.name == ingredient then + if existing.name == ingredient then add_to_ingredient(recipe, ingredient, quantity) return end @@ -464,23 +776,22 @@ function util.add_ingredient(recipe_name, ingredient, quantity, options) local is_fluid = not not data.raw.fluid[ingredient] if data.raw.recipe[recipe_name] and (data.raw.item[ingredient] or is_fluid) then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) add_ingredient(data.raw.recipe[recipe_name], ingredient, quantity, is_fluid) - add_ingredient(data.raw.recipe[recipe_name].normal, ingredient, quantity, is_fluid) - add_ingredient(data.raw.recipe[recipe_name].expensive, ingredient, quantity, is_fluid) end end function add_ingredient(recipe, ingredient, quantity, is_fluid) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == ingredient or existing.name == ingredient then + if existing.name == ingredient then return end end if is_fluid then table.insert(recipe.ingredients, {type="fluid", name=ingredient, amount=quantity}) else - table.insert(recipe.ingredients, {ingredient, quantity}) + table.insert(recipe.ingredients, {type="item", name=ingredient, amount=quantity}) end end end @@ -488,21 +799,17 @@ end -- Add a given ingredient prototype to a given recipe function util.add_ingredient_raw(recipe_name, ingredient, options) if not should_force(options) and bypass(recipe_name) then return end - if data.raw.recipe[recipe_name] and (data.raw.item[ingredient.name] or data.raw.item[ingredient[1]]) then + if data.raw.recipe[recipe_name] and data.raw.item[ingredient.name] then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) add_ingredient_raw(data.raw.recipe[recipe_name], ingredient) - add_ingredient_raw(data.raw.recipe[recipe_name].normal, ingredient) - add_ingredient_raw(data.raw.recipe[recipe_name].expensive, ingredient) end end function add_ingredient_raw(recipe, ingredient) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if ( - (existing[1] and (existing[1] == ingredient[1] or existing[1] == ingredient.name)) or - (existing.name and (existing.name == ingredient[1] or existing.name == ingredient.name)) - ) then + if existing.name == ingredient.name then return end end @@ -515,19 +822,15 @@ function util.set_ingredient(recipe_name, ingredient, quantity, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] and data.raw.item[ingredient] then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) set_ingredient(data.raw.recipe[recipe_name], ingredient, quantity) - set_ingredient(data.raw.recipe[recipe_name].normal, ingredient, quantity) - set_ingredient(data.raw.recipe[recipe_name].expensive, ingredient, quantity) end end function set_ingredient(recipe, ingredient, quantity) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == ingredient then - existing[2] = quantity - return - elseif existing.name == ingredient then + if existing.name == ingredient then existing.amount = quantity existing.amount_min = nil existing.amount_max = nil @@ -542,43 +845,31 @@ end function util.add_product(recipe_name, product, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] and - (data.raw.item[product[1]] or data.raw.item[product.name] or - data.raw.fluid[product[1]] or data.raw.fluid[product.name] + (data.raw.item[product.name] or data.raw.fluid[product.name] ) then add_product(data.raw.recipe[recipe_name], product) - add_product(data.raw.recipe[recipe_name].normal, product) - add_product(data.raw.recipe[recipe_name].expensive, product) end end function add_product(recipe, product) if recipe ~= nil then - if (product[1] and data.raw.item[product[1]]) or - (product.name and data.raw[product.type][product.name]) then - if not recipe.normal then - if recipe.results == nil then - recipe.results = {{recipe.result, recipe.result_count and recipe.result_count or 1}} - end - recipe.result = nil - recipe.result_count = nil - table.insert(recipe.results, product) + if product.name and data.raw[product.type][product.name] then + if recipe.results == nil then + recipe.results = {{recipe.result, recipe.result_count and recipe.result_count or 1}} end + recipe.result = nil + recipe.result_count = nil + table.insert(recipe.results, product) end end end --- Get the amount of the ingredient, will check base/normal not expensive +-- Get the amount of the ingredient function util.get_ingredient_amount(recipe_name, ingredient_name) local recipe = data.raw.recipe[recipe_name] if recipe then - if recipe.normal and recipe.normal.ingredients then - for i, ingredient in pairs(recipe.normal.ingredients) do - if ingredient[1] == ingredient_name then return ingredient[2] end - if ingredient.name == ingredient_name then return ingredient.amount end - end - elseif recipe.ingredients then + if recipe.ingredients then for i, ingredient in pairs(recipe.ingredients) do - if ingredient[1] == ingredient_name then return ingredient[2] end if ingredient.name == ingredient_name then return ingredient.amount end end end @@ -587,27 +878,17 @@ function util.get_ingredient_amount(recipe_name, ingredient_name) return 0 end --- Get the amount of the result, will check base/normal not expensive +-- Get the amount of the result function util.get_amount(recipe_name, product) if not product then product = recipe_name end local recipe = data.raw.recipe[recipe_name] if recipe then - if recipe.normal and recipe.normal.results then - for i, result in pairs(recipe.normal.results) do - if result[1] == product then return result[2] end - if result.name == product then return result.amount end - end - elseif recipe.normal and recipe.normal.result_count then - return recipe.normal.result_count - elseif recipe.results then + if recipe.results then for i, result in pairs(recipe.results) do - if result[1] == product then return result[2] end if result.name == product then return result.amount end end - elseif recipe.result_count then - return recipe.result_count end - return 1 + return 0 end return 0 end @@ -617,9 +898,7 @@ function util.get_result_count(recipe_name, product) if not product then product = recipe_name end local recipe = data.raw.recipe[recipe_name] if recipe then - if recipe.normal and recipe.normal.results then - return #(recipe.normal.results) - elseif recipe.results then + if recipe.results then return #(recipe.results) end return 1 @@ -633,16 +912,15 @@ function util.replace_ingredient(recipe_name, old, new, amount, multiply, option if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] and (data.raw.item[new] or data.raw.fluid[new]) then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) replace_ingredient(data.raw.recipe[recipe_name], old, new, amount, multiply) - replace_ingredient(data.raw.recipe[recipe_name].normal, old, new, amount, multiply) - replace_ingredient(data.raw.recipe[recipe_name].expensive, old, new, amount, multiply) end end function replace_ingredient(recipe, old, new, amount, multiply) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == new or existing.name == new then + if existing.name == new then return end end @@ -656,16 +934,6 @@ function replace_ingredient(recipe, old, new, amount, multiply) ingredient.amount = amount end end - end - if ingredient[1] == old then - ingredient[1] = new - if amount then - if multiply then - ingredient[2] = amount * ingredient[2] - else - ingredient[2] = amount - end - end end end end @@ -676,9 +944,8 @@ function util.remove_ingredient(recipe_name, old, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) remove_ingredient(data.raw.recipe[recipe_name], old) - remove_ingredient(data.raw.recipe[recipe_name].normal, old) - remove_ingredient(data.raw.recipe[recipe_name].expensive, old) end end @@ -686,7 +953,7 @@ function remove_ingredient(recipe, old) index = -1 if recipe ~= nil and recipe.ingredients ~= nil then for i, ingredient in pairs(recipe.ingredients) do - if ingredient.name == old or ingredient[1] == old then + if ingredient.name == old then index = i break end @@ -703,9 +970,8 @@ function util.replace_some_product(recipe_name, old, old_amount, new, new_amount local is_fluid = not not data.raw.fluid[new] -- NOTE CURRENTLY UNUSUED if data.raw.recipe[recipe_name] and (data.raw.item[new] or is_fluid) then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) replace_some_product(data.raw.recipe[recipe_name], old, old_amount, new, new_amount, is_fluid) - replace_some_product(data.raw.recipe[recipe_name].normal, old, old_amount, new, new_amount, is_fluid) - replace_some_product(data.raw.recipe[recipe_name].expensive, old, old_amount, new, new_amount, is_fluid) end end @@ -714,7 +980,7 @@ function replace_some_product(recipe, old, old_amount, new, new_amount) if recipe.result == new then return end if recipe.results then for i, existing in pairs(recipe.results) do - if existing[1] == new or existing.name == new then + if existing.name == new then return end end @@ -723,9 +989,6 @@ function replace_some_product(recipe, old, old_amount, new, new_amount) for i, product in pairs(recipe.results) do if product.name == old then product.amount = math.max(1, product.amount - old_amount) - end - if product[1] == old then - product[2] = math.max(1, product[2] - old_amount) end end end @@ -737,47 +1000,61 @@ function util.replace_some_ingredient(recipe_name, old, old_amount, new, new_amo local is_fluid = not not data.raw.fluid[new] if data.raw.recipe[recipe_name] and (data.raw.item[new] or is_fluid) then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) replace_some_ingredient(data.raw.recipe[recipe_name], old, old_amount, new, new_amount, is_fluid) - replace_some_ingredient(data.raw.recipe[recipe_name].normal, old, old_amount, new, new_amount, is_fluid) - replace_some_ingredient(data.raw.recipe[recipe_name].expensive, old, old_amount, new, new_amount, is_fluid) end end function replace_some_ingredient(recipe, old, old_amount, new, new_amount, is_fluid) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == new or existing.name == new then + if existing.name == new then return end end for i, ingredient in pairs(recipe.ingredients) do if ingredient.name == old then ingredient.amount = math.max(1, ingredient.amount - old_amount) - end - if ingredient[1] == old then - ingredient[2] = math.max(1, ingredient[2] - old_amount) end end add_ingredient(recipe, new, new_amount, is_fluid) end end +-- set the probability of a product. +function util.set_product_probability(recipe_name, product, probability, options) + if not should_force(options) and bypass(recipe_name) then return end + if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) + set_product_probability(data.raw.recipe[recipe_name], product, probability) + end +end + +function set_product_probability(recipe, product, probability) + if recipe then + if recipe.results then + for i, result in pairs(recipe.results) do + if result.name == product then + result.probability = probability + end + end + end + end +end + -- set the amount of a product. function util.set_product_amount(recipe_name, product, amount, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) set_product_amount(data.raw.recipe[recipe_name], product, amount) - set_product_amount(data.raw.recipe[recipe_name].normal, product, amount) - set_product_amount(data.raw.recipe[recipe_name].expensive, product, amount) end end function set_product_amount(recipe, product, amount) if recipe then - if recipe.result_count then - recipe.result_count = amount - end if recipe.results then for i, result in pairs(recipe.results) do if result.name == product then @@ -790,9 +1067,6 @@ function set_product_amount(recipe, product, amount) result.amount = amount end end - if result[1] == product then - result[2] = amount - end end end if not recipe.results and not recipe.result_count then @@ -805,11 +1079,10 @@ end -- multiply the cost, energy, and results of a recipe by a multiple function util.multiply_recipe(recipe_name, multiple, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) multiply_recipe(data.raw.recipe[recipe_name], multiple) - multiply_recipe(data.raw.recipe[recipe_name].normal, multiple) - multiply_recipe(data.raw.recipe[recipe_name].expensive, multiple) end end @@ -837,9 +1110,6 @@ function multiply_recipe(recipe, multiple) result.catalyst_amount = result.catalyst_amount * multiple end end - if result[1] then - result[2] = result[2] * multiple - end end end if not recipe.results and not recipe.result_count then @@ -851,9 +1121,6 @@ function multiply_recipe(recipe, multiple) if ingredient.name then ingredient.amount = ingredient.amount * multiple end - if ingredient[1] then - ingredient[2] = ingredient[2] * multiple - end end end end @@ -861,15 +1128,14 @@ end -- Returns true if a recipe has an ingredient function util.has_ingredient(recipe_name, ingredient) - return data.raw.recipe[recipe_name] and ( - has_ingredient(data.raw.recipe[recipe_name], ingredient) or - has_ingredient(data.raw.recipe[recipe_name].normal, ingredient)) + return data.raw.recipe[recipe_name] and + has_ingredient(data.raw.recipe[recipe_name], ingredient) end function has_ingredient(recipe, ingredient) if recipe ~= nil and recipe.ingredients ~= nil then for i, existing in pairs(recipe.ingredients) do - if existing[1] == ingredient or existing.name == ingredient then + if existing.name == ingredient then return true end end @@ -880,11 +1146,10 @@ end -- Remove a product from a recipe, WILL NOT remove the only product function util.remove_product(recipe_name, old, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) remove_product(data.raw.recipe[recipe_name], old) - remove_product(data.raw.recipe[recipe_name].normal, old) - remove_product(data.raw.recipe[recipe_name].expensive, old) end end @@ -892,7 +1157,7 @@ function remove_product(recipe, old) index = -1 if recipe ~= nil and recipe.results ~= nil then for i, result in pairs(recipe.results) do - if result.name == old or result[1] == old then + if result.name == old then index = i break end @@ -907,8 +1172,6 @@ function util.set_main_product(recipe_name, product, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] then set_main_product(data.raw.recipe[recipe_name], product) - set_main_product(data.raw.recipe[recipe_name].normal, product) - set_main_product(data.raw.recipe[recipe_name].expensive, product) end end @@ -923,8 +1186,6 @@ function util.replace_product(recipe_name, old, new, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] then replace_product(data.raw.recipe[recipe_name], old, new, options) - replace_product(data.raw.recipe[recipe_name].normal, old, new, options) - replace_product(data.raw.recipe[recipe_name].expensive, old, new, options) end end @@ -940,7 +1201,6 @@ function replace_product(recipe, old, new, options) if recipe.results then for i, result in pairs(recipe.results) do if result.name == old then result.name = new end - if result[1] == old then result[1] = new end end end end @@ -965,11 +1225,10 @@ end -- Set energy required function util.set_recipe_time(recipe_name, time, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) set_recipe_time(data.raw.recipe[recipe_name], time) - set_recipe_time(data.raw.recipe[recipe_name].normal, time) - set_recipe_time(data.raw.recipe[recipe_name].expensive, time) end end @@ -984,11 +1243,10 @@ end -- Multiply energy required function util.multiply_time(recipe_name, factor, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) multiply_time(data.raw.recipe[recipe_name], factor) - multiply_time(data.raw.recipe[recipe_name].normal, factor) - multiply_time(data.raw.recipe[recipe_name].expensive, factor) end end @@ -1003,11 +1261,10 @@ end -- Add to energy required function util.add_time(recipe_name, amount, options) if not should_force(options) and bypass(recipe_name) then return end - me.add_modified(recipe_name) if data.raw.recipe[recipe_name] then + me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) add_time(data.raw.recipe[recipe_name], amount) - add_time(data.raw.recipe[recipe_name].normal, amount) - add_time(data.raw.recipe[recipe_name].expensive, amount) end end @@ -1024,6 +1281,7 @@ function util.set_category(recipe_name, category, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] and data.raw["recipe-category"][category] then me.add_modified(recipe_name) + prepare_redo_recycling(recipe_name) data.raw.recipe[recipe_name].category = category end end @@ -1068,13 +1326,6 @@ function util.add_icon(recipe_name, icon, options) icon_size=data.raw.item[data.raw.recipe[recipe_name].result].icon_size, icon_mipmaps=data.raw.item[data.raw.recipe[recipe_name].result].icon_mipmaps, }} - elseif data.raw.recipe[recipe_name].normal and - data.raw.item[data.raw.recipe[recipe_name].normal.result] then - data.raw.recipe[recipe_name].icons = {{ - icon=data.raw.item[data.raw.recipe[recipe_name].normal.result].icon, - icon_size=data.raw.item[data.raw.recipe[recipe_name].normal.result].icon_size, - icon_mipmaps=data.raw.item[data.raw.recipe[recipe_name].normal.result].icon_mipmaps, - }} end data.raw.recipe[recipe_name].icon = nil data.raw.recipe[recipe_name].icon_size = nil @@ -1094,6 +1345,17 @@ function util.set_icons(recipe_name, icons, options) end end +-- Set tech icons +function util.set_tech_icons(technology, icons, options) + if not should_force(options) and bypass(technology) then return end + if data.raw.technology[technology] then + me.add_modified(technology) + data.raw.technology[technology].icons = icons + data.raw.technology[technology].icon = nil + data.raw.technology[technology].icon_size = nil + end +end + -- Set recipe icons function util.set_item_icons(item_name, icons) if data.raw.item[item_name] then @@ -1133,12 +1395,32 @@ function util.add_crafting_category(entity_type, entity, category) end end +-- Add crafting category to all entities that have another category +function util.add_crafting_category_if(entity_type, category, other_category) + if data.raw[entity_type] and data.raw["recipe-category"][category] and data.raw["recipe-category"][other_category] then + for _, entity in pairs(data.raw[entity_type]) do + local found_good = false + local found_bad = false + for _, existing in pairs(entity.crafting_categories) do + if existing == other_category then + found_good = true + end + if existing == category then + found_bad = true + end + end + if found_good and not found_bad then + table.insert(entity.crafting_categories, category) + end + end + end +end + + function util.add_to_ingredient(recipe, ingredient, amount, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe] then add_to_ingredient(data.raw.recipe[recipe], ingredient, amount) - add_to_ingredient(data.raw.recipe[recipe].normal, ingredient, amount) - add_to_ingredient(data.raw.recipe[recipe].expensive, ingredient, amount) end end @@ -1161,8 +1443,6 @@ function util.add_to_product(recipe_name, product, amount, options) if not should_force(options) and bypass(recipe_name) then return end if data.raw.recipe[recipe_name] then add_to_product(data.raw.recipe[recipe_name], product, amount) - add_to_product(data.raw.recipe[recipe_name].normal, product, amount) - add_to_product(data.raw.recipe[recipe_name].expensive, product, amount) end end @@ -1176,10 +1456,6 @@ function add_to_product(recipe, product, amount) if result.name == product then result.amount = result.amount + amount return - end - if result[1] == product then - result[2] = result[2] + amount - return end end end @@ -1251,7 +1527,9 @@ function util.create_list() icon = "__core__/graphics/empty.png", icon_size = 1, stack_size = 1, - flags = {"hidden", "hide-from-bonus-gui"} + hidden = true, + hidden_in_factoriopedia = true, + flags = {"hide-from-bonus-gui"} }}) end @@ -1382,4 +1660,61 @@ function util.set_vtk_dcm_ingredients() end end +-- Set correct number of outputs for recyclers +function util.size_recycler_output() + if data.raw.recipe["scrap-recycling"] and data.raw.recipe["scrap-recycling"].results then + for i, entity in pairs(data.raw.furnace) do + if util.contains(entity.crafting_categories, "recycling-or-hand-crafting") then + if entity.result_inventory_size < #data.raw.recipe["scrap-recycling"].results then + entity.result_inventory_size = #data.raw.recipe["scrap-recycling"].results + end + end + end + else + local most = 0 + for i, recipe in pairs(data.raw.recipe) do + if data.raw.recipe.ingredients and #data.raw.recipe.ingredients > most then + most = #data.raw.recipe.ingredients + end + end + for i, entity in pairs(data.raw.furnace) do + if util.contains(entity.crafting_categories, "recycling-or-hand-crafting") then + if entity.result_inventory_size < most then + entity.result_inventory_size = most + end + end + end + end +end + + +-- Save recycling metadata that is later removed by quality mod. Call near end of data.lua +function util.prepare_recycling_helper() + if mods.quality then + for _, recipe in pairs(data.raw.recipe) do + recipe.auto_recycle_helper = recipe.auto_recycle + end + end +end + +-- Recalculate recycling recipes, call near end of data-updates.lua, after calling +-- util.prepare_recycling_helper from data.lua +function util.redo_recycling() + if mods.quality then + local recycling = require("__quality__.prototypes.recycling") + for _, recipe in pairs(data.raw.recipe) do + recipe.auto_recycle = recipe.auto_recycle_helper -- keeping this outside conditional to improve fidelity across multiple mods + if recipe.redo_recycling then + recycling.generate_recycling_recipe(recipe) + end + end + end +end + +-- Preps the recipe to have recycling recalculated. Expects the recipe exists. +function prepare_redo_recycling(recipe_name) + data.raw.recipe[recipe_name].redo_recycling = true +end + + return util