In this entire section, we’ll have many specific terms to cover, concepts to digest, things like that. I think the first big question to answer is – what is UI, and what is UI modding.
UI and UI Modding
UI stands for “User Interface”, for those out of the know. It’s basically the collection of everything the user can interact with while playing a game. Buttons, unit cards, maps, pop-ups, and much else all tie into UI. The usage of UI is wildly varied – you can cause various things to change upon interacting with interfaces, you can highlight or move things on the screen, so much more.
UI modding is anything that affects the user interface, simply enough. If you add a button, or make a new panel, or create new tooltips – that’s UI modding. As mentioned previously, it’s primarily done via Lua, so Lua skills are expected.
The largest concept to understand is a base game object – UI Components, heretofore known as “UIC”. A UIC is a script interface – similar to the script interfaces for factions, characters, regions, etc., – but they’re attached directly to the state of some object in the UI. A UIC could be a button, or it could be some text, or it could be a tooltip.
The main difference between UICs methods, and methods of other script interfaces, is the fact that UICs have methods to get details, and set details. Whereas in WH2, all script interfaces have only getter methods – like
character:region() – and in 3K, script interfaces are divided into getter objects – a query interface – and into setter objects – a modify interface, a UIC is composed of both getters and setters. So with one method, you might read the UIC’s position or width, and with another method you might set them.
Children of the Root
The second largest concept to understand for UICs – parenthood.
Every UIC is the “child” of another, with one exception – the root component. All of the UI in any situation is built upon the UI root, which is the UIC that has no parent (poor guy), and from which all other UICs are descended. You can get the UI root by using
core:get_ui_root(), which returns the root UIC.
Since every UIC is a descendant of the root, every UIC can be tracked and found from their path to the root. As an example, the path to the top bar, which holds treasury/effects/pooled resources, is found at the following path:
"root" -> "layout" -> "resources_bar" -> "topbar_list_parent"
Which means, basically: the UIC with the ID ‘topbar_list_parent’ is a child of ‘resources_bar’, which is a child of ‘layout’, which is a child of the root component.
Parents are very definitive of UICs. The parent of a UIC can define a lot of properties for a UIC. For instance, the order in which components go on the top bar pointed above is decided by the order of the topbar’s children. The topbar’s first child is the treasury holder – which is the first component from left to right! The very last child in this instance is the final effect visible.
Another reason why parentage is important – moving a parent component moves all of its children. The position of a parent will wholly decide the location and of a child. As well, many parent components have defined bounds – when a child goes past those bounds, it becomes invisible, due to some various details defined on the parent that I don’t have time to explain here.
The main usage of parentage, though, is to find UICs. Let’s look at our first bit of code!
The first main function we will use for UI modding is
find_uicomponent(). It takes an initial argument of a starting UIC, and all following arguments are the ID’s of the children in the path you want to check. So, for instance, if we want to grab the UIC object of the topbar, we would use the following code:
local root = core:get_ui_root() local topbar = find_uicomponent(root, "layout", "resouces_bar", "topbar_list_parent")
Note that I had to use
core:get_ui_root() to get the UIC object.
find_uicomponent() needs a starting UIC to begin searching from. The above function grabs the root, and then checks all its direct children for a component called “layout”, and then checks that child for a component called “resources_bar”, and then finally checks its children for “topbar_list_parent”.
At this point, you’re likely wondering – “how the heck do I find out the paths for these UICs?!?”. Great question, words I just typed out. Amazing how you anticipated the next step of the tutorial!
The Power of Clicking
There’s two more fun functions we’re going to learn today. The first you don’t actually have to call anywhere, because CA calls it for us. It’s
output_uicomponent_on_click(). What it does is – when you click a UIC, it outputs data about that UIC. Pretty cool. Among other things, it prints out the UICs location, its width/height, and its path from root.
Gasp! Maybe THAT’S how you find out the paths!
In order to find out paths for various UICs, you have to make sure script debugging is activated (use the script debug activator mod!), and then just like, click on stuff. Go try this out now!
Note: You have to actually call output_uicomponent_on_click() if you’re testing this out in battle or in the frontend. Just add a .lua file in script/battle/mod or script/frontend/mod, with just that one statement.
The Power of Printing
Alright, you’ve now got a bunch of paths. Let’s pick one in particular, and we’re going to use our final function for the day –
print_all_uicomponent_children(uic). All you have to do is provide it a single arg – the UIC of which you want to print children – and it will go ahead and print all the paths to the various children of that UIC.
Go ahead and try this out now. I’d recommend using the DevTool Console, for easier testing in-game. Try this out for a few UICs, see what happens when you mess up, find some minor issues here and there if you can.
This first tutorial is super small and basic, but that’s because we need to understand various very important concepts before going on. With all this known, we’re ready to get into some new and custom stuff. Next tutorial, we’re going to be learning how to create our first hand-made UIC, and we’ll click it, and it’ll do stuff. That’s right – A BUTTON.