• Crusader Kings III Available Now!

    The realm rejoices as Paradox Interactive announces the launch of Crusader Kings III, the latest entry in the publisher’s grand strategy role-playing game franchise. Advisors may now jockey for positions of influence and adversaries should save their schemes for another day, because on this day Crusader Kings III can be purchased on Steam, the Paradox Store, and other major online retailers.


    Real Strategy Requires Cunning

blackninja9939

Programmer
69 Badges
Aug 28, 2013
2.285
3.367
  • Europa Universalis IV: Mare Nostrum
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Tyranny: Archon Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Stellaris: Lithoids
  • Europa Universalis IV: Dharma
  • Crusader Kings II: Conclave
  • Stellaris
  • Stellaris Sign-up
  • Hearts of Iron IV: Cadet
  • Hearts of Iron IV: Colonel
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Magicka: Wizard Wars Founder Wizard
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Mandate of Heaven
  • BATTLETECH
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Shadowrun Returns
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: The Republic
  • Stellaris: Ancient Relics
  • Imperator: Rome
  • Prison Architect
  • Mount & Blade: Warband
  • Stellaris: Distant Stars
  • Imperator: Rome Sign Up
  • Crusader Kings II: Holy Fury
  • Teleglitch: Die More Edition
  • Victoria 2
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Deluxe Edition
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Age of Wonders: Planetfall
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Crusader Kings II: Jade Dragon
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
Reactions:

cristofolmc

Field Marshal
On Probation
30 Badges
Mar 5, 2009
2.521
57
  • Europa Universalis III
  • Europa Universalis III: Chronicles
  • Europa Universalis III Complete
  • Divine Wind
  • Heir to the Throne
  • Crusader Kings II
  • Rome Gold
  • Europa Universalis IV: Common Sense
  • Imperator: Rome Sign Up
  • Imperator: Rome
  • Europa Universalis IV: Cradle of Civilization
  • Age of Wonders III
  • Europa Universalis IV: Mandate of Heaven
  • Europa Universalis IV: Rights of Man
  • Hearts of Iron IV Sign-up
  • Europa Universalis IV: Cossacks
  • 500k Club
  • Victoria 2
  • Europa Universalis III Complete
  • Europa Universalis III Complete
  • Victoria 2: A House Divided
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II: The Old Gods
  • Crusader Kings II: Sons of Abraham
Noiiiiiceeeee Matthew. This will come in handy for the first steps into modding I:R!
 

steveh11

Games Player
107 Badges
Jun 9, 2001
2.390
317
www.asstr.org
  • Cities: Skylines Deluxe Edition
  • Victoria: Revolutions
  • Rome Gold
  • Semper Fi
  • Sengoku
  • Teleglitch: Die More Edition
  • Victoria 2
  • Victoria 2: A House Divided
  • Victoria 2: Heart of Darkness
  • Warlock: Master of the Arcane
  • Warlock 2: The Exiled
  • 500k Club
  • Cities: Skylines
  • Europa Universalis IV: Res Publica
  • Crusader Kings II: Holy Knight (pre-order)
  • Europa Universalis III: Collection
  • Europa Universalis IV: El Dorado
  • Europa Universalis IV: Pre-order
  • Crusader Kings II: Way of Life
  • Pillars of Eternity
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Paradox Order
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Cossacks
  • Crusader Kings III
  • Europa Universalis IV: Art of War
  • Ancient Space
  • 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: Sunset Invasion
  • Crusader Kings II: Sword of Islam
  • Europa Universalis III
  • Divine Wind
  • Europa Universalis IV: Conquest of Paradise
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Call to arms event
  • For the Motherland
  • Hearts of Iron III
  • Hearts of Iron III: Their Finest Hour
  • Hearts of Iron III Collection
  • Heir to the Throne
  • Europa Universalis III Complete
  • March of the Eagles
Thanks!
 

Nicolas-frm

Major
27 Badges
Oct 24, 2015
584
575
  • Crusader Kings II
  • Crusader Kings II: Sword of Islam
  • Europa Universalis IV: Wealth of Nations
  • Stellaris: Leviathans Story Pack
  • Stellaris - Path to Destruction bundle
  • Crusader Kings III
  • Stellaris: Lithoids
  • Stellaris: Ancient Relics
  • Imperator: Rome Sign Up
  • Europa Universalis IV: Golden Century
  • Stellaris: Megacorp
  • Stellaris: Distant Stars
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Stellaris: Humanoids Species Pack
  • Europa Universalis IV: Cradle of Civilization
  • Stellaris: Digital Anniversary Edition
  • Hearts of Iron IV: Cadet
  • Stellaris
  • Rome: Vae Victis
  • Victoria 2: A House Divided
  • Victoria 2
  • 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

Programmer
69 Badges
Aug 28, 2013
2.285
3.367
  • Europa Universalis IV: Mare Nostrum
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Tyranny: Archon Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Stellaris: Lithoids
  • Europa Universalis IV: Dharma
  • Crusader Kings II: Conclave
  • Stellaris
  • Stellaris Sign-up
  • Hearts of Iron IV: Cadet
  • Hearts of Iron IV: Colonel
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Magicka: Wizard Wars Founder Wizard
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Mandate of Heaven
  • BATTLETECH
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Shadowrun Returns
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: The Republic
  • Stellaris: Ancient Relics
  • Imperator: Rome
  • Prison Architect
  • Mount & Blade: Warband
  • Stellaris: Distant Stars
  • Imperator: Rome Sign Up
  • Crusader Kings II: Holy Fury
  • Teleglitch: Die More Edition
  • Victoria 2
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Deluxe Edition
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Age of Wonders: Planetfall
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Crusader Kings II: Jade Dragon
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

Sergeant
34 Badges
Aug 15, 2015
88
87
  • Victoria 2: Heart of Darkness
  • Crusader Kings II: Monks and Mystics
  • Crusader Kings II: Horse Lords
  • 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
  • Europa Universalis IV: Common Sense
  • Europa Universalis IV: Mandate of Heaven
  • 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 II: Way of Life
  • Europa Universalis IV: El Dorado
  • Victoria 2: A House Divided
  • Victoria 2
  • 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

Programmer
69 Badges
Aug 28, 2013
2.285
3.367
  • Europa Universalis IV: Mare Nostrum
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Tyranny: Archon Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Stellaris: Lithoids
  • Europa Universalis IV: Dharma
  • Crusader Kings II: Conclave
  • Stellaris
  • Stellaris Sign-up
  • Hearts of Iron IV: Cadet
  • Hearts of Iron IV: Colonel
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Magicka: Wizard Wars Founder Wizard
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Mandate of Heaven
  • BATTLETECH
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Shadowrun Returns
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: The Republic
  • Stellaris: Ancient Relics
  • Imperator: Rome
  • Prison Architect
  • Mount & Blade: Warband
  • Stellaris: Distant Stars
  • Imperator: Rome Sign Up
  • Crusader Kings II: Holy Fury
  • Teleglitch: Die More Edition
  • Victoria 2
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Deluxe Edition
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Age of Wonders: Planetfall
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Crusader Kings II: Jade Dragon
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
84 Badges
Aug 5, 2011
807
749
  • Stellaris
  • Hearts of Iron III
  • Magicka
  • Majesty 2 Collection
  • Stellaris: Galaxy Edition
  • Europa Universalis IV: Res Publica
  • Victoria: Revolutions
  • Rome Gold
  • Semper Fi
  • Stellaris: Galaxy Edition
  • Heir to the Throne
  • Europa Universalis IV: Rights of Man
  • Cities: Skylines Deluxe Edition
  • Europa Universalis IV: Mare Nostrum
  • Cities: Skylines - Snowfall
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Third Rome
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Cossacks
  • Crusader Kings II: Sword of Islam
  • Arsenal of Democracy
  • Hearts of Iron II: Armageddon
  • 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
  • For The Glory
  • Darkest Hour
  • Europa Universalis III
  • Europa Universalis III Complete
  • Divine Wind
  • 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
  • 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
  • Crusader Kings III
  • 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
38 Badges
May 15, 2016
2.181
650
  • PDXCon 2017 Awards Winner
  • 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

Programmer
69 Badges
Aug 28, 2013
2.285
3.367
  • Europa Universalis IV: Mare Nostrum
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Tyranny: Archon Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Stellaris: Lithoids
  • Europa Universalis IV: Dharma
  • Crusader Kings II: Conclave
  • Stellaris
  • Stellaris Sign-up
  • Hearts of Iron IV: Cadet
  • Hearts of Iron IV: Colonel
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Magicka: Wizard Wars Founder Wizard
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Mandate of Heaven
  • BATTLETECH
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Shadowrun Returns
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: The Republic
  • Stellaris: Ancient Relics
  • Imperator: Rome
  • Prison Architect
  • Mount & Blade: Warband
  • Stellaris: Distant Stars
  • Imperator: Rome Sign Up
  • Crusader Kings II: Holy Fury
  • Teleglitch: Die More Edition
  • Victoria 2
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Deluxe Edition
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Age of Wonders: Planetfall
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Crusader Kings II: Jade Dragon
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: Cossacks
  • Europa Universalis IV: Cradle of Civilization
  • Crusader Kings II
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')]
 

Phlopsi

General
38 Badges
May 15, 2016
2.181
650
  • PDXCon 2017 Awards Winner
  • 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: Cossacks
  • Europa Universalis IV: Cradle of Civilization
  • Crusader Kings II
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

Programmer
69 Badges
Aug 28, 2013
2.285
3.367
  • Europa Universalis IV: Mare Nostrum
  • Crusader Kings II: Charlemagne
  • Crusader Kings II: Rajas of India
  • Crusader Kings II: Sons of Abraham
  • Crusader Kings II: The Old Gods
  • Tyranny: Archon Edition
  • Crusader Kings II: Way of Life
  • Europa Universalis IV: Common Sense
  • Crusader Kings II: Horse Lords
  • Stellaris: Lithoids
  • Europa Universalis IV: Dharma
  • Crusader Kings II: Conclave
  • Stellaris
  • Stellaris Sign-up
  • Hearts of Iron IV: Cadet
  • Hearts of Iron IV: Colonel
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV: Rights of Man
  • Magicka: Wizard Wars Founder Wizard
  • Crusader Kings II: Monks and Mystics
  • Europa Universalis IV: Mandate of Heaven
  • BATTLETECH
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Shadowrun Returns
  • Europa Universalis IV: Rule Britannia
  • Crusader Kings II: The Republic
  • Stellaris: Ancient Relics
  • Imperator: Rome
  • Prison Architect
  • Mount & Blade: Warband
  • Stellaris: Distant Stars
  • Imperator: Rome Sign Up
  • Crusader Kings II: Holy Fury
  • Teleglitch: Die More Edition
  • Victoria 2
  • Europa Universalis IV: Golden Century
  • Imperator: Rome Deluxe Edition
  • Cities: Skylines
  • Europa Universalis IV: El Dorado
  • Age of Wonders: Planetfall
  • Crusader Kings II: Sunset Invasion
  • Crusader Kings II: Legacy of Rome
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II
  • Crusader Kings II: Jade Dragon
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: Cossacks
  • Europa Universalis IV: Cradle of Civilization
  • Crusader Kings II
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]"