219 lines
9.8 KiB
Lua

--[[ Copyright (c) 2017 Optera
* Part of Lighted Electric Poles +
*
* See LICENSE.md in the project directory for license information.
--]]
local format = string.format
local gmatch = string.gmatch
local flib = require('__flib__.data-util')
local light_scale = settings.startup["lepp_light_size_factor"].value
local light_size_limit = settings.startup["lepp_light_max_size"].value
local lep_icons_layer = { { icon = "__LightedPolesPlus__/graphics/icons/lighted.png", icon_size = 32, tint = {r=1, g=1, b=1, a=0.85} } }
local pole_entity_whitelist = {}
for name in gmatch(settings.startup["lepp_pole_whitelist"].value, '([^, *]+)') do
pole_entity_whitelist[name] = true
end
local pole_entity_blacklist = {}
for name in gmatch(settings.startup["lepp_pole_blacklist"].value, '([^, *]+)') do
pole_entity_blacklist[name] = true
end
local tech_blacklist = {}
for name in gmatch(settings.startup["lepp_tech_blacklist"].value, '([^, *]+)') do
tech_blacklist[name] = true
end
local fallback_technology = settings.startup["lepp_tech_fallback"].value
local pole_names = {} -- dictionary [original pole item name] -> lighted pole entity/item/recipe name
local lightedPoles = {}
-- finds all recipes by result
function find_recipe_by_results(search_products)
local found_recipes = {} -- recipes producing the product
for _, recipe in pairs (data.raw["recipe"]) do
if recipe.result and search_products[recipe.result] then
found_recipes[recipe.name] = {product=recipe.result, subgroup=recipe.subgroup, order=recipe.order}
end
if recipe.normal and recipe.normal.result and search_products[recipe.normal.result] then
found_recipes[recipe.name] = {product=recipe.normal.result, subgroup=recipe.subgroup, order=recipe.order}
end
if recipe.expensive and recipe.expensive.result and search_products[recipe.expensive.result] then
found_recipes[recipe.name] = {product=recipe.expensive.result, subgroup=recipe.subgroup, order=recipe.order}
end
if recipe.results then
for _, r in pairs(recipe.results) do
if type(r) == "table" and (not r.type or r.type == "item")
and (r.name and search_products[r.name] or search_products[r[1]]) then
found_recipes[recipe.name] = {product=r.name or r[1], subgroup=recipe.subgroup, order=recipe.order}
end
end
end
if recipe.normal and recipe.normal.results then
for _, r in pairs(recipe.normal.results) do
if type(r) == "table" and (not r.type or r.type == "item")
and (r.name and search_products[r.name] or search_products[r[1]]) then
found_recipes[recipe.name] = {product=r.name or r[1], subgroup=recipe.subgroup, order=recipe.order}
end
end
end
if recipe.expensive and recipe.expensive.results then
for _, r in pairs(recipe.expensive.results) do
if type(r) == "table" and (not r.type or r.type == "item")
and (r.name and search_products[r.name] or search_products[r[1]]) then
found_recipes[recipe.name] = {product=r.name or r[1], subgroup=recipe.subgroup, order=recipe.order}
end
end
end
end
return found_recipes
end
-- look through items for electric-poles should save looking through recipes and entities
for _, item in pairs (data.raw["item"]) do
-- look through all item.place_result in case item and recipe names don't match entity name
if item.place_result and data.raw["electric-pole"][item.place_result] and not pole_entity_blacklist[item.place_result] then
-- log("[LEP+] found pole "..item.place_result.." in item "..item.name)
local pole = data.raw["electric-pole"][item.place_result]
if pole_entity_whitelist[item.place_result] -- include if whitelisted
or (pole.draw_copper_wires ~= false -- exclude poles without copper wire connection
and pole.maximum_wire_distance and pole.maximum_wire_distance > 0 -- exclude poles with no wire reach
and pole.minable and pole.minable.result and pole.minable.result == item.name) then
pole.fast_replaceable_group = pole.fast_replaceable_group or "electric-pole"
local newName = "lighted-"..pole.name
-- log("[LEP+] copying entity "..tostring(pole.name).." to "..tostring(newName))
local newPole = flib.copy_prototype(pole, newName, true)
newPole.icons = flib.create_icons(pole, lep_icons_layer) or lep_icons_layer
newPole.localised_name = {"entity-name.lighted-pole", {"entity-name." .. pole.name}}
if newPole.next_upgrade then
newPole.next_upgrade = "lighted-"..newPole.next_upgrade
end
-- log("[LEP+] copying item "..tostring(item.name).." to "..tostring(newName))
pole_names[item.name] = newName --save name for technology lookup
local newItem = flib.copy_prototype(item, newName, true)
newItem.icons = flib.create_icons(item, lep_icons_layer) or lep_icons_layer
newItem.localised_name = newPole.localised_name
newItem.order = (item.order or "").."-0"
newPole.icons = newPole.icons or newItem.icons -- use item icon for lighted pole in case base pole entity had none
local hidden_lamp = flib.copy_prototype(data.raw["lamp"]["small-lamp"], newName.."-lamp", true)
hidden_lamp.icons = newPole.icons
hidden_lamp.localised_name = newPole.localised_name
hidden_lamp.minable = nil
hidden_lamp.next_upgrade = nil
hidden_lamp.flags = {"not-blueprintable", "not-deconstructable", "placeable-off-grid", "not-on-map"}
hidden_lamp.selectable_in_game = false
hidden_lamp.collision_box = {{-0.1, -0.1}, {0.1, 0.1}}
hidden_lamp.selection_box = {{-0.4, -0.4}, {0.4, 0.4}}
hidden_lamp.collision_mask = { "resource-layer" }
hidden_lamp.picture_off =
{
filename = "__core__/graphics/empty.png",
priority = "high",
width = 1,
height = 1,
frame_count = 1,
axially_symmetrical = false,
direction_count = 1,
}
hidden_lamp.picture_on =
{
filename = "__core__/graphics/empty.png",
priority = "high",
width = 1,
height = 1,
frame_count = 1,
axially_symmetrical = false,
direction_count = 1,
}
local lamp_count = 1
local light_size = 40 --small lamp default
hidden_lamp.light = {intensity = 0.9, size = light_size, color = {r=1.0, g=1.0, b=1.0}}
hidden_lamp.light_when_colored = {intensity = 1, size = light_size * 0.15, color = {r=1.0, g=1.0, b=1.0}}
hidden_lamp.energy_usage_per_tick = "5kW"
if light_scale > 0 then
light_size = math.floor(math.sqrt(newPole.maximum_wire_distance)*(40/math.sqrt(7.5))*light_scale+0.5) -- scale to small lamp radius on small poles
if light_size > light_size_limit then light_size = light_size_limit end
lamp_count = math.ceil(light_size / 40)
hidden_lamp.light = {intensity = 0.9, size = light_size, color = {r=1.0, g=1.0, b=1.0}}
hidden_lamp.light_when_colored = {intensity = 1, size = light_size * 0.15, color = {r=1.0, g=1.0, b=1.0}}
hidden_lamp.energy_usage_per_tick = light_size * 0.125 .."kW"
end
log("[LEP+] Created "..newName.."; light size = "..light_size)
local newRecipe =
{
type = "recipe",
name = newName,
enabled = "false",
ingredients =
{
{item.name, 1},
{"small-lamp", lamp_count}
},
result = newName
}
-- find original recipe so new recipe can be sorted next to it
local recipes = find_recipe_by_results({[item.name] = true})
for k,v in pairs(recipes) do
if v.subgroup then newRecipe.subgroup = v.subgroup end
if v.order then newRecipe.order = v.order.."-0" end
log(format("[LEP+] sorting new recipe according to recipe \"%s\" subgroup= \"%s\" order= \"%s\"", k, v.subgroup, v.order) )
break -- pick first recipe
end
-- temporary store generated pole, will be added to data after generation is complete
table.insert(lightedPoles, newPole)
table.insert(lightedPoles, newItem)
table.insert(lightedPoles, hidden_lamp)
table.insert(lightedPoles, newRecipe)
end
end
end
data:extend(lightedPoles)
local recipe_lookup = find_recipe_by_results(pole_names)
local techs_found = {}
-- add to technology
for _, tech in pairs(data.raw["technology"]) do
if tech.effects and not tech_blacklist[tech.name] then
for _, effect in pairs(tech.effects) do
if effect.recipe and recipe_lookup[effect.recipe] then
local base_item = recipe_lookup[effect.recipe].product
if not (techs_found[base_item] and techs_found[base_item][tech.name]) then
-- don't insert multiple times in same technology (nullius)
log("[LEP+] found original pole "..base_item.." in technology "..tech.name..", inserting "..pole_names[base_item].." into technology "..tech.name)
table.insert(data.raw["technology"][tech.name].effects, {type="unlock-recipe",recipe=pole_names[base_item]})
-- multiple techs may unlock the same recipe
techs_found[base_item] = techs_found[base_item] or {}
techs_found[base_item][tech.name] = true
end
end
end
end
end
-- add unassigned recipes to fallback technology (optics)
local tech = data.raw.technology[fallback_technology]
if tech then
for original_pole, lighted_pole in pairs(pole_names) do
if not techs_found[original_pole] then
if tech.effects then
log("[LEP+] no technology unlock found for "..original_pole..", inserting "..lighted_pole.." into technology "..tech.name)
table.insert(tech.effects, {type="unlock-recipe", recipe=lighted_pole})
else
log("[LEP+] no technology unlock found for "..original_pole..", creating new effects table for "..lighted_pole.." in technology "..tech.name)
tech.effects = {type="unlock-recipe", recipe=lighted_pole}
end
end
end
else
error("[LEP+] ERROR: Technology "..fallback_technology.." not found")
end