Scripted GUI modding

From Hearts of Iron 4 Wiki
Jump to navigation Jump to search

Scripted GUIs are a very powerful feature that allow modders to implement custom GUI interfaces and logic.


Scripted GUIs are placed in /Hearts of Iron IV/common/scripted_guis/.

Here is a general overview of each of the elements within a scripted gui:

scripted_gui = {
    <name> = {
        window_name = <string>
        context_type = <type>
        parent_window_token = <string>
        visible = {
        effects = {
            <element>_click = {
            <element>_<modifier>_click = {
        triggers = {
            <element>_click_enabled = {
            <element>_visible = {
        properties = {
            <element> = {
                image = <string>
                frame = <var>
                x = <var>
                y = <var>
        ai_enabled = {
        ai_test_parent = <string>
        ai_test_interval = <int>
        ai_test_variance = <float>
        ai_test_scopes = <type>
        ai_check = {
        ai_check_scope = {
        ai_max_weight_taken_per_test = <int>
        ai_weights = {
            <element>_<modifiers>_click = {
                ai_will_do = {
                    base = <int>
                    factor = <float>
                    add = <float>
                    modifier = {
                        factor = <float>
                        add = <float>
                ignore_lower_weights = {
                    factor = <float>

Window Name[edit]

Defines the interface container the scripted GUI uses.

The referenced interface container should be of the type containerWindowType.

The scripted GUI creates an instance of the specified container and its elements for each valid user of the scripted GUI.

Parent Window Token[edit]

Defines which existing window the scripted GUI interface should be attached to. This is optional, by default a scripted GUI interface will appear anywhere whilst its visible scope is valid.

The following tokens can be used:

  • top_bar
  • decision_tab
  • technology_tab
  • trade_tab
  • construction_tab
  • production_tab
  • deployment_tab
  • logistics_tab
  • diplomacy_tab (only when no country is selected)
  • politics_tab
  • tech_infantry_folder
  • tech_support_folder
  • tech_armor_folder
  • tech_artillery_folder
  • tech_land_doctrine_folder
  • tech_naval_folder
  • tech_naval_doctrine_folder
  • tech_air_techs_folder
  • tech_air_doctrine_folder
  • tech_electronics_folder
  • tech_industry_folder
  • national_focus

You can specifiy the exact window name (i.e. tech_tree_my_modded_tree) if none of the tokens above are suitable. If using this method, you must use parent_window_name instead of parent_window_token.

Using the selected_state_view or selected_country_view contexts will scope to the last selected country or state when used with these windows.

Context Type[edit]

Defines the context of the GUI, i.e. what scope the GUI operates on.

The options are:

  • player_context
  • selected_country_context
  • selected_state_context
  • decision_category

Player context makes the GUI context that of the country that GUI is displayed for. This means the default scope is the country using the GUI.

Selected country context makes the GUI context that of the currently selected country (i.e. clicked on). This means the default scope is the selected country, and ROOT is the country using the GUI.

Selected state context makes the GUI context that of the currently selected state (i.e. clicked on). This means the default scope is the selected state, and ROOT is the country using the GUI.

Decision category makes the GUI context that of the country that GUI is displayed for. This is the only scope that can be implemented into decision categories, like the congress system for USA.

When using the selected contexts, it is important to remember that the default scope is that of the selected type, and not the country using the GUI itself, meaning you need to explicitly scope to ROOT when dealing with said country.


Defines when the scripted GUI is visible for the current scope.

Note that the scripted GUI has to be visible for the AI if it is to use it.


Defines what effects should be attached to button elements within the interface. <element> should be the name of the element.

There are additional modifiers added before the click suffix that alter the type of click recognized. These are fairly obvious to understand, and can be chained.


  • right
  • alt
  • control
  • shift

For example: my_button_alt_right_click = { }


Defines when interface elements are usable or visible. By default elements are clickable and visible.

<element>_<modifiers>_click_enabled evaluates when the specified element should be clickable.

Note that <element>_click_enabled overrides the specific triggers such as <element>_right_click_enabled.

<element>_visible evaluates when the specified element should be visible. This can be used for any interface element, such as icons and text.

Note that if an element is not visible, the AI will be unable to click on it as well.


Properties allow for specified elements to be manipulated whilst in-game, allowing for their texture and position to be changed.

Properties support manipulating the frame of a texture directly with the frame attribute, which changes the frame to the value given by a specified variable.

Likewise, properties support manipulating the x and y co-oordinates for an element, with the x and y attributes which changes the element position to the value given by a specified variable.

The image attribute determines the texture used:

properties = {
    my_icon = {
        image = "GFX_my_texture"

This would assign an icon element with the name of my_icon with a texture GFX_my_texture.

At first glance this may seem useless, but the power here is that the string accepts scripted localization. This means you can create a scripted localization entry that supplies the texture string.

properties = {
    my_icon = {
        image = "[get_my_icon_texture]"
defined_text = {
    name = get_my_icon_texture
    text = {
        trigger = {
        localization_key = "GFX_my_texture_1"
    text = {
        trigger = {
        localization_key = "GFX_my_texture_2"

This is an example of using scripted localization to supply the property with the texture string.

Note you can also refer to the exact frame within the string, like so:

text = {
    localization_key = "GFX_my_texture:4"


The true usefulness of scripted GUIs is that they can be used by the AI, meaning new features can be properly implemented with custom interfaces that the AI can navigate.

AI enabled[edit]

The first step is to determine when the AI is enabled for the GUI.

ai_enabled = {

This scope is checked during initialization, and any AI that fail are never checked again.

This is the best optimization, as it means invalid AIs will never be checked again, but it is only checked once.

AI Test Attributes[edit]

These attributes determine when the AI checks the scripted GUI.

ai_test_interval determines how often the AI checks, in hours. ai_test_variance determines the variance in time for the check, which is the specified variance divided by 2 for plus and minus.

AI Check[edit]

This scope is checked on every tick of the interval specified by ai_test_interval. If it evaluates as false, the AI will ignore the GUI for the tick.

AI Test Scopes[edit]

The AI needs to be told who it should target when using scripted GUIs. You can imagine this as the AI clicking on the countries or states.

You can specify nothing, but this will result in the AI checking every possible country or state, which will harm performance, and so should be avoided unless required.

For player_context and decision_category, ai_test_scopes is not needed as the only checked scope is the country using the GUI.

For selected_country_context the AI will check every country in the world by default. By specifying an ai_test_scopes, the AI will be limited to the specified range of countries.

The tokens for selected_country_context:

  • test_self_country
  • test_enemy_countries
  • test_ally_countries
  • test_neighbouring_countries
  • test_neighbouring_ally_countries
  • test_neighbouring_enemy_countries

You can combined multiple ai_test_scopes by adding multiple to the definition.

For selected_state_context the AI will check every state in the world by default. By specifying an ai_test_scopes, the AI will be limited to the specified range of states.

The tokens for selected_state_context:

  • test_self_owned_states
  • test_enemy_owned_states
  • test_ally_owned_states
  • test_self_controlled_states
  • test_enemy_controlled_states
  • test_ally_controlled_states
  • test_neighbouring_states
  • test_neighbouring_enemy_states
  • test_neighbouring_ally_states
  • test_our_neighbouring_states - AIs edge states
  • test_our_neighbouring_states_against_allies - AIs edge states to allies
  • test_our_neighbouring_states_against_enemies - AIs edge states to enemies
  • test_contesded_states - states that shares provinces between enemy countries

You can combined multiple ai_test_scopes by adding multiple to the definition.

You can define test_if_only_major which will limit the other scopes to only major countries or states owned by them.

You can define test_if_only_coastal which will limit the other scopes to only coastal countries or states.

AI Check Scope[edit]

Now the AI knows what to target, it is possible to filter these with triggers.

ai_check_scope = {

AI Weights[edit]

The AI also needs to be told how to handle the actual clickable elements within the GUI. This happens with the ai_weights scope.

You add an entry for the element and define a set of factors within the ai_will_do scope.

You can use factor or add, although only one should be present in the same scope.

Whilst the weight for an element is above 0, the AI will attempt to click it.

By default, the AI will only select one element per tick, clicking the element with the highest score. To allow the AI to click more than one element, specify ai_max_weight_taken_per_test = <int>, which sets the maximum number of actions the AI will take.

By default each action has an AI weight of 1. You can define a higher cost by adding the weight attribute to the ai_will_do.

The ignore_lower_weights attribute is added to the ai_will_do scope to tell the AI to ignore every action below the specified weight whilst its factor is above 0.

This allows the AI to ignore other actions as it may need to save a resource to take the action. Without this, the AI would take another action that may take the same resource and so would never take the first action, even when the factor is higher, as it would never save enough resource to take it.

AI Parents[edit]

You can define an AI parent that means the AI for different scripted GUIs is processed together. This is useful if different GUIs may use resources that another would depelete, and so by processing the AI together, the actions can be properly limited.

Scripted Localization[edit]

There is a special localization command that allows a scripted GUI element to display its effect within a tooltip.


For example:

MY_TOOLTIP: "[!test_button_click]"


You can use the console command human_ai to enable AI for the current human country. This writes the AI checks and the results of said checks to the scripted_ai.log.

Event targets CANNOT be used in scripted GUIs, it will break everything. Make use of variable scopes instead.

Scripted effects and triggers can be used in scripted GUIs, and can be useful to seperate the GUI logic and the gameplay logic.

Enable Debug mode by adding -debug to your launch options in Steam. Not only this mode will give you access to error logs, you can also use Control + Alt + Right Click combination to open a debug menu which can be used for access the gui file that you hover on. By default this will open the file in notepad. Following lines can be added to settings.txt under \Documents\Paradox Interactive\Hearts of Iron IV\ to use your favorite editor. (Replace the path with your actual exe path if it differs)

For Notepad++

editor="C:\\Program Files\\Notepad++\\notepad++.exe"
editor_postfix=" -n$"

For Sublime

editor="C:\\Program Files\\Sublime Text 3\\sublime_text.exe"