fusion-lab/control.lua

Wed, 27 Aug 2025 10:26:12 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Wed, 27 Aug 2025 10:26:12 +0300
changeset 19
adbc5c74f279
parent 10
101603241531
permissions
-rw-r--r--

Lots of stuff

---@class FusionLabStorageData
---@field heat_interface LuaEntity heat buffer shadowing this entity

---@class FusionLabStorage
---@field fusion_labs table<LuaEntity, FusionLabStorageData>?
storage = {}

---@param heat_interface LuaEntity
local function init_heat_interface(heat_interface)
	heat_interface.custom_status = {diode=defines.entity_status_diode.green, label={"entity-status.normal"}}
end

local function init_storage()
	if storage.fusion_labs == nil
	then
		storage.fusion_labs = {}
		local num_labs = 0
		for _, surface in pairs(game.surfaces)
		do
			for _, lab in pairs(surface.find_entities_filtered{name="fusion-lab"})
			do
				if lab.valid
				then
				num_labs = num_labs + 1
					local heat_interfaces = surface.find_entities_filtered{
						name='fusion-lab-heat-interface',
						position=lab.position,
						limit = 1,
					}
					local heat_interface
					if #heat_interfaces == 0
					then
						heat_interfaces = {lab.surface.create_entity{
							name='fusion-lab-heat-interface',
							position=lab.position,
							force=lab.force,
						}}
						heat_interfaces[1].temperature = 15
						heat_interfaces[1].destructible = false
						heat_interfaces[1].active = false
						init_heat_interface(heat_interfaces[1])
					end
					storage.fusion_labs[lab] = {
						heat_interface = heat_interfaces[1],
					}
				end
			end
		end
	end
end

local function cleanup_labs()
	local new_storage_fusion_labs = {}
	for lab, lab_info in pairs(storage.fusion_labs or {})
	do
		if lab.valid
		then
			new_storage_fusion_labs[lab] = lab_info
		end
	end
	storage.fusion_labs = new_storage_fusion_labs
end

script.on_nth_tick(31, function(event)
	init_storage()
	local need_cleanup = false
	for lab, lab_info in pairs(storage.fusion_labs or {})
	do
		if not lab.valid
		then
			need_cleanup = true
		elseif lab.status == defines.entity_status.working
		then
			local heat_interface = lab_info.heat_interface

			if not heat_interface.valid
			then
				-- (╯°□°)╯︵ ┻━┻
				game.print("[Fusion lab] Heat interface data corrupt, rebuilding")
				storage.fusion_labs = nil
				init_storage()
				return
			end

			lab.minable = (heat_interface.temperature <= 900)
			-- A cryogenic plant cooling hot fluoroketone voids 1320kW
			-- of heat energy, so the fusion lab with no modules just happens
			-- to conveniently radiate exactly half of that energy rate.
			--
			-- The 0.341 here is 31/60*0.66 = 0.341 degrees of heat increase
			-- every 31 ticks, for 0.66 ℃/sec. it's written out as 0.341 to
			-- avoid potential floating point rounding errors.
			heat_interface.temperature = heat_interface.temperature + (1 + lab.consumption_bonus) * 0.341
			if heat_interface.temperature > 600
			then
				lab.surface.create_entity{
					name = 'fusion-lab-smoke-source',
					position={lab.position.x + 3.5 * (math.random() - 0.5), lab.position.y + 3.5 * (math.random() - 0.5)},
					force=lab.force,
				}
			end
			if heat_interface.temperature > 710.0
			then
				lab.surface.create_entity{
					name = 'crash-site-fire-flame',
					position={lab.position.x + 3.5 * (math.random() - 0.5), lab.position.y + 3.5 * (math.random() - 0.5)},
					force=game.forces.neutral,
				}
			end
		end
	end
	if need_cleanup
	then
		cleanup_labs()
	end
	for _, player in pairs(game.players)
	do
		if player.gui.relative.fusion_lab_gui and player.opened and player.opened.name == "fusion-lab"
		then
			for lab, lab_info in pairs(storage.fusion_labs)
			do
				if lab == player.opened
				then
					local heat_interface = lab_info.heat_interface
					local gui = player.gui.relative.fusion_lab_gui
					gui.heat.value = heat_interface.temperature / 700
					gui.heat.caption = {"format-degrees", string.format("%.2f", heat_interface.temperature)}
				end
			end
		end
	end
end)

script.on_event(defines.events.on_entity_died, function(event)
	local lab = event.entity
	event.entity.force = game.forces.neutral
	-- we can't rely on storage here; search for the heat interface on the map
	local heat_interfaces = lab.surface.find_entities_filtered{
		name = 'fusion-lab-heat-interface',
		position = lab.position,
		limit = 1,
	}
	if #heat_interfaces > 0
	then
		local heat_interface = heat_interfaces[1]
		if heat_interface.temperature > 700
		then
			for _, ofs in pairs{
				{0, 0},
				{5, 0},
				{-5, 0},
				{0, 5},
				{0, -5},
				{1.5, 1.5},
				{-1.5, 1.5},
				{-1.5, -1.5},
				{1.5, -1.5}}
			do
				local pos = {
					x = lab.position.x + ofs[1],
					y = lab.position.y + ofs[2]}
				lab.surface.create_entity{
					name = 'artillery-projectile',
					position = pos,
					target = pos,
					force = game.forces.neutral,
					cause = event.entity,
				}
			end
		end
		heat_interface.destroy()
	end
end, {{filter="name", name="fusion-lab"}})

---@param event EventData
local function on_fusion_lab_mined(event)
	init_storage()
	local entity = event.entity ---@type LuaEntity
	for _, heat_interface in pairs(entity.surface.find_entities_filtered{
			name='fusion-lab-heat-interface',
			position = entity.position
		})
	do
		heat_interface.destroy()
	end
end

local function on_fusion_lab_built(event)
	init_storage()
	local lab = event.entity
	heat_interface = lab.surface.create_entity{
		name='fusion-lab-heat-interface',
		position=lab.position,
		force=lab.force,
	}
	heat_interface.temperature = 15
	heat_interface.destructible = false
	heat_interface.active = false
	storage.fusion_labs[lab] = {heat_interface = heat_interface}
end

script.on_event(defines.events.on_player_mined_entity, on_fusion_lab_mined, {{filter="name", name="fusion-lab"}})
script.on_event(defines.events.on_robot_mined_entity, on_fusion_lab_mined, {{filter="name", name="fusion-lab"}})
script.on_event(defines.events.on_space_platform_mined_entity, on_fusion_lab_mined, {{filter="name", name="fusion-lab"}})
script.on_event(defines.events.on_built_entity, on_fusion_lab_built, {{filter="name", name="fusion-lab"}})
script.on_event(defines.events.on_robot_built_entity, on_fusion_lab_built, {{filter="name", name="fusion-lab"}})
script.on_event(defines.events.on_space_platform_built_entity, on_fusion_lab_built, {{filter="name", name="fusion-lab"}})

mercurial