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
end
Code: 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.
end
Code: 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"})