In Factorio all entity UI's are read-only. If you want to modify a UI you have to completely recreate it and its logic. However, another option exists where you leave the UI alone and add your own UI around it. That's the approach discussed here and it's much easier.
The code is not laid out in order. If you're new to programming the events go at the bottom. The UI function goes at the top and I put the destroy function under that.
Control.lua
First we need to hook the gui_opened event and check that it's the right entity. In-this case: ammo-turret.
Code: Select all
script.on_event(defines.events.on_gui_opened,function(event)
  if event.entity == nil then return end
  if event.entity.type == 'ammo-turret' then
    local player = game.players[event.player_index] --Find the player that opened the UI
    turret1_ui(player,event.entity) -- Run our "create gui" method
  end
  end)
  Code: Select all
  script.on_event(defines.events.on_gui_closed,function(event)
  if event.entity == nil then return end
  if event.entity.type == 'ammo-turret' then
    local player = game.players[event.player_index] --Find the player that closed the UI
    turret1_ui_hide(player) -- Run our "destroy gui" method
  end
  end)Code: Select all
	function turret1_ui_hide(ply)
	if ply == nil then return end
		local player_gui = ply.gui.center
		if not player_gui.turret_wrap then --If for some reason this method is called but the UI does not exist, we return to avoid throwing a nil pointer except (Shout-out to since deceased Java language).
		return  
		end
		
		player_gui.turret_wrap.destroy() --Removes the UI
	endCode: Select all
script.on_event(defines.events.on_gui_click, function(event)
  if event.element.name == "button_upgrade1" then --If they interacted with our button
	local player = game.players[event.player_index]
	local turret = player.opened
    if player.get_main_inventory().get_item_count("coin") >= 1000 then -- and If they have enough coins
		player.remove_item{name="coin", count=1000} --remove the coins
		--Then do stuff here
		return
	end
  end
  -- Add in more elements here by copying the above and pasting it here changing element.name to whatever your elements are named.
endCode: Select all
function turret1_ui(ply, ent)
		local player_gui = ply.gui.center -- Get the center GUI of player
		if player_gui.turret_wrap ~= nil then -- If the UI already exists then return cause we don't want multiple.
			
			return
		end
		
		
		player_gui.add({ type="frame", name="turret_wrap", direction="horizontal", style="turretgui"}) --add a frame
		player_gui.turret_wrap.add({ type="frame", name="button_f", direction="vertical"})
		player_gui.turret_wrap.add({ type="flow", name="textFlow", direction="vertical", style="textlabel_flow"}) -add a flow for proper layout
		if ent.name == "turret1" then -- If you have multiple entities you can use this a bunch of times to create a dynamic UI between entities. Or if you're only doing this once you can create all the UI you need
			player_gui.turret_wrap.button_f.add({ type="sprite-button", tooltip="Upgrade to Cobalt Turret 2k\n\n"..stats1, name="button_upgrade1", sprite="upgradebuttonimg", clicked_sprite="upgradebuttonimg_click", style="turretgui_button"}) -- Button name="" corresponds to our method that detects if the button was pressed.
			player_gui.turret_wrap.textFlow.add({ type="label", name="label1a", caption="Health: 400"})
			player_gui.turret_wrap.textFlow.add({ type="label", name="label1b", caption="Range: 18"})
			player_gui.turret_wrap.textFlow.add({ type="label", name="label1c", caption="Shooting Speed: 7.5/s"})
			player_gui.turret_wrap.textFlow.add({ type="label", name="label1d", caption="Damage bonus: 0%"})
		end
end
data.lua: require("prototypes.style")
prototypes/style.lua:
Every array here requires type and parent. Everything else is optional. Note that parent isn't really the parent. It's just the element you're applying it to. If you want to style a button then the parent is button. If you want to style a frame then the parent is frame. Normally you can guess the type by adding "_style" as a suffix to the UI element you're editing (ex. frame_style). I believe width and height are alternate names to minimum_width and minimum_height. Don't forget to restart the game after each edit. Other guides will have more advanced styling but most of them are outdated making it difficult to figure out whats relevant today.
See style specification: https://wiki.factorio.com/Types/StyleSpecification
Code: Select all
gui = data.raw["gui-style"].default --A mod can only call data.raw["gui-style"].default once.
	gui["turretgui"] = { --This 'turretgui' name reflects the style in control.lua (style="turretgui"
  type = "frame_style",
  parent = "frame",
  left_margin = 850,
  bottom_margin = 95,
  minimum_height = 250
}
	gui["turretgui_button"] = {
  type = "button_style",
  parent = "button",
  width = 64,
  height = 64,
  top_margin = 11
}
	gui["textlabel_flow"] = { --Note that vertical_flow_style and its parent "vertical_flow"
  type = "vertical_flow_style",
  parent = "vertical_flow",
  left_margin = 10
}
All of the sprite-button guides are outdated. This is how to add a sprite to a sprite-button
Code: Select all
data:extend({
	{
		type = "sprite",
		name = "upgradebuttonimg", --Name this whatever you want
		width = "64",
		height = "64",
		filename = "__Amod__/resource/upgrade.png"
	},
	{
		type = "sprite",
		name = "upgradebuttonimg_click", -- If you add _click and _hover to them it makes it easier to distinguish between them.
		width = "64",
		height = "64",
		filename = "__Amod__/resource/upgrade_click.png"
	}
})
Code: Select all
player_gui.turret_wrap.button_f.add({ type="sprite-button", tooltip="Upgrade to Cobalt Turret 2k\n\n"..stats1, name="button_upgrade1", sprite="upgradebuttonimg", clicked_sprite="upgradebuttonimg_click", style="turretgui_button"})

