blackninja9939

Experienced Programmer - Crusader Kings 3
77 Badges
Aug 28, 2013
2.367
6.117
  • Crusader Kings III
  • Stellaris: Federations
  • Battle for Bosporus
  • Stellaris: Nemesis
  • Stellaris: Necroids
  • Europa Universalis IV
  • Crusader Kings III: Royal Edition
  • Europa Universalis 4: Emperor
  • Crusader Kings II
  • Crusader Kings II: Holy Fury
  • Imperator: Rome - Magna Graecia
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Europa Universalis IV: Rights of Man
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Synthetic Dawn
  • Surviving Mars
  • BATTLETECH
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Monks and Mystics
  • Tyranny: Archon Edition
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: Reapers Due
  • Hearts of Iron IV: Colonel
  • Stellaris Sign-up
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Lithoids
  • Stellaris: Distant Stars
  • Europa Universalis IV: Dharma
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Prison Architect
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Age of Wonders: Planetfall
  • Crusader Kings II: Conclave
  • Crusader Kings II: The Republic
  • Victoria 2
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Crusader Kings II: Way of Life
  • Stellaris
  • Mount & Blade: Warband
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
What is Jomini?

Jomini is a shared library for our grand strategy games, it exists as a mid layer between the project and Clausewitz engine.
The goal is to move lots of the duplicated code we had in all our grand strategy games into Jomini so instead of copy pasting features all the time, we can just reuse them and also add improvements and bug fixed which the other projects can benefit from.

This is NOT the thread to be asking game level questions in.
If you have a question about pops, characters or trade etc. then that is a game specific thing not something in Jomini so should not be asked about here.


Jomini is not just scripting stuff (despite however much I pretend), it also contains:
  • Gamestate
  • Achievements
  • Coat of Arms/Shield
  • Save Games
  • Multiplayer
  • Map & Editor
  • And more
Script Features in Jomini

Over the past year we’ve moved a lot of features into Jomini so they are shared, a fair few are just miscellaneous code improvements but we also have a lot of new features we can consistently use on the projects now, a not complete list of which I’ll cover some of them:
  • Scope Types
  • Event Targets
  • Saved Scopes
  • Script Lists
  • Saved Lists
  • Variables
  • Script Values
  • Comparisons
  • Scripted Triggers and Effects
  • Scripted Modifiers
  • Scripted Lists
  • Events
  • Dynamic Descriptions
  • On Actions
  • Trigger and Effect Descriptions
All things Scopes

Event Targets


The idea of scope types and switching between them is in Jomini, the current Jomini scope types are: no scope, bool, value, color and flag. Yes numbers and bools etc. are a scope type, it has its pros and cons. We refer to these scope types as primitive scopes due to their basic nature and generally not having an object attached to it just the raw ID.
Every event or interaction has a “top scope” which stores root, saved scopes and local variables.

Event Targets are how we 1-1 switch between scope objects, they are comprised of one or more “links” separated by dots. Eg: root.mother.father
As they are separated by dots they can be used in one line so you can do
set_character_religion = root.father.mother.religion
A link can have multiple input types to lead to one output type, allowing polymorphic links that can do more than one thing! So “culture” can move from a province, character, country, pop etc. to their religion.

A scope object can be saved with an arbitrary name to reference later on in the top scope, in our older games these were called event targets. The name was changed as internally both were called event targets and one is shorter to type for script. Eg:
Code:
father = { save_scope_as = cool_person }
scope:cool_person = { kill_painfully = yes }

Comparing Scopes

Gone are the days of needing things like father = { character = root.mother.father } as a condition to see if two characters are the same.
Now we can just do father = root.mother.father, this works for any event target so you can compare things very simply.

This also works in conjunction with comparison triggers which are treated as a special link, all comparison triggers can be used at the end of an event target to get its value with relation to the last link eg: root.mother.mother.prominence will return root's grandmother’s prominence.
So now we can easily compare two values by doing things like root.loyalty > mother.prominence to check if root has more loyalty than their mother does prominence.
This can also be used in effects to do mother = { add_loyalty = root.prominence } which adds loyalty to root's mother equal to root’s prominence.

For numeric comparisons we have all comparison operators available: >, <, >=, <=, =, !=

Some examples based Old system vs the Jomini system:
Old:
Code:
event_target:target = {
    mother = {
        root = {
            character = prev
        }
    }
}

Jomini:
Code:
root = scope:target.mother

Old:
Code:
root = {
    export_to_variable = {
        which = my_loyalty
        value = loyalty
    }
}
mother = {
    export_to_variable = {
        which = my_prominence
        value = prominence
    }
}
if = {
    limit = {
        root = {
            check_variable = {
                which = my_loyalty
                which = my_prominence
                which = mother
            }
        }
    }
}

Jomini:
Code:
root.loyalty > mother.prominence

Script Lists

Script lists are how we move from one scope to one or more from a list of similar objects. Eg: any_sibling

With the new system we internally only register the list builder such as sibling, the code then automatically makes the various versions for the script.
Currently we have four versions created: any_, every_, random_ and ordered_
The first three should be recognisable, but they’ve all been extended with new functionality
  • Any: Is a trigger that returns true if any of the list meet certain conditions, can have an optional count or percent parameter to indicate X many or Y percent of the list must meet the conditions
  • Every: Runs effects on all members of the list if they meet certain conditions. Can have multiple alternative_limits for backup conditions if the previous set was not met.
  • Random: Runs effects one one member of the list if they meet certain conditions. Can also have alternative_limits as well as a weight to influence which random object to run effects on.
  • Ordered: Runs effect on the entry in a list based on position or range of positions. The list can be ordered by anything such as loyalty or gold. Can have a limit and alternative_limits on it to filter members of the list.

An example of finding someone with the highest value in old script vs Jomini:
Old:
Code:
every_family_member = {
    export_to_variable = {
        which = my_loyalty
        value = loyalty
    }
}
random_family_member = {
    save_event_target_as = highest_loyalty
}
while = {
    limit = {
        any_family_member = {
            check_variable = {
                which = my_loyalty
                which = my_loyalty
                which = event_target:highest_loyalty
            }
        }
    }
    random_family_member = {
        limit = {
            check_variable = {
                which = my_loyalty
                which = my_loyalty
                which = event_target:highest_loyalty
            }
        }
        save_event_target_as = highest_loyalty
    }
}
every_family_member = {
    remove_variable = my_loyalty
}
event_target:highest_loyalty = {
    add_prominence = 20
}

Jomini:
Code:
ordered_family_member = {
    order_by = loyalty
    position = 0
    add_prominence = 20
}

Script Values

Shock and horror, we can now actually do maths in the scripting language!
With a new system for Jomini any trigger and effect that can take a value can now also take a script value which come in three forms:
  • Simple Values
  • Ranges
  • Formulas
Simple named values are just a static look up, you define the a name and it is given an associated value eg: medium_gold_cost = 50. Wherever you type medium_gold_cost it will treat it as 50! Really useful for balancing numbers so if you want to increase costs game wide you can tweak one number instead of going through all of the script…

Ranges are between two numbers/script values, eg: trigger_event = { id = cool_event.1 days = { 1 5 } } will launch the event in 1-5 days time.

Formulas are where the system really shines, it lets you compute numbers by doing basic arithmetic and rounding! It can also do conditional operations with ifs and else_ifs, do randomising and loops.
Formulas can also be done inline with where you call them instead of making a specific named formula.

Code:
example_fancy_gold = {
    add = gold
    multiply = 3
    divide = 2
    subtract = 500
    max = 2500
    min = 1000
}

num_non_cultured_provinces = {
    value = 0
    every_owned_province = {
        limit = {
            NOT = {
                dominant_province_culture = root.culture
            }
        }
        add = 1
    }
}

province_pop_friction_size_svalue = {
    value = 0
    scope:pop_friction_enemy_province = {
        if = {
            limit = {
                total_population > 3
            }
            add = {
                value = total_population
                divide = 4
                ceiling = yes
            }
        }
    }
}

Variables

Any non-primitive scope type can be made to store variables in it, which scope types to have them is a game level decision so if you find a scope that does not make a request for it to be added, variables themselves can be any scope type. You can store a value, bool, flag or character etc. inside of them.
This allows for recording a saved scope on a specific object instead of just in a top scope.

Variables can be stored in three places: a scope object (character, country etc.), locally in a top scope (like a normal saved scope) or globally in the game state.
Scoped variables exist as long as the object they are on exists (so for a character they are lost when they die), local variables exist as long as the top scope does and global variables exist until manually cleared.
For every variable trigger and effect there exists a version for each type, the format is prefix_<type>_suffix
eg: set_variable, set_local_variable and set_global_variable
variable_list_size, local_variable_list_size and global_variable_list_size

Variables themselves are treated as a scope object referring to whatever is stored in them allow you to scope to them.
One could have a best friend variable on a character which they save someone as the value then scope to that best friend variable to give the character a gift later on.

The event target link to scope to a variable depends on the storage type:
Code:
var:name
local_var:name
global_var:name

Value type variables can be manipulated with simple arithmetic as well as rounding.

Example of saving a permanent reference inside an object:
Old:
Code:
Good luck with that, depending on your game will depend on the hack you need to use.
Generally it is invisible opinion modifiers and flags to mark people.

Jomini:
Code:
# Event Chain:
set_variable = {
    name = best_friend
    value = root.father
}
# Totally separate event chain
root.var:best_friend = {
    add_loyalty = 20
}

Example of rounding a value:
Old:
Code:
# Depends a lot on the gme you have, to my knowledge only CK2 has the effects needed
set_variable = {
    which = test_var
    value = 10.5
}
divide_variable = { # Now 5.25, I want to round to nearest 5
    which = test_var
    value = 2
}
set_variable = {
    which = test_var_remainder # 5.25
    which = test_var
}
modulo_variable = {
    which = test_var_remainder # Now 0.25
    value = 5
}
subtract_variable = {
    which = test_var
    which = test_var_remainder
}
# Now test_var is rounded to 5

Jomini:
Code:
set_variable = {
    name = test_var
    value = 10.5
}
chance_variable = { # Now 5.25, I want to nearest 5
    name = test_var
    divide = 2
}
round_variable = {
    name = test_var
    nearest = 5
}
# Now test_var is rounded to 5

Scripted Blocks

As in our older games, Jomini has scripted triggers and effects. We also have scripted modifiers that function similarly but for mean time to happen constructs so you can reduce giant modifier lists.
All of them can take scripted arguments as in EU4

eg:
Code:
# Scripted Effect
change_culture_and_notify = {
    set_culture = $CULTURE$
    trigger_event = $CULTURE$.0
}
# Using
root.father = { change_culture_and_notify = { CULTURE = roman }

Scripted Lists are a new addition which let you create your own script lists based on a coded one with extra conditions:
Code:
citizen = {
    base = pops_in_province
    conditions = { pop_type = citizen }
}
This creates any/every/random/ordered_citizen which functions as any/every/random/ordered_pops_in_province + listed conditions.

Target & Variable Lists

You can now create custom lists of saved scopes or variables
They are added and removed with:
Code:
scope_to_add = { add_to_list = list_name }
scope_to_remove = { remove_from_list = list_name }
The list can be iterated over via:
Code:
any/every/random/ordered_in_list = {
    list = list_name
}
Lists can be checked:
Code:
some_scope = { is_in_list = list_name }

You can also have lists of variables in the current scope, locally or globally.
They are added and removed with:
Code:
add_to_variable_list = { name = variable_name target = scope }
remove_list_variable = { name = variable_name target = scope }
clear_variable_list = variable_name
They can be iterated over via:
Code:
any/every/random/ordered_in_list = {
    variable = variable_name
}
They can be checked via:
Code:
is_target_in_variable_list = { name = variable_name target = scope }
variable_list_size = { name = variable_name target = value }
has_variable_list = variable_name

Events and On Actions

Events have been moved to Jomini, the syntax is nearly identical to the older games but instead of defining the event type first you write its ID. Games are free to specialise their events as needed, for example Imperator includes some portraits on their events.
Mean time to happen events have been removed for numerous reasons, primarily because it is bad.

As a replacement for that on actions have been moved to Jomini and been opened up to allow scripter made on actions that function as neat containers of events and methods of random distribution.

We also no longer hack scope objects into root, from chains or this for on actions and instead give them a specifically named saved scopes. So if you have an on action from a battle with a winner, loser, location and war scopes you won’t have to comment in the files what they all mean instead you just use a clearly named scope of scope:battle_location etc.

Old:
Code:
tombola_effect = {
    if = {
        limit = {
            should_get_tombola = yes
        }
        random_list = {
            30 = {
                modifier = {
                    factor = 2
                    is_cool = yes
                }
                trigger_event = cool_event.1
            }
            30 = {
                modifier = {
                    factor = 2
                    is_fancy_pants = yes
                }
                trigger_event = cool_event.2
            }
            30 = {
                modifier = {
                    factor = 2
                    has_lots_of_friends = yes
                }
                trigger_event = cool_event.3
            }
            30 = {
                modifier = {
                    factor = 2
                    is_super_awesome = yes
                }
                trigger_event = cool_event.4
            }
            30 = {
                modifier = {
                    factor = 2
                    is_running_out_of_things_to_list = yes
                }
                trigger_event = cool_event.5
            }
            # ... repeat for lots of events
        }
    }
}

Jomini:
Code:
tombola_on_action = {
    trigger = {
        should_get_tombola = yes
    }
    # Modifiers on the events directly instead of spammed here making this unreadable
    random_events = {
        30 = cool_event.1
        30 = cool_event.2
        30 = cool_event.3
        30 = cool_event.4
        30 = cool_event.5
    }
}

Dynamic Descriptions

Events can now have their descriptions and titles be pieced together bit by bit from conditional and random parts to form dynamic text without needing to nest 20 pieces of custom localisation in multiple different files and folders. This lets you build some very complex event descriptions.

Code:
cool_event.1 = {
    desc = {
        desc = cool_event.1.intro
        first_valid = {
            triggered_desc = {
                cool_event.1.blue_flag
                trigger = { var:flag = flag:blue_flag }
            }
            random_valid = {
                count = 2
                triggered_desc = {
                    cool_event.1.red_flag
                    trigger = { var:flag = flag:red_flag }
                }
                triggered_desc = {
                    cool_event.1.yellow_flag
                    trigger = { var:flag = flag:yellow_flag }
                }
                triggered_desc = {
                    cool_event.1.green_flag
                    trigger = { var:flag = flag:green_flag }
                }
                desc = cool_event.1.brown_flag
            }
        }
        desc = cool_event.1.no_flag
    }
    random_valid = {
        desc = cool_event.1.conclusion.a
        desc = cool_event.1.conclusion.b
    }
}

Sweet Sweet Documentation

We have previously made attempts at automatic documentation with varied success, some bits could be outdated or incorrect, some core information was not printed at all etc.
Now the "script_docs" console command has been moved to Jomini and using it in game will outputs the following information to separate files in your games log folder:
  • All effects, the scopes they can be used in and a brief description, if they are a script list the scope they lead to.
  • All triggers, the scopes they can be used in and a brief description, if they are a script list the scope they lead to.
  • All scope types, character, country, value etc.
  • All event target links, the scopes they can be used from, the scope they output to and a brief description.
  • All saved scopes created by the code.
  • All modifiers, the scope they can be applied to eg: levy_reinforcement_rate
  • All on actions, if they are from code or script and the expected scope they are called in
Improved Error Logging

The script should now be a LOT better at logging errors, we made as much as possible get caught in Jomini with clear errors as to what is going wrong, individual effects and triggers will still need game level specific errors but those should also be a lot better.

GUI & Localization System

We have a new GUI system for the games which works with its own specif setup of scripting, it is also the same system used for the localization system. Collectively this is called the Data System
Everything you can run must be either registered in by the code or made as a scripted gui.

All things you can use in the data are split into four categories:
- Types, the type of an object which corresponds to its class/struct in the code
- Promotes, moving from an object of one type to an object of another
- Functions, calling a function on an object which returns another object
- Callbacks, calling a function on an object which does not return anything

Another thing to keep in mind is that the data system obeys (for the most part) how const works in C++. Without getting too technical functions, promote and callbacks can be marked as const only, which means that object which are const cannot call non-const. This is unlikely to affect you if you use the scripted guis though.

Scripted GUI

The scripted gui lets you evaluate and execute arbitrary script via the UI in a manner that will keep the game synchronized in multiplayer. You define the script in common/scripted_guis and can then reference that in data entries.

For example a cheat button to give you gold and take it from another character:
Code:
# common/scripted_guis
cheat_gold_button = {
    scope = character
    saved_scopes = {
        second
    }
    is_shown = { # Can be omitted as always true
        always = yes
    }
    is_valid = {
        gold < 5000
    }
    effect = {
        add_gold = 500
        scope:second = {
            add_gold = -500
        }
    }
}

# in a gui entry
button = {
    name = "my_cheat_button"
    datacontext = "[GetScriptedGui('cheat_gold_button')]"
    texture = "gfx/interface/icons/shared_icons/bankruptcy.dds"
    visible = "[ScriptedGui.IsShown( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( 'second', SomeOtherCharacter.MakeScope ).End )]"
    enabled = "[ScriptedGui.IsValid( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( 'second', SomeOtherCharacter.MakeScope ).End )]"
    onclick = "[ScriptedGui.Execute( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( 'second', SomeOtherCharacter.MakeScope ).End )]"
    tooltip = "[ScriptedGui.BuildTooltip( GuiScope.SetRoot( SomeCharacter.MakeScope ).AddScope( 'second', SomeOtherCharacter.MakeScope ).End )]"
}

Do not make calls to GuiScope without a matching call to End, otherwise you are going to introduce a memory leak and the game will eventually crash.

The AI will make use of these buttons based on the ai_is_valid trigger and the ai_chance definitions.
 
  • 6Love
  • 1Like
  • 1
Reactions:

Nicolas-

Nc-Rm
32 Badges
Oct 24, 2015
715
1.516
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Europa Universalis IV: Wealth of Nations
  • Stellaris - Path to Destruction bundle
  • Stellaris: Leviathans Story Pack
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Nemesis
  • Stellaris: Distant Stars
  • Stellaris: Megacorp
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Stellaris: Lithoids
  • Stellaris: Federations
  • Crusader Kings III
  • Crusader Kings III: Royal Edition
  • Stellaris: Necroids
  • Stellaris: Apocalypse
  • Stellaris: Humanoids Species Pack
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Digital Anniversary Edition
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV: Cadet
  • Stellaris
  • Rome: Vae Victis
  • Victoria 2: A House Divided
  • Victoria 2
  • Europa Universalis IV
  • Stellaris: Synthetic Dawn
  • Imperator: Rome
  • Hearts of Iron IV: Expansion Pass
  • Rome Gold
This may be a difficult question, but there is a character interaction called "Arrange Marriage" which opens a character selection screen to choose one to marry the selected character with.

This interaction seems to be script-based and not hardcoded, I was wondering what command prompts the character selection screen? Is it character_actor_trigger?

Or is it something that's hardcoded?

If it's not it'd be pretty useful to use in combination with Scripted GUI (though you already said you'll be adding lists at some point, which may solve this).
 

blackninja9939

Experienced Programmer - Crusader Kings 3
77 Badges
Aug 28, 2013
2.367
6.117
  • Crusader Kings III
  • Stellaris: Federations
  • Battle for Bosporus
  • Stellaris: Nemesis
  • Stellaris: Necroids
  • Europa Universalis IV
  • Crusader Kings III: Royal Edition
  • Europa Universalis 4: Emperor
  • Crusader Kings II
  • Crusader Kings II: Holy Fury
  • Imperator: Rome - Magna Graecia
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Europa Universalis IV: Rights of Man
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Synthetic Dawn
  • Surviving Mars
  • BATTLETECH
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Monks and Mystics
  • Tyranny: Archon Edition
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: Reapers Due
  • Hearts of Iron IV: Colonel
  • Stellaris Sign-up
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Lithoids
  • Stellaris: Distant Stars
  • Europa Universalis IV: Dharma
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Prison Architect
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Age of Wonders: Planetfall
  • Crusader Kings II: Conclave
  • Crusader Kings II: The Republic
  • Victoria 2
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Crusader Kings II: Way of Life
  • Stellaris
  • Mount & Blade: Warband
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
This may be a difficult question, but there is a character interaction called "Arrange Marriage" which opens a character selection screen to choose one to marry the selected character with.

This interaction seems to be script-based and not hardcoded, I was wondering what command prompts the character selection screen? Is it character_actor_trigger?

Or is it something that's hardcoded?

If it's not it'd be pretty useful to use in combination with Scripted GUI (though you already said you'll be adding lists at some point, which may solve this).
No idea, as I say at the top of this thread anything game specific like that I am not gonna be able to answer really. Try copy pasting the arrange marriage interaction and changing its name and a couple of triggers, see which part does what.
 

ToraktheNord

Second Lieutenant
35 Badges
Aug 15, 2015
112
225
  • Victoria 2: Heart of Darkness
  • Europa Universalis IV: Mandate of Heaven
  • Europa Universalis IV: Cossacks
  • Europa Universalis IV: Mare Nostrum
  • Hearts of Iron IV Sign-up
  • Hearts of Iron IV: Cadet
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Common Sense
  • Hearts of Iron IV: Death or Dishonor
  • Europa Universalis IV: Cradle of Civilization
  • Crusader Kings II: Holy Fury
  • Europa Universalis IV: Golden Century
  • Imperator: Rome
  • Imperator: Rome Sign Up
  • Crusader Kings III
  • Crusader Kings III: Royal Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: El Dorado
  • Victoria 2: A House Divided
  • Victoria 2
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV
  • Victoria: Revolutions
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Art of War
  • Crusader Kings II
  • Europa Universalis IV: Conquest of Paradise
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Republic
  • Crusader Kings II: The Old Gods
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Charlemagne
I've read through the logs now, particulary the province_window.gui, and I'm a bit confused, are provinces now called provinces or cities, since I don't seem to find anything really referencing it?
 

blackninja9939

Experienced Programmer - Crusader Kings 3
77 Badges
Aug 28, 2013
2.367
6.117
  • Crusader Kings III
  • Stellaris: Federations
  • Battle for Bosporus
  • Stellaris: Nemesis
  • Stellaris: Necroids
  • Europa Universalis IV
  • Crusader Kings III: Royal Edition
  • Europa Universalis 4: Emperor
  • Crusader Kings II
  • Crusader Kings II: Holy Fury
  • Imperator: Rome - Magna Graecia
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Europa Universalis IV: Rights of Man
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Synthetic Dawn
  • Surviving Mars
  • BATTLETECH
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Monks and Mystics
  • Tyranny: Archon Edition
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: Reapers Due
  • Hearts of Iron IV: Colonel
  • Stellaris Sign-up
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Lithoids
  • Stellaris: Distant Stars
  • Europa Universalis IV: Dharma
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Prison Architect
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Age of Wonders: Planetfall
  • Crusader Kings II: Conclave
  • Crusader Kings II: The Republic
  • Victoria 2
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Crusader Kings II: Way of Life
  • Stellaris
  • Mount & Blade: Warband
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
I've read through the logs now, particulary the province_window.gui, and I'm a bit confused, are provinces now called provinces or cities, since I don't seem to find anything really referencing it?
Generally all the script and code will call them provinces still.
City == Province
Province == Area
Region == Region
 

Ariphaos

Colonel
87 Badges
Aug 5, 2011
822
770
  • Stellaris
  • Heir to the Throne
  • Stellaris: Galaxy Edition
  • Magicka
  • Majesty 2 Collection
  • Stellaris: Galaxy Edition
  • Europa Universalis IV: Res Publica
  • Victoria: Revolutions
  • Rome Gold
  • Semper Fi
  • Hearts of Iron III
  • Europa Universalis IV: Mare Nostrum
  • Europa Universalis IV: Rights of Man
  • Cities: Skylines Deluxe Edition
  • Cities: Skylines - Snowfall
  • Europa Universalis IV: Third Rome
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cossacks
  • Cities: Skylines - After Dark
  • Darkest Hour
  • Crusader Kings II
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: The Old Gods
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: The Republic
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: Sword of Islam
  • For The Glory
  • Europa Universalis III
  • Europa Universalis III Complete
  • Divine Wind
  • Arsenal of Democracy
  • Europa Universalis IV: Art of War
  • Europa Universalis IV: Conquest of Paradise
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Call to arms event
  • Hearts of Iron II: Armageddon
  • Stellaris: Galaxy Edition
  • Magicka 2: Ice, Death and Fury
  • Crusader Kings II: Reapers Due
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: El Dorado
  • 500k Club
  • Rome: Vae Victis
  • Stellaris: Nemesis
  • Europa Universalis III Complete
  • Europa Universalis III Complete
The game should probably let go of the script_docs logs it generates once it has made them.

The idea of having a calendar to mod doesn't seem game specific so - are there any plans to allow for the modding of the masks for this?

I'm not sure if this is in_scope for Jomini here, but are/will conditional returns of named elements possible?

For example, in slave pops, we have

Code:
    can_promote_to = freemen
   demotes_to = slaves

This isn't necessarily the best example.

Say we have a society that outlaws slaves and makes all free subjects citizens. So we setup a 'demotion chance' that takes that into account here, is there some way to make this sort of thing happen:

Code:
    can_promote_to = {
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = freemen }

   demotes_to =
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = slaves }

Or something like this. I know there are ways around this specific example, but it would still be useful.
 

Phlopsi

General
39 Badges
May 15, 2016
2.197
688
  • Europa Universalis IV
  • PDXCon 2017 Awards Winner
  • Stellaris: Federations
  • Stellaris: Necroids
  • Crusader Kings II
  • Hearts of Iron III
  • Magicka
  • Cities: Skylines
  • Stellaris
  • Prison Architect
  • Imperator: Rome
The game should probably let go of the script_docs logs it generates once it has made them.
You mean, the game keeps the file handle after they've been generated and you can't move/edit them?

I'm not sure if this is in_scope for Jomini here, but are/will conditional returns of named elements possible?

For example, in slave pops, we have

Code:
    can_promote_to = freemen
   demotes_to = slaves

This isn't necessarily the best example.

Say we have a society that outlaws slaves and makes all free subjects citizens. So we setup a 'demotion chance' that takes that into account here, is there some way to make this sort of thing happen:

Code:
    can_promote_to = {
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = freemen }

   demotes_to =
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = slaves }

Or something like this. I know there are ways around this specific example, but it would still be useful.
There is no conditional return for those features. If they were to add them, they'd probably look like this:
Code:
demotes_to = {
    random = yes/no
    freemen = {
        chance = 40 # optional
        # trigger section
    }
    slaves = {
        chance = 60 # optional
        always = yes
    }
}
 

blackninja9939

Experienced Programmer - Crusader Kings 3
77 Badges
Aug 28, 2013
2.367
6.117
  • Crusader Kings III
  • Stellaris: Federations
  • Battle for Bosporus
  • Stellaris: Nemesis
  • Stellaris: Necroids
  • Europa Universalis IV
  • Crusader Kings III: Royal Edition
  • Europa Universalis 4: Emperor
  • Crusader Kings II
  • Crusader Kings II: Holy Fury
  • Imperator: Rome - Magna Graecia
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Europa Universalis IV: Rights of Man
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Synthetic Dawn
  • Surviving Mars
  • BATTLETECH
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Monks and Mystics
  • Tyranny: Archon Edition
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: Reapers Due
  • Hearts of Iron IV: Colonel
  • Stellaris Sign-up
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Lithoids
  • Stellaris: Distant Stars
  • Europa Universalis IV: Dharma
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Prison Architect
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Age of Wonders: Planetfall
  • Crusader Kings II: Conclave
  • Crusader Kings II: The Republic
  • Victoria 2
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Crusader Kings II: Way of Life
  • Stellaris
  • Mount & Blade: Warband
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
The game should probably let go of the script_docs logs it generates once it has made them.

The idea of having a calendar to mod doesn't seem game specific so - are there any plans to allow for the modding of the masks for this?

I'm not sure if this is in_scope for Jomini here, but are/will conditional returns of named elements possible?

For example, in slave pops, we have

Code:
    can_promote_to = freemen
   demotes_to = slaves

This isn't necessarily the best example.

Say we have a society that outlaws slaves and makes all free subjects citizens. So we setup a 'demotion chance' that takes that into account here, is there some way to make this sort of thing happen:

Code:
    can_promote_to = {
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = freemen }

   demotes_to =
    if = { limit = { country.has_law = outlawed_slavery }
       result = citizens
     }
   else = { result = slaves }

Or something like this. I know there are ways around this specific example, but it would still be useful.
No plans for calendar mods right now, its very tied into the code right now, but maybe one day.

Our script language is not really like that, its not a return based thing for types like that generally.
 

hdhhshdsh<s

Second Lieutenant
22 Badges
Mar 1, 2016
166
0
  • Europa Universalis IV: Art of War
  • Europa Universalis IV: Conquest of Paradise
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Res Publica
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Third Rome
  • Europa Universalis IV: Mare Nostrum
  • Imperator: Rome
  • Europa Universalis IV: Dharma
  • Europa Universalis IV: Rule Britannia
  • Surviving Mars
  • Europa Universalis IV: Mandate of Heaven
  • Cities: Skylines - Mass Transit
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV: Cadet
  • Europa Universalis IV: Common Sense
  • Europa Universalis IV: El Dorado
  • Cities: Skylines
  • Europa Universalis IV
  • Crusader Kings II
  • Europa Universalis IV: Cossacks
  • Europa Universalis IV: Cradle of Civilization
I'm having quite some difficulty understanding the new data type system and how to use it in localization.
In the other paradox games, showing the value of a variable would be something akin to
Code:
[ROOT.var_name.GetValue]
With the new system I'm at a loss, have tried these and variations but can't seem to understand the logic

Code:
[VariableInfo.GetValue('var_name')]
[Country.VariableInfo.GetValue('var_name')]
 

Nicolas-

Nc-Rm
32 Badges
Oct 24, 2015
715
1.516
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Europa Universalis IV: Wealth of Nations
  • Stellaris - Path to Destruction bundle
  • Stellaris: Leviathans Story Pack
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Nemesis
  • Stellaris: Distant Stars
  • Stellaris: Megacorp
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Stellaris: Lithoids
  • Stellaris: Federations
  • Crusader Kings III
  • Crusader Kings III: Royal Edition
  • Stellaris: Necroids
  • Stellaris: Apocalypse
  • Stellaris: Humanoids Species Pack
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Digital Anniversary Edition
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV: Cadet
  • Stellaris
  • Rome: Vae Victis
  • Victoria 2: A House Divided
  • Victoria 2
  • Europa Universalis IV
  • Stellaris: Synthetic Dawn
  • Imperator: Rome
  • Hearts of Iron IV: Expansion Pass
  • Rome Gold
Using the Data System, is it possible to use GetCharacter on a character stored in a variable?

Mainly looking to use this:

Code:
                portrait_button = {
                    using = portrait_50_no_pop
                    position = { 0 50 }
                    datacontext = "[GovernmentView.GetPlayer.GetCharacter(character storied in a variable?)]"}
 

Phlopsi

General
39 Badges
May 15, 2016
2.197
688
  • Europa Universalis IV
  • PDXCon 2017 Awards Winner
  • Stellaris: Federations
  • Stellaris: Necroids
  • Crusader Kings II
  • Hearts of Iron III
  • Magicka
  • Cities: Skylines
  • Stellaris
  • Prison Architect
  • Imperator: Rome
I'm having quite some difficulty understanding the new data type system and how to use it in localization.
In the other paradox games, showing the value of a variable would be something akin to
Code:
[ROOT.var_name.GetValue]
With the new system I'm at a loss, have tried these and variations but can't seem to understand the logic

Code:
[VariableInfo.GetValue('var_name')]
[Country.VariableInfo.GetValue('var_name')]
ROOT.Var('my_var').GetValue or inside tooltips, where no ROOT is defined, try using SCOPE/THIS/PREV. If you still have issues, please state the context where you're trying to display it.
 

hdhhshdsh<s

Second Lieutenant
22 Badges
Mar 1, 2016
166
0
  • Europa Universalis IV: Art of War
  • Europa Universalis IV: Conquest of Paradise
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Res Publica
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Third Rome
  • Europa Universalis IV: Mare Nostrum
  • Imperator: Rome
  • Europa Universalis IV: Dharma
  • Europa Universalis IV: Rule Britannia
  • Surviving Mars
  • Europa Universalis IV: Mandate of Heaven
  • Cities: Skylines - Mass Transit
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV: Cadet
  • Europa Universalis IV: Common Sense
  • Europa Universalis IV: El Dorado
  • Cities: Skylines
  • Europa Universalis IV
  • Crusader Kings II
  • Europa Universalis IV: Cossacks
  • Europa Universalis IV: Cradle of Civilization
ROOT.Var('my_var').GetValue or inside tooltips, where no ROOT is defined, try using SCOPE/THIS/PREV. If you still have issues, please state the context where you're trying to display it.
Thank you - that was simple. It works for me in events, but I cant seem to get the scoping right inside a widget.
In ingame_topbar.gui I've added a new widget with a textbox. I tried displaying the variable in the "text =" both directly and through a localization string, but neither seemed to work
 

blackninja9939

Experienced Programmer - Crusader Kings 3
77 Badges
Aug 28, 2013
2.367
6.117
  • Crusader Kings III
  • Stellaris: Federations
  • Battle for Bosporus
  • Stellaris: Nemesis
  • Stellaris: Necroids
  • Europa Universalis IV
  • Crusader Kings III: Royal Edition
  • Europa Universalis 4: Emperor
  • Crusader Kings II
  • Crusader Kings II: Holy Fury
  • Imperator: Rome - Magna Graecia
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Europa Universalis IV: Rights of Man
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Synthetic Dawn
  • Surviving Mars
  • BATTLETECH
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Monks and Mystics
  • Tyranny: Archon Edition
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: Reapers Due
  • Hearts of Iron IV: Colonel
  • Stellaris Sign-up
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Lithoids
  • Stellaris: Distant Stars
  • Europa Universalis IV: Dharma
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Prison Architect
  • Imperator: Rome Sign Up
  • Stellaris: Ancient Relics
  • Age of Wonders: Planetfall
  • Crusader Kings II: Conclave
  • Crusader Kings II: The Republic
  • Victoria 2
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Crusader Kings II: Way of Life
  • Stellaris
  • Mount & Blade: Warband
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
Thank you - that was simple. It works for me in events, but I cant seem to get the scoping right inside a widget.
In ingame_topbar.gui I've added a new widget with a textbox. I tried displaying the variable in the "text =" both directly and through a localization string, but neither seemed to work
What did you actually type that didn't work? Just saying "it doesn't work" without showing your script is not gonna help either of us solve it ;)
 
  • 1Like
Reactions:

hdhhshdsh<s

Second Lieutenant
22 Badges
Mar 1, 2016
166
0
  • Europa Universalis IV: Art of War
  • Europa Universalis IV: Conquest of Paradise
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Res Publica
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Third Rome
  • Europa Universalis IV: Mare Nostrum
  • Imperator: Rome
  • Europa Universalis IV: Dharma
  • Europa Universalis IV: Rule Britannia
  • Surviving Mars
  • Europa Universalis IV: Mandate of Heaven
  • Cities: Skylines - Mass Transit
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV: Cadet
  • Europa Universalis IV: Common Sense
  • Europa Universalis IV: El Dorado
  • Cities: Skylines
  • Europa Universalis IV
  • Crusader Kings II
  • Europa Universalis IV: Cossacks
  • Europa Universalis IV: Cradle of Civilization
What did you actually type that didn't work? Just saying "it doesn't work" without showing your script is not gonna help either of us solve it ;)
Sorry, it probably works, I just mean I cant figure out how to scope it correctly lol. Thank you for taking time to answer these questions.
Code:
textbox = {
                    name = "new_stat_test"
                    position = { 72 3 }
                    using = MarbleButtonFont
                    autoresize = yes
                    text = "var_testing"
                    tooltip = "tooltip_test"
                    widgetanchor = top|hcenter
                }
I tried both this method with localization, but also directly using [PREV.Var('test_var_1').GetValue] inside text = "". - with the scopes Phlopsi suggested (SCOPE,THIS,PREV,ROOT) and tried InGameTopbar.GetPlayer as well.
My localization:
Code:
 var_testing:0 "[PREV.Var('test_var_1').GetValue]"