--- a/more-descriptions/data-final-fixes.lua Sat Jul 05 00:35:55 2025 +0300 +++ b/more-descriptions/data-final-fixes.lua Wed Jul 23 14:46:54 2025 +0300 @@ -1,21 +1,65 @@ +---@type data.FeatureFlags +feature_flags = feature_flags + local function seconds(x) return {"time-symbol-seconds", tostring(x)} end -local function build_new_description(main_description, new_descriptions) - local new_localised_description = { - "", - main_description, - } - for i, k in pairs(new_descriptions) +local energy_zero_table = { + ["0W"] = 1, + ["0kW"] = 1, + ["0MW"] = 1, + ["0GW"] = 1, + ["0TW"] = 1, +} + +---@type table<string, 1> +local recipes_that_have_productivity_research = {} + +for _, technology in pairs(data.raw["technology"] or {}) +do + for _, effect in pairs(technology.effects or {}) do - if i ~= 1 + if effect.type == "change-recipe-productivity" then - table.insert(new_localised_description, "\n") + recipes_that_have_productivity_research[effect.recipe] = 1 end - table.insert(new_localised_description, k) end - return new_localised_description +end + +---@param x string +local function energy_zero(x) + return x == nil or energy_zero_table[x] +end + +---@param x LocalisedString +-- localised string containing too many entries? snap it into many pieces and catenate them +local function snap(x) + if type(x) == "table" and #x > 20 and x[1] == "" + then + local max_per_part = math.ceil((#x - 1) / 18) + local result = {""} + local segment = {""} + for k, v in pairs(x) + do + if k > 1 + then + if #segment >= max_per_part + 1 + then + table.insert(result, snap(segment)) + segment = {""} + end + table.insert(segment, v) + end + end + if #segment > 1 + then + table.insert(result, snap(segment)) + end + return result + else + return x + end end local item_categories = @@ -173,6 +217,26 @@ "solar-panel", } +-- Find all entity categories that contain prototypes that can freeze. +-- If a prototype in such a category cannot freeze, that's worth pointing out. +-- However, it's not worth pointing out that the steel chest cannot freeze, +-- since no container freezes (in vanilla anyway). +local freezable_entity_categories = {} +if feature_flags.freezing +then + for _, category in pairs(entity_categories) + do + for _, entity in pairs(data.raw[category] or {}) + do + if not energy_zero(entity.heating_energy) + then + freezable_entity_categories[entity.type] = 1 + break + end + end + end +end + local function find_entity(name) for _, entity_category in pairs(entity_categories) do @@ -184,6 +248,7 @@ return nil end +-- @type table<string, string> local ammo_categories = {} for _, ammo in pairs(data.raw.ammo) @@ -199,29 +264,43 @@ then ammo_categories[ammo.ammo_category] = ammo_categories[ammo.ammo_category] .. "..." end +end + +---@param proto data.Prototype +---@param tooltip_field LocalisedString +local function generic_add_description(proto, tooltip_field) + if not proto.custom_tooltip_fields + then + proto.custom_tooltip_fields = {} + end + table.insert(proto.custom_tooltip_fields, tooltip_field) end for _, item_type in pairs(item_categories) do for _, item in pairs(data.raw[item_type] or {}) do - local new_descriptions = {} local recycling_recipe = data.raw.recipe[item.name.."-recycling"] - local add_description = function(x) - table.insert(new_descriptions, x) + ---@param tooltip_field data.CustomTooltipField + local function add_description(tooltip_field) + generic_add_description(item, tooltip_field) end local add_ammo_from_attack_parameters = function(attack_parameters) if attack_parameters.ammo_category and ammo_categories[attack_parameters.ammo_category] then - add_description{"more-descriptions-mod.gun-accepts-ammo", ammo_categories[attack_parameters.ammo_category]} + add_description{ + name = {"more-descriptions-mod.gun-accepts-ammo"}, + value = ammo_categories[attack_parameters.ammo_category]} end for _, category in pairs(attack_parameters.ammo_categories or {}) do if ammo_categories[category] then - add_description{"more-descriptions-mod.gun-accepts-ammo", ammo_categories[category]} + add_description{ + name = {"more-descriptions-mod.gun-accepts-ammo"}, + value = ammo_categories[category]} end end end @@ -234,9 +313,12 @@ table.insert(recycling_results, "[img="..result.type.."."..result.name.."]") end add_description{ - "more-descriptions-mod.recycling", - seconds(recycling_recipe.energy_required), - recycling_results + name = {"more-descriptions-mod.recycling"}, + value = { + "more-descriptions-mod.recycling-results", + seconds(recycling_recipe.energy_required), + snap(recycling_results), + }, } end @@ -246,31 +328,39 @@ if refining_recipe ~= nil then add_description{ - "more-descriptions-mod.refining-cost", - tostring(refining_recipe.energy_required), + name = {"more-descriptions-mod.refining-cost"}, + value = seconds(refining_recipe.energy_required), } elseif recycling_recipe ~= nil then - add_description{"more-descriptions-mod.cannot-be-refined"} + add_description{ + name = {"more-descriptions-mod.cannot-be-refined"}, + value = ""} end end if item.type == "ammo" and (item.reload_time or 0) > 0 then add_description{ - "more-descriptions-mod.reload-time", - seconds(tostring(item.reload_time / 60.0)), + name = {"more-descriptions-mod.reload-time"}, + value = seconds(tostring(item.reload_time / 60.0)), } end if item.type == "active-defense-equipment" and item.automatic then - add_description{"more-descriptions-mod.fires-automatically"} + add_description{ + name = {"more-descriptions-mod.fires-automatically"}, + value = "", + } end if item.type == "armor" and item.provides_flight then - add_description{"more-descriptions-mod.armor-provides-flight"} + add_description{ + name = {"more-descriptions-mod.armor-provides-flight"}, + value = "", + } end if item.type == "gun" @@ -287,36 +377,66 @@ local width = math.ceil(cb[2][1] - cb[1][1]) local height = math.ceil(cb[2][2] - cb[1][2]) add_description{ - "more-descriptions-mod.size", - tostring(width), - tostring(height), + name = {"more-descriptions-mod.entity-size"}, + value = { + "more-descriptions-mod.size", + tostring(width), + tostring(height), + }, } end if entity.drops_full_belt_stacks then - add_description{"more-descriptions-mod.drops-full-belt-stacks"} + add_description{ + name = {"more-descriptions-mod.drops-full-belt-stacks"}, + value = ""} end if entity.heat_buffer and entity.heat_buffer.specific_heat then add_description{ - "more-descriptions-mod.specific-heat", - entity.heat_buffer.specific_heat, + name = {"more-descriptions-mod.specific-heat"}, + value = { + "more-descriptions-mod.energy-per-degrees-celsius", + entity.heat_buffer.specific_heat, + }, } elseif entity.energy_source and entity.energy_source.type == "heat" and entity.energy_source.specific_heat then add_description{ - "more-descriptions-mod.specific-heat", - entity.energy_source.specific_heat, + name = {"more-descriptions-mod.specific-heat"}, + value = entity.energy_source.specific_heat, } end if entity.is_military_target then - add_description{"more-descriptions-mod.is-military-target"} + add_description{ + name = {"more-descriptions-mod.is-military-target"}, + value = "", + } + end + + if not energy_zero(entity.heating_energy or "0W") + then + local value = entity.heating_energy + if entity.type == "underground-belt" or entity.type == "pipe-to-ground" + then + value = {"more-descriptions-mod.value-per-end", value} + end + add_description{ + name = {"more-descriptions-mod.heating-energy"}, + value = value, + } + elseif freezable_entity_categories[entity.type] + then + add_description{ + name = {"more-descriptions-mod.no-heating-energy"}, + value = "", + } end if entity.type == "agricultural-tower" @@ -328,30 +448,45 @@ local z = (2 * w * math.ceil((W - w) / 2 / w)) + w -- num of growth cells extending from the edges of the tower local r = math.floor(entity.radius) -- why is it double..? - add_description{"more-descriptions-mod.agricultural-tower-num-inputs", - tostring(entity.input_inventory_size) + add_description{ + name = {"more-descriptions-mod.agricultural-tower-num-inputs"}, + value = tostring(entity.input_inventory_size) } - add_description{"more-descriptions-mod.agricultural-tower-growth-cell-size", - tostring(w) + add_description{ + name = {"more-descriptions-mod.agricultural-tower-growth-cell-size"}, + value = { + "more-descriptions-mod.size", + tostring(w), + tostring(w), + } } - add_description{"more-descriptions-mod.agricultural-tower-growth-cell-count", - tostring(4 * r * (r + (z / w))) + add_description{ + name = {"more-descriptions-mod.agricultural-tower-growth-cell-count"}, + value = tostring(4 * r * (r + (z / w))) } - add_description{"more-descriptions-mod.agricultural-tower-total-size", - tostring(z + 2 * r * w) + total_size = tostring(z + 2 * r * w) + add_description{ + name = {"more-descriptions-mod.agricultural-tower-total-size"}, + value = { + "more-descriptions-mod.size", + total_size, + total_size, + }, } elseif entity.type == "ammo-turret" then if entity.energy_per_shot ~= nil then - add_description{"more-descriptions-mod.energy-per-shot-fired", - entity.energy_per_shot} + add_description{ + name = {"more-descriptions-mod.energy-per-shot-fired"}, + value = entity.energy_per_shot} end add_ammo_from_attack_parameters(entity.attack_parameters) elseif entity.type == "beacon" then - add_description{"more-descriptions-mod.beacon-supply-area-distance", - tostring(entity.supply_area_distance) + add_description{ + name = {"more-descriptions-mod.beacon-supply-area-distance"}, + value = tostring(entity.supply_area_distance) } elseif entity.type == "car" then @@ -370,109 +505,159 @@ end if immunities ~= "" then - add_description{"more-descriptions-mod.car-immune-to-impacts", immunities} + add_description{ + name = {"more-descriptions-mod.car-immune-to-impacts"},value = immunities} end elseif entity.type == "constant-combinator" then -- used by pushbutton mod if (entity.pulse_duration or 0) > 60 then - add_description{"more-descriptions-mod.constant-combinator-pulse-duration", - seconds(entity.pulse_duration / 60.0)} + add_description{ + name = {"more-descriptions-mod.constant-combinator-pulse-duration"}, + value = seconds(entity.pulse_duration / 60.0), + } elseif (entity.pulse_duration or 0) > 0 then - add_description{"more-descriptions-mod.constant-combinator-pulse-duration", - {"more-descriptions-mod.ticks", tostring(entity.pulse_duration)}} + add_description{ + name = {"more-descriptions-mod.constant-combinator-pulse-duration"}, + value = { + "more-descriptions-mod.ticks", + tostring(entity.pulse_duration), + }, + } end elseif (entity.type == "container" or entity.type == "logistic-container") then if entity.inventory_type == "with_filters_and_bar" then - add_description{"more-descriptions-mod.container-filters"} + add_description{ + name = {"more-descriptions-mod.container-filters"}, + value = "", + } end elseif entity.type == "cargo-wagon" then -- all cargo wagons support filters - add_description{"more-descriptions-mod.container-filters"} + add_description{ + name = {"more-descriptions-mod.container-filters"}, + value = "", + } elseif entity.type == "display-panel" then - add_description{"more-descriptions-mod.display-panel-max-text-width", - tostring(entity.max_text_width or 400)} + add_description{ + name = {"more-descriptions-mod.display-panel-max-text-width"}, + value = tostring(entity.max_text_width or 400), + } elseif entity.type == "logistic-robot" or entity.type == "construction-robot" then if entity.speed_multiplier_when_out_of_energy > 0 then - add_description{"more-descriptions-mod.robot-speed-multiplier-when-out-of-energy", - tostring(entity.speed_multiplier_when_out_of_energy * 100)} + add_description{ + name = {"more-descriptions-mod.robot-speed-multiplier-when-out-of-energy"}, + value = tostring(entity.speed_multiplier_when_out_of_energy * 100), + } else - add_description{"more-descriptions-mod.robot-crashes-when-out-of-energy"} + add_description{ + name = {"more-descriptions-mod.robot-crashes-when-out-of-energy"}, + value = "", + } end elseif entity.type == "inserter" then + if entity.bulk + then + add_description{ + name = {"more-descriptions-mod.inserter-bulk"}, + value = tostring(entity.filter_count), + } + end if entity.wait_for_full_hand then - add_description{"more-descriptions-mod.inserter-wait-for-full-hand", - tostring(entity.filter_count)} + add_description{ + name = {"more-descriptions-mod.inserter-wait-for-full-hand"}, + value = "", + } + end + if entity.enter_drop_mode_if_held_stack_spoiled + then + add_description{ + name = {"more-descriptions-mod.inserter-enters-drop-mode-if-held-stack-spoils"}, + value = "", + } end elseif entity.type == "land-mine" then - add_description{"more-descriptions-mod.land-mine-timeout", - seconds((entity.timeout or 120) / 60.0)} + add_description{ + name = {"more-descriptions-mod.land-mine-timeout"}, + value = seconds((entity.timeout or 120) / 60.0), + } elseif entity.type == "radar" then if entity.connects_to_other_radars ~= false then - add_description{"more-descriptions-mod.radar-connection"} + add_description{ + name = {"more-descriptions-mod.radar-connection"}, + value = "", + } end end if entity.filter_count then - add_description{"more-descriptions-mod.filter-count", - tostring(entity.filter_count)} + add_description{ + name = {"more-descriptions-mod.filter-count"}, + value = tostring(entity.filter_count), + } end for _, flag in pairs(entity.flags or {}) do if flag == "no-automated-item-insertion" then - table.insert(new_descriptions, {"more-descriptions-mod.no-automated-item-insertion"}) + add_description{ + name = {"more-descriptions-mod.no-automated-item-insertion"}, + value = "", + } end end end - - if #new_descriptions > 0 - then - local main_description = item.localised_description - and {"", item.localised_description, "\n"} - or { - "?", - {"", {"entity-description."..item.name}, "\n"}, - {"", {"item-description."..item.name}, "\n"}, - "" - } - item.localised_description = build_new_description(main_description, new_descriptions) - end end end for _, recipe in pairs(data.raw.recipe) do - local new_descriptions = {} - + ---@param tooltip_field data.CustomTooltipField + local function add_description(tooltip_field) + generic_add_description(recipe, tooltip_field) + end if recipe.allow_productivity then - table.insert(new_descriptions, {"more-descriptions-mod.allows-productivity"}) + add_description{ + name = {"more-descriptions-mod.allows-productivity"}, + value = "", + } end - if #new_descriptions > 0 + if recipes_that_have_productivity_research[recipe.name] + then + add_description{ + name = {"more-descriptions-mod.recipe-has-productivity-research"}, + value = "", + } + end + + if recipe.result_is_always_fresh then - local main_description = recipe.localised_description - and {"", recipe.localised_description, "\n"} - or { - "?", - {"", {"recipe-description."..recipe.name}, "\n"}, - "" + add_description{ + name = {"more-descriptions-mod.recipe-result-is-always-fresh"}, + value = "", } - recipe.localised_description = build_new_description(main_description, new_descriptions) + end + if recipe.reset_freshness_on_craft + then + add_description{ + name = {"more-descriptions-mod.recipe-result-freshness-reset"}, + value = "", + } end end @@ -481,19 +666,27 @@ do for _, entity in pairs(data.raw[entity_category] or {}) do - local new_descriptions = {} + ---@param tooltip_field data.CustomTooltipField + local function add_description(tooltip_field) + generic_add_description(entity, tooltip_field) + end if entity.minable then - table.insert(new_descriptions, {"more-descriptions-mod.mining-time", - seconds(entity.minable.mining_time)}) + add_description{ + name = {"more-descriptions-mod.mining-time"}, + value = seconds(entity.minable.mining_time), + } end for _, flag in pairs(entity.flags or {}) do if flag == "breaths-air" then - table.insert(new_descriptions, {"more-descriptions-mod.breathes-air"}) + add_description{ + name = {"more-descriptions-mod.breathes-air"}, + value = "", + } end end @@ -501,48 +694,41 @@ then if (entity.time_to_capture or 0) > 0 then - table.insert(new_descriptions, {"more-descriptions-mod.unit-spawner-time-to-capture", - seconds(entity.time_to_capture / 60.0)}) + add_description{ + name = {"more-descriptions-mod.unit-spawner-time-to-capture"}, + value = seconds(entity.time_to_capture / 60.0), + } end end - - if #new_descriptions > 0 - then - local main_description = entity.localised_description - and {"", entity.localised_description, "\n"} - or { - "?", - {"", {"entity-description."..entity.name}, "\n"}, - "" - } - entity.localised_description = build_new_description(main_description, new_descriptions) - end end end -for _, space_location in pairs(data.raw["space-location"]) -do - local new_descriptions = {} - - if (space_location.fly_condition or false) - then - table.insert(new_descriptions, {"more-descriptions-mod.space-location-fly-condition"}) - end - - if space_location.auto_save_on_first_trip == false -- (nil=true) - then - table.insert(new_descriptions, {"more-descriptions-mod.space-location-no-autosave"}) - end - - if #new_descriptions > 0 - then - local main_description = space_location.localised_description - and {"", space_location.localised_description, "\n"} - or { - "?", - {"", {"space-location-description."..space_location.name}, "\n"}, - "" - } - space_location.localised_description = build_new_description(main_description, new_descriptions) +if feature_flags.space_travel +then + for _, category in pairs{"space-location", "planet"} + do + for _, space_location in pairs(data.raw[category]) + do + ---@param tooltip_field data.CustomTooltipField + local function add_description(tooltip_field) + generic_add_description(space_location, tooltip_field) + end + ---@cast space_location data.SpaceLocationPrototype + local new_descriptions = {} + if (space_location.fly_condition or false) + then + add_description{ + name = {"more-descriptions-mod.space-location-fly-condition"}, + value = "", + } + end + if space_location.auto_save_on_first_trip == false -- (nil=true) + then + add_description{ + name = {"more-descriptions-mod.space-location-no-autosave"}, + value = "", + } + end + end end end \ No newline at end of file