518 lines
17 KiB
Lua
518 lines
17 KiB
Lua
local floor = math.floor
|
|
|
|
local function add_to_description(type, prototype, localised_string)
|
|
if prototype.localised_description and prototype.localised_description ~= '' then
|
|
prototype.localised_description = {'', prototype.localised_description, '\n', localised_string}
|
|
return
|
|
end
|
|
|
|
local place_result = prototype.place_result or prototype.placed_as_equipment_result
|
|
if type == 'item' and place_result then
|
|
for _, machine in pairs(data.raw) do
|
|
machine = machine[place_result]
|
|
if machine and machine.localised_description then
|
|
prototype.localised_description = {
|
|
'?',
|
|
{'', machine.localised_description, '\n', localised_string},
|
|
localised_string
|
|
}
|
|
return
|
|
end
|
|
end
|
|
|
|
local entity_type = prototype.place_result and 'entity' or 'equipment'
|
|
prototype.localised_description = {
|
|
'?',
|
|
{'', {entity_type .. '-description.' .. place_result}, '\n', localised_string},
|
|
{'', {type .. '-description.' .. prototype.name}, '\n', localised_string},
|
|
localised_string
|
|
}
|
|
else
|
|
prototype.localised_description = {
|
|
'?',
|
|
{'', {type .. '-description.' .. prototype.name}, '\n', localised_string},
|
|
localised_string
|
|
}
|
|
end
|
|
end
|
|
|
|
local function contains(tbl, goal, f)
|
|
for _, v in pairs(tbl) do
|
|
if f then
|
|
if f(v) == goal then return true end
|
|
else
|
|
if v == goal then return true end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function localised_string_contains(localised_string, key)
|
|
if type(localised_string) ~= 'table' then
|
|
return false
|
|
end
|
|
if localised_string[1] == key then
|
|
return localised_string[1]
|
|
end
|
|
for k, v in ipairs(localised_string) do
|
|
if k ~= 1 then
|
|
local result = localised_string_contains(v, key)
|
|
if result then return result end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local prefixes = {
|
|
[''] = 1,
|
|
k = 1000,
|
|
K = 1000,
|
|
M = 1000000,
|
|
G = 1000000000,
|
|
T = 1000000000000,
|
|
P = 1000000000000000,
|
|
E = 1000000000000000000,
|
|
Z = 1000000000000000000000,
|
|
Y = 1000000000000000000000000
|
|
}
|
|
local function energy_to_number(energy)
|
|
local amount, unit, _ = string.match(energy, '(%d+)(%a-)[JW]')
|
|
return tonumber(amount) * prefixes[unit]
|
|
end
|
|
|
|
local function map(tbl, f)
|
|
local result = {}
|
|
for k, v in pairs(tbl) do
|
|
result[k] = f(v, k, tbl)
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function localised_string_depth(localised_string)
|
|
if type(localised_string) ~= 'table' then
|
|
return 0
|
|
end
|
|
local result = 0
|
|
for k, v in pairs(localised_string) do
|
|
if k ~= 1 then
|
|
local depth = localised_string_depth(v)
|
|
if depth > result then
|
|
result = depth
|
|
end
|
|
end
|
|
end
|
|
return result + 1
|
|
end
|
|
|
|
-- productivity
|
|
|
|
local recipes = {}
|
|
for module_name, mod in pairs(data.raw.module) do
|
|
if mod.limitation and mod.effect.productivity and module_name:find('pyveganism') == nil then
|
|
for recipe_name, recipe in pairs(data.raw.recipe) do
|
|
if not recipes[recipe_name] and contains(mod.limitation, recipe_name) then
|
|
add_to_description('recipe', recipe, {'description.productivity-message'})
|
|
recipes[recipe_name] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- allowed modules
|
|
|
|
if settings.startup['ed-allowed-modules'].value then
|
|
for _, prototype in ipairs{'lab', 'assembling-machine', 'furnace', 'rocket-silo', 'beacon', 'mining-drill'} do
|
|
for _, machine in pairs(data.raw[prototype]) do
|
|
if (prototype == 'lab' or prototype == 'mining-drill') and machine.allowed_effects == nil then
|
|
machine.allowed_effects = {'speed', 'productivity', 'consumption', 'pollution'}
|
|
end
|
|
|
|
local modules = machine.module_specification
|
|
if modules and tonumber(modules.module_slots) and tonumber(modules.module_slots) > 0 and machine.allowed_effects and machine.allowed_effects ~= {} then
|
|
add_to_description('entity', machine, {'description.module-slots', tostring(machine.module_specification.module_slots)})
|
|
|
|
local allowed
|
|
if type(machine.allowed_effects) == 'string' then
|
|
allowed = {machine.allowed_effects}
|
|
elseif type(machine.allowed_effects) == 'table' then
|
|
allowed = machine.allowed_effects
|
|
end
|
|
|
|
if not contains(allowed, 'speed') then
|
|
add_to_description('entity', machine, {'description.speed-module-limitation'})
|
|
end
|
|
if not contains(allowed, 'productivity') then
|
|
add_to_description('entity', machine, {'description.productivity-module-limitation'})
|
|
end
|
|
if not contains(allowed, 'consumption') then
|
|
add_to_description('entity', machine, {'description.consumption-module-limitation'})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- building size
|
|
|
|
if settings.startup['ed-building-size'].value then
|
|
for _, prototype in pairs(data.raw) do
|
|
for item_name, item in pairs(prototype) do
|
|
if item.stack_size then
|
|
if item.place_result then
|
|
for _, entity in pairs(data.raw) do
|
|
for _, entity in pairs(entity) do
|
|
if entity.minable and entity.minable.result == item_name and (entity.flags == nil or contains(entity.flags, 'placeable-off-grid') == false) then
|
|
local box = entity.collision_box
|
|
if box then
|
|
local x = math.ceil(box[2][2] * 2) / 2 - math.floor(box[1][2] * 2) / 2
|
|
local y = math.ceil(box[2][1] * 2) / 2 - math.floor(box[1][1] * 2) / 2
|
|
if x > 1 or y > 1 then
|
|
if y > x then x, y = y, x end
|
|
add_to_description('entity', entity, {'description.building-size', tostring(x), tostring(y)})
|
|
end
|
|
end
|
|
goto done
|
|
end
|
|
end
|
|
end
|
|
::done::
|
|
end
|
|
else break end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- resistances for military entities
|
|
|
|
if settings.startup['ed-military-resistances'].value then
|
|
for _, prototype in pairs(data.raw) do
|
|
for _, entity in pairs(prototype) do
|
|
if entity.stack_size then break end
|
|
if entity.attack_parameters or (entity.flags and contains(entity.flags, 'placeable-enemy')) then
|
|
entity.hide_resistances = false
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, prototype in ipairs{'wall', 'gate', 'car', 'artillery-wagon'} do
|
|
for _, entity in pairs(data.raw[prototype]) do
|
|
entity.hide_resistances = false
|
|
end
|
|
end
|
|
end
|
|
|
|
-- heat
|
|
|
|
if settings.startup['ed-heat'].value then
|
|
for _, name in ipairs{'reactor', 'heat-pipe'} do
|
|
for _, prototype in pairs(data.raw[name]) do
|
|
local buffer = prototype.heat_buffer
|
|
add_to_description('entity', prototype, {'description.max-heat', buffer.max_temperature})
|
|
add_to_description('entity', prototype, {(name == 'reactor') and 'description.heat-loss-reactor' or 'description.heat-loss-pipe', buffer.min_temperature_gradient or 1})
|
|
end
|
|
end
|
|
end
|
|
|
|
-- solar ratios
|
|
|
|
if settings.startup['ed-solar-ratios'].value then
|
|
for _, prototype in ipairs{'accumulator', 'solar-panel'} do
|
|
for name, machine in pairs(data.raw[prototype]) do
|
|
for _, item in pairs(data.raw.item) do
|
|
if item.place_result == name then
|
|
item.localised_description = item.localised_description or machine.localised_description or ''
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local empty_table = function() return {} end
|
|
local accumulators_perfect = map(data.raw.accumulator, empty_table)
|
|
local accumulators_imperfect = map(data.raw.accumulator, empty_table)
|
|
local solar_panels_perfect = map(data.raw['solar-panel'], empty_table)
|
|
local solar_panels_imperfect = map(data.raw['solar-panel'], empty_table)
|
|
|
|
local accumulator_count = 0
|
|
local solar_count = 0
|
|
|
|
for _, _ in pairs(data.raw['solar-panel']) do
|
|
solar_count = solar_count + 1
|
|
end
|
|
|
|
for accumulator_name, accumulator in pairs(data.raw.accumulator) do
|
|
accumulator_count = accumulator_count + 1
|
|
local accumulator_localised_name = accumulator.localised_name or {'entity-name.' .. accumulator_name}
|
|
local accumulator_size = accumulator.energy_source.buffer_capacity
|
|
|
|
if accumulator_size == '1J' then goto a end
|
|
|
|
for solar_name, solar in pairs(data.raw['solar-panel']) do
|
|
local solar_localised_name = solar.localised_name or {'entity-name.' .. solar_name}
|
|
local panel_production = solar.production
|
|
|
|
if panel_production == '1W' then goto s end
|
|
|
|
local ratio = energy_to_number(panel_production) / energy_to_number(accumulator_size) * 70
|
|
|
|
local integer = math.floor(ratio)
|
|
local decimal = ratio - integer
|
|
local pn, n, N = 0, 1
|
|
local pd, d, D = 1, 0
|
|
local x, perfect, q, Q
|
|
repeat
|
|
x = x and 1 / (x - q) or decimal
|
|
q, Q = math.floor(x), math.floor(x + 0.5)
|
|
pn, n, N = n, q * n + pn, Q * n + pn
|
|
pd, d, D = d, q * d + pd, Q * d + pd
|
|
perfect = decimal - N/D
|
|
until math.abs(perfect) < 0.00000001
|
|
perfect = perfect == 0
|
|
|
|
if perfect then
|
|
local accumulator_ratio = N + D * integer
|
|
local solar_ratio = D
|
|
table.insert(accumulators_perfect[accumulator_name], {'description.solar-ratio', solar_localised_name, accumulator_ratio, solar_ratio})
|
|
table.insert(solar_panels_perfect[solar_name], {'description.solar-ratio', accumulator_localised_name, solar_ratio, accumulator_ratio})
|
|
else
|
|
table.insert(accumulators_imperfect[accumulator_name], {'description.solar-ratio-imperfect', solar_localised_name , math.floor(0.5 + ratio * 1000) / 1000})
|
|
table.insert(solar_panels_imperfect[solar_name], {'description.solar-ratio-imperfect', accumulator_localised_name, math.floor(0.5 + 1 / ratio * 1000) / 1000})
|
|
end
|
|
::s::
|
|
end
|
|
::a::
|
|
end
|
|
|
|
for name, accumulator in pairs(data.raw.accumulator) do
|
|
if solar_count + localised_string_depth(accumulator.localised_description) > 18 then goto next end
|
|
for _, perfect in pairs(accumulators_perfect[name]) do
|
|
add_to_description('entity', accumulator, perfect)
|
|
end
|
|
for _, perfect in pairs(accumulators_imperfect[name]) do
|
|
add_to_description('entity', accumulator, perfect)
|
|
end
|
|
::next::
|
|
end
|
|
|
|
for name, solar in pairs(data.raw['solar-panel']) do
|
|
if accumulator_count + localised_string_depth(solar.localised_description) > 18 then goto next end
|
|
for _, perfect in pairs(solar_panels_perfect[name]) do
|
|
add_to_description('entity', solar, perfect)
|
|
end
|
|
for _, perfect in pairs(solar_panels_imperfect[name]) do
|
|
add_to_description('entity', solar, perfect)
|
|
end
|
|
::next::
|
|
end
|
|
end
|
|
|
|
-- radar range
|
|
|
|
if settings.startup['ed-radar-stats'].value then
|
|
for _, radar in pairs(data.raw.radar) do
|
|
add_to_description('entity', radar, {'description.radar-primary-range', radar.max_distance_of_nearby_sector_revealed})
|
|
add_to_description('entity', radar, {'description.radar-secondary-range', radar.max_distance_of_sector_revealed})
|
|
add_to_description('entity', radar, {'description.radar-scan-time', math.floor(0.5 + energy_to_number(radar.energy_per_sector) / energy_to_number(radar.energy_usage) * 100) / 100})
|
|
end
|
|
end
|
|
|
|
-- inserters
|
|
|
|
if settings.startup['ed-inserter-stats'].value then
|
|
local inserter_stack_size = 1
|
|
local stack_inserter_stack_size = 1
|
|
|
|
for _, technology in pairs(data.raw.technology) do
|
|
if technology.hidden ~= true and technology.enabled ~= false and technology.effects then
|
|
for _, effect in ipairs(technology.effects) do
|
|
if effect.type == 'inserter-stack-size-bonus' then
|
|
inserter_stack_size = inserter_stack_size + effect.modifier
|
|
elseif effect.type == 'stack-inserter-capacity-bonus' then
|
|
stack_inserter_stack_size = stack_inserter_stack_size + effect.modifier
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local fastest_belt
|
|
local slowest_belt
|
|
for _, belt in pairs(data.raw['transport-belt']) do
|
|
local speed = belt.speed * 480
|
|
if 0 < speed and speed < 200 then
|
|
if fastest_belt == nil or speed > fastest_belt then
|
|
fastest_belt = speed
|
|
end
|
|
if slowest_belt == nil or speed < slowest_belt then
|
|
slowest_belt = speed
|
|
end
|
|
end
|
|
end
|
|
|
|
for inserter_name, inserter in pairs(data.raw.inserter) do
|
|
local multiplier_1 = inserter.stack and 2 or 1
|
|
local multiplier_2 = inserter.stack and stack_inserter_stack_size or inserter_stack_size
|
|
local hand_speed = inserter.rotation_speed * 57.75
|
|
for _, item in pairs(data.raw.item) do
|
|
if item.place_result == inserter_name then
|
|
item.localised_description = item.localised_description or inserter.localised_description or ''
|
|
end
|
|
end
|
|
add_to_description('entity', inserter, {
|
|
'',
|
|
{'description.inserter-speed'},
|
|
{'description.inserter-speed-chest-to-chest'},
|
|
{'description.inserter-stack-size', multiplier_1, math.floor(0.5 + hand_speed * multiplier_1 * 100) / 100},
|
|
{'description.inserter-stack-size', multiplier_2, math.floor(0.5 + hand_speed * multiplier_2 * 100) / 100},
|
|
{'description.inserter-speed-chest-to-belt'},
|
|
{'description.inserter-stack-size', multiplier_1, math.floor(0.5 + 1 / (1 / hand_speed / multiplier_1 + 0.0445272463 * multiplier_1 / slowest_belt) * 100) / 100},
|
|
{'description.inserter-belt-speed', slowest_belt},
|
|
'\n',
|
|
{'description.inserter-stack-size', multiplier_2, math.floor(0.5 + 1 / (1 / hand_speed / multiplier_2 + 0.0445272463 * multiplier_2 / fastest_belt) * 100) / 100},
|
|
{'description.inserter-belt-speed', fastest_belt},
|
|
'\n',
|
|
{'description.inserter-speed-belt-to-chest'},
|
|
{'description.inserter-stack-size-guess', multiplier_1, math.floor(0.5 + 1 / (1 / hand_speed / multiplier_1 + 0.055 * multiplier_1 / slowest_belt) * 10) / 10},
|
|
{'description.inserter-belt-speed', slowest_belt},
|
|
'\n',
|
|
{'description.inserter-stack-size-guess', multiplier_2, math.floor(0.5 + 1 / (1 / hand_speed / multiplier_2 + 0.055 * multiplier_2 / fastest_belt) * 10) / 10},
|
|
{'description.inserter-belt-speed', fastest_belt},
|
|
})
|
|
end
|
|
end
|
|
|
|
-- SE build restrictions
|
|
|
|
if mods['space-exploration'] then
|
|
for _, building in pairs(data.raw) do
|
|
for _, building in pairs(building) do
|
|
if building.localised_description then
|
|
local placement = localised_string_contains(building.localised_description, 'placement_restriction_line')
|
|
if placement then
|
|
add_to_description('entity', building, placement)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- tank size and pressure
|
|
|
|
if settings.startup['ed-tank-size'].value then
|
|
for prototype_name, tank in pairs(data.raw) do
|
|
for tank_name, tank in pairs(tank) do
|
|
local box = tank.fluid_box
|
|
if box then
|
|
if tank.minable then
|
|
local size = (box.height or 1) * (box.base_area or 1)
|
|
local pressure = (box.height or 1) + (box.base_level or 0)
|
|
|
|
if prototype_name ~= 'storage-tank' or pressure ~= 1 then
|
|
add_to_description('entity', tank, {'description.tank-size', size * 100})
|
|
add_to_description('entity', tank, {'description.pressure', pressure * 100})
|
|
end
|
|
end
|
|
else break end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- fluid colors
|
|
|
|
if settings.startup['ed-fluid-colors'].value then
|
|
local function interpret_color(color)
|
|
local r = color.r or color[1] or 0
|
|
local g = color.g or color[2] or 0
|
|
local b = color.b or color[3] or 0
|
|
local a = color.a or color[4] or 1
|
|
|
|
if r <= 1 and g <= 1 and b <= 1 and a <= 1 then
|
|
r = r * 255
|
|
g = g * 255
|
|
b = b * 255
|
|
end
|
|
|
|
return '[color=' .. tostring(floor(r)) .. ',' .. tostring(floor(g)) .. ',' .. tostring(floor(b)) .. '] ■[/color]'
|
|
end
|
|
|
|
for _, fluid in pairs(data.raw.fluid) do
|
|
if fluid.localised_name and fluid.localised_name ~= '' then
|
|
fluid.localised_name = {'', fluid.localised_name, interpret_color(fluid.base_color)}
|
|
else
|
|
fluid.localised_name = {'', {'fluid-name.' .. fluid.name}, interpret_color(fluid.base_color)}
|
|
end
|
|
end
|
|
end
|
|
|
|
-- deadlock stacking & item stack sizes
|
|
|
|
for _, prototype in pairs(data.raw) do
|
|
for item_name, item in pairs(prototype) do
|
|
if item.stack_size and not item_name:find('^big%-data%-') then
|
|
add_to_description('item', item, {'description.stack-size', tostring(item.stack_size)})
|
|
|
|
if mods['deadlock-beltboxes-loaders'] and data.raw.item['deadlock-stack-' .. item_name] then
|
|
add_to_description('item', item, {'description.stackable'})
|
|
end
|
|
else break end
|
|
end
|
|
end
|
|
|
|
-- voiding
|
|
|
|
if settings.startup['ed-voiding'].value then
|
|
local void_categories = {
|
|
['incineration'] = {'incinerator', 'electric-incinerator'},
|
|
['fuel-incineration'] = {'electric-incinerator'},
|
|
['flaring'] = {'vent-stack', 'flare-stack'},
|
|
['py-incineration'] = {'py-burner'},
|
|
['py-venting'] = {'py-gas-vent'},
|
|
['py-runoff'] = {'py-sinkhole'},
|
|
['angels-chemical-void'] = {'angels-flare-stack'},
|
|
['angels-water-void'] = {'clarifier'}
|
|
}
|
|
|
|
for _, recipe in pairs(data.raw.recipe) do
|
|
if recipe.category and void_categories[recipe.category] then
|
|
recipe.always_show_products = true
|
|
|
|
local difficulty = recipe.normal or recipe.expensive or recipe
|
|
local ingredient = difficulty.ingredients[1]
|
|
|
|
if ingredient == nil then break end
|
|
|
|
if ingredient[1] then
|
|
ingredient = {type = 'item', name = ingredient[1], amount = ingredient[2]}
|
|
end
|
|
|
|
local target
|
|
local target_type = 'item'
|
|
if ingredient.type == 'item' then
|
|
for _, prototype in pairs(data.raw) do
|
|
for _, item in pairs(prototype) do
|
|
if item.stack_size and prototype[ingredient.name] then
|
|
target = prototype[ingredient.name]
|
|
goto done
|
|
end
|
|
break
|
|
end
|
|
end
|
|
::done::
|
|
elseif ingredient.type == 'fluid' then
|
|
target = data.raw.fluid[ingredient.name]
|
|
target_type = 'fluid'
|
|
end
|
|
|
|
for _, machine in ipairs(void_categories[recipe.category]) do
|
|
machine = data.raw.furnace[machine] or data.raw['assembling-machine'][machine]
|
|
if machine then
|
|
add_to_description(target_type, target, {
|
|
'description.voidable',
|
|
machine.localised_name or {'entity-name.' .. machine.name},
|
|
math.floor(0.5 + ingredient.amount / (difficulty.energy_required or 0.5) * 100) / 100
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|