• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Dev Diary #168 - Code of Khans

Hi! This expansion is adding quite a few new systems, and today we’re here to talk about the modability and underlying tech of some of them.

Tributaries

One of the more impactful features we’re adding is tributaries. So we’re on the same page when it comes to terminology: a suzerain is to a tributary what a liege is to a vassal.
Previously, a vassal had a collection of individual contracts defined on their government type which made up their complete “vassal contract”. This included things such as “feudal_government_taxes” added on the “feudal_government”, which determined how much a vassal with the feudal government would pay to their liege.
However, with the addition of tributaries this has changed slightly. Firstly, pretty much everything related to “vassal contracts” have been renamed to “subject contracts”. To enable re-use of these contract lists and usage outside of governments, we’ve added a new database called “subject contract groups” which includes the typical list of individual contracts, but can also include extra parameters such as how they should be inherited on succession and how they should appear on the map. These are documented in the info file for subject contracts groups.

image_01.png

[An example of a subject contract group for a type of tributary]

Tributaries basically work the same way as vassals, with the same system for contracts. But instead of being applied automatically based on your government when you become someone’s vassal, tributaries need to be started manually through script.

image_02.png

[Starting new tributary contracts is easy!]

This effect will only work if both the tributary and the suzerain are independent rulers, and that the resulting tributary relation won’t result in a circular loop of people being tributaries to each other. This can easily be checked with the “can_be_tributary_of” trigger. They can also be broken with “scope:some_tributary_character = { end_tributary = yes }”
Tributary contract groups are also marked with “is_tributary = yes” so that we can differentiate them from regular vassal relationships, as characters with tributary contracts are still considered “independent rulers”.
To get a character’s suzerain you can use the new “character.suzerain” link, or “character.overlord” which will get either the liege if the character’s a vassal, or the suzerain if they’re a tributary. “top_suzerain” and “top_overlord” also exist. The latter will first find your top liege and then keep going to your top liege’s top suzerain, if they have one.

The AI has a chance to break free from their suzerain each year based on the “ai_will_do” in the “cease_paying_tribute_interaction”, which is what’s displayed here:

image_03.png


Obedience

Any character who has a government type that uses the “obedience” government rule, or has a liege/suzerain/employer who does, will use obedience. The threshold needed to become obedient and the obedience value are both calculated in script:

image_04.png


Put simply, if the calculated Obedience value is greater than the threshold, that character will be Obedient. The Obedience target is set in Code with the following priority:
  • De Facto Liege
  • Suzerain
  • Employer
  • De Jure Liege
  • None

Obedience is checked in many places using the “is_obedient” and “is_obedient_to” triggers.

Confederations

Confederations are a group of smaller independent rulers coming together, acting as allies in defense against greater threats. Creating one is simple using the “create_confederation” effect.

image_05.png


Confederations invalidate on a daily tick if they have fewer than two members, so after a confederation has been created another member must be added using “add_confederation_member”

image_06.png


Members of the confederation will skew their map color towards the color of the confederation creator based on the define “CONFEDERATION_REALM_COLOR_FACTOR”.

Situations

We have implemented a new general system for supporting dynamic region-based gameplay, which we call the Situation system. Its purpose is to provide a fundamental building block for various types of systems, from Struggle-like socio-political systems, to environment systems like the Great Steppe, or smaller temporary effects like a Natural Disaster. (All Under Heaven mentioned!)

In this sense you can consider Situations to be an evolution of the Struggle system, where we took the learnings of that system, and made it more dynamic and flexible. Extendable in our C++ code base (example: Migrations), but also flexible in our GUI system, and more moddable.

To note: we have not converted existing Struggles to be Situations, because Struggles contain specific functionality and bespoke interfaces that we do not have in exactly the same way as in the new Situation system.

image_07.png


As you can see from the documentation file above, we’re using this system in both Khans of the Steppe, as well as All Under Heaven. It is part of the base game, and thus available for all modders regardless of DLC ownership.
Now how is this system structured? I will try to explain in a succinct manner. The terms might be a bit dry, but that is because it is a core system - each implementation can rename things in the interface as they like!

Sub-regions - A Situation type consists of one or more geographical sub-regions. These subregions are fixed in number, but each can grow and contract their geographical area while the game is running. Example: the three sub-regions of the Great Steppe - west, central, and east.

Phases - Each Situation type has a set of phases which can transition from one to another via various mechanics. We grabbed some functionality from the Struggle system and extended it.

An active phase can transition to another phase in these ways:
  • Max Duration Reached - If a maximum phase duration is defined, and it is reached, a new phase is picked from the possible future phases, according to a rule, either a weighted pick of the future phases based on the points they have accumulated, or entirely random.
    Example: The Great Steppe seasons progress in this manner.
  • Points Takeover - One of the future phases has accumulated enough points to reach its “takeover” target. Similar to Struggles, you can use catalysts to add points to specific future phases. It will stop the current phase, and put itself as the active phase.
    Example: Some of the special seasons of The Great Steppe work this way
  • Duration Takeover - One of the future phases has reached a specific duration. It will stop the current phase, and put itself as the active phase. This can be used to provide a more predictable version of the points takeover phase.
  • Changed via Script - Our script system is powerful - and we can switch phases directly, skipping the automatic systems. It can also change to a phase that isn’t an official ‘future phase’ of the active phase.

Each sub-region has its own active phase, and its own phase progression, but the possible phases are defined on a situation level. Nothing would prevent us (or a modder) from implementing multiple phase ‘cycles’ within a situation though!

Of course a situation phase definition also contains modifiers and parameters that will apply to the region (county_modifiers), or the characters participating in the situation (character_modifiers), filtered by their Participant Group, which segues nicely into…

Participant Groups - Who is impacted by the situation? Well we can define a set of participant groups within the situation. Similarly to sub-regions, the groups themselves are pre-defined in the situation type, but are dynamic while the game is running - characters can join and leave groups.
Each sub-region has their own set of these pre-defines participant groups, and within each sub-region a character can only belong to one participant group (or none).
So what determines which group you would belong to? This is determined by potential candidates, and settings on the groups. By default the candidates are all the rulers within the geographical area of the relevant sub-region. But you can also add and remove candidates manually via script. (for example you could add the Pope to the Great Steppe even though they are nowhere near)

For each sub-region, we go through all the candidates, and the first group that is valid for them is where they are added. It is possible to not be valid for any group! Then they’re not part of the Situation.

image_08.png


Dynamic Sub-region Creation - When you have defined a situation type, it can be added to the world via a history definition, or via a script effect. But you can also define a new set of sub-regions while starting a situation! This allows us to instantiate the same situation type in multiple locations.

image_09.png


Ending - A Situation ends automatically when a phase (in any sub-region) ends without a new phase starting. Additionally, they can be ended in script via an ‘end_situation’ effect.

Graphical Features - Bundled with the Situation system we also have some additional graphical features. Simple ones include the ability to define the map-color of specific sub-regions or participant groups. But more notably we have also added Map Province Effects - a way to apply an effect on the map based on the current Situation phase of a sub-region.
These effects can be applied with a specific effect type and intensity (0.0 - 1.0), we bundle some effects out of the box in Khans of the Steppe: Drought, Summer, Snow - but mods could add more of course!

image_10.png

[Regular terrain north of the Aral sea]

image_11.png

[Summer province effect at full intensity]

image_12.png

[Snow province effect at full intensity - this effect is hooked into our existing winter shader, so it will fade in/out neatly]

image_13.png

[Drought province at full intensity]

All-in-all the Situation system is a building block which allows a game-play feature to use what they need, and tweak what they want, often without requiring new C++ code.

Migration

Nomadic migration is an extension of the situations system - situation type can set that it supports migrations. This will enable additional mechanics for the player and the AI in the map area covered by the specific situation. Migration process and AI decision-making in regards to migration is a complex task, largely controlled by code. We do that every time when there’s high overall complexity and performance risks. Here are the customization points that can be used to tweak how and what happens during migration.

Migration always happens within some situations. A game rule allows you to enable additional situations in different parts of the world, and migrations will happen independently inside those areas. When you mod your own situations that support migration, please do note that such situations shouldn’t overlap.

Both player and AI start migration via special interaction called “migration_interaction” in script. Initiation of migration travel or war is handled in code, but the rest can be adjusted. For example, actual transfer of land after migration is up to script. The property of the interaction “ai_accept” controls if the recipient allows you to migrate into their lands peacefully, or will it lead to war. “ai_will_do” on the other hand is used to score the best migration target when AI makes its decision where to migrate. Unlike other interactions, this one gets lots of additional data provided by code to script, so scoring can be more nuanced. Additional scopes are migration target, all potential enemies in case of hostile migration, target land fertility, total military power of all defenders and their allies - all this allows you to prioritise for different targets, balancing risks and benefits.

When migration is hostile, it uses a special casus belli - “migration_cb”.

Migration range is limited by migration distance (MAX_MIGRATION_SQUARED_DISTANCE), and there are modifiers (max_migration_distance_mult) that extend or shrink it. It allows you to control different AI behaviors, setting some rulers to be more free-roaming, and putting harsher restrictions on others.

Domiciles

It is our second expansion that uses domiciles, and it introduces a new domicile type - nomadic camp. With more hand-on experience with this system some previous technical decisions proved to be error-prone and hard to work with. So we decided to change how domiciles are connected to playable landless rulers. Domiciles are now owned not by a person, but by a special landless title. Adventurers always have their camp title, landless noble families have noble family title, and nomads have a nomadic camp title. This solves several problems at once - domicile inheritance is now completely controlled by inheritance of special titles. No more cases when code has to decide for a ruler which of the 2 domiciles they should keep - their own or the one they inherited from someone else. Title can have no holder for some time, and when it gets a new holder at some point, domicile is returned back into the game - no risk of accidentally destroying a rich and build-up domicile due to an unfortunate succession. Nothing changes in script or UI - there’s still a direct connection between a ruler and active domicile they have. When a ruler holds several special titles with domiciles, only one of those domiciles will be active - the one that matches the ruler's government type. This shouldn’t normally happen in the base game though.

Fertility

Fertility is a value calculated at the County level. Every County that is in Situation with Migration or whose Holder has a Government Type with the Government Rule uses_county_fertility has County Fertility calculated and shown in the UI.

image_14.png

[Government Rules for Nomadic Government]

If you want to mod in a Situation that uses Fertility without Migration, just add migration = yes to the Situation setup, but disable the migration interaction (migration_interaction) and make sure you add the uses_county_fertility government rule where necessary.

Herders are a bit special in that they also replenish County Fertility, which is another Government Rule called replenishes_county_fertility. They contribute a base monthly Fertility gain per county, governed by the define BASE_HERDER_GAIN_PER_COUNTY.

Monthly Fertility change is a bit more complex than our usual systems. We adjust both Growth and Decline to better simulate how nomadic herds would reduce local pastureland, with the overall change often settling at some lower number (though this depends on your domain size and some other factors).

County Fertility Growth is changed according to this function:

image_15.png

image_16.png

[County Fertility Growth Equation and Graph]

County Fertility Decline is changed according to this function:

image_17.png

image_18.png

[County Fertility Decline Equation and Graph]

Where these two curves intersect is theoretically the Equilibrium point of a given County in the game. A County’s Fertility will always trend toward the Equilibrium point. There is, however, a “pusher” which determines how sensitive Equilibrium is to the difference between Growth and Decline.

image_19.png

[County Fertility Pusher Equation]

Given the complexity of these equations, we opted for a simpler way to calculate the Equilibrium point to display in the UI, using the small angle approximation sin(x) ≈ x :

image_20.png

[County Fertility Equilibrium Approximation Equation]

Put together with Character, Holding, and County modifiers, these functions contribute what you see in the game as Monthly County Fertility Change.

It is important to note that the math behind all this is largely contained in what we’ve called “Current County Fertility Modifier” in the monthly change breakdown. This number is the result of these calculations and what directs the Fertility in a County to trend toward its Equilibrium point.

image_21.png

[Example of a Fertility Monthly Change breakdown]

For anyone that hasn’t taken a math class recently, this may all seem like gobbledygook, so here’s the main takeaway for modders: The central way to affect how County Fertility grows and declines, and where it will hit Equilibrium, is by adjusting the following defines which hook into the functions above:

image_22.png

[Defines for affecting how County Fertility Change behaves]

Herd

Herd is a new currency stored by a Character’s Domicile.

image_23.png

[Yurt Domicile script showing the herd parameter]

Every Domicile has Current Herd and Max Herd values, accessible by the following triggers:

image_24.png

[herd and max_herd triggers available for domiciles]

A Domicile’s Herd Limit (Max Herd) is determined by their tier plus any relevant modifiers. There is a new define listing base Herd Limit values by tier

image_25.png

[Defines affecting Herd Capacity, Herd Conversion, and Monthly Gold Income from Herd]

Along with that comes a Base Herd Conversion rate, which determines how many of your Herd get turned into Horde Riders when you raise your armies. And additionally a define to control how much Gold income a Character gets based on their Herd.

Every month, your Herd will increase based on the Herd Gain from your domain as well as contributions from Vassals and Tributaries. The Herd you gain from your Domain is equal to the current County Fertility of that County multiplied by the define HERD_GAIN_FROM_COUNTY_MULTIPLIER

image_26.png

[Herd Gain from County Fertility Multiplier Define]

Raid Intents

With raid intents we’re adding some customizability to raiding. It can change what you receive when you return with loot, and modify the raiding army in some way.

image_27.png


Here we see the raze intent which will add prestige and dread when your raiding army returns with loot, but gives a -60% modifier to raiding speed.
We also use the “on_raid_action_completion” on-action to have different effects happen after each successful raid on a holding depending on the active raid intent of the raiding army. You can check a scoped army’s raid intent using “raid_intent = NAME_OF_INTENT” trigger.

Generated Character Templates

It is now possible to specify a scripted character template per Government Type. This template will be used when a new character is automatically generated for that government type in code, for example, when granting a title to an automatically generated character.

image_28.png

[Script syntax for specifying a generated character template]

image_29.png

[Scripted character template for a Herder]

We use this pretty frequently in the Steppe when you start Migration and leave behind your lands to Herders. So whenever you begin migrating, the Herders that appear to oversee your previous Domain are generated according to the template above.

The aim here is to give script and modders more control over the characters that are created for titles that already have government types specified.

Skeleton Update

With this release comes an updated skeleton for the characters. We’ve added new sleeve, skirt, and cloak joints, to help increase the animation fidelity for clothing. The adding of joints to the male_body.mesh and female_body.mesh also means that any item modders may have created that uses these skeletons will have to have those joints added, or the item will look very weird (sort of “exploding”), as the joint count array now places joints in a different order and has a larger amount of them. To help modders out, we’ve decided to publish our skeleton files, both our own Maya files as well as in the more universal FBX format. You can find these files over here.

To expedite fixing old clothes, cloaks, and legwear, modders can use these files to copy over the skinning from the various types of clothes in the files to their own items. Some manual reskinning is generally necessary, but hopefully this should make it much faster than doing it all manually. In general, legwear (pants) get the skinweights copied from the regular body (skinned to the legs), cloaks have a specific cloak item in the files to copy from (skinned to the cloak joints as well as the upper arms/neck/upper back), and regular clothes can copy from a “body and skirt” item (skinning the upper body to the body's joints, and the lower body to the skirt joints). Pick whatever item seems to suit the one needing reskinning.

Our previously made clothing should look and act pretty much the same as before, while new animations and clothes will be able to have more movement independent of the body. This will allow us to simulate better movement based on weird poses or fast movement.

Combat

For the combat-loving modders out there, we have added some commonly requested on-actions you can use to apply effects when combat starts, or when an army joins a combat.

image_30.png


Additionally we have added some new script effects which will allow more control over combat outcomes:
  • set_winner = yes - effect you can apply to a combat side to force a winner in combat without reducing soldiers to 0. (on the next tick, more clean)
  • force_win = yes - effect you can apply to a combat side to force a winner in combat without reducing soldiers to 0. (instantly)
  • set_disallowed_retreat = yes - effect to disallow retreat on a combat side (they will wipe on defeat)
  • set_allow_early_retreat = yes - effect to allow retreat when battle just started (prevents wipes)
  • set_skip_pursuit = yes - effect to skip the pursuit phase after a combat win (so soft casualties are not converted to hard casualties)

We have also added a new ‘defeated’ map military unit animation state, which is set when a unit is defeated after combat, allowing for some cool extra animations.




That's all for now! We'll be back next week to talk about some of the art and music coming in Khans of the Steppe, so be sure to check that out next Tuesday.
 
  • 62Like
  • 16
  • 14Love
  • 4
Reactions:
I don't think this has been answered in previous dev diaries, can you tell us how cultures will work for nomads? They don't have promote culture task. Will their culture "spread" like with CK2 nomads, or in a different way?
 
  • 2Like
  • 1
Reactions:
  • Will mods need to change how domiciles work? For example, mods that add domiciles to feudals or theocracies will need to add titular titles just to hold these, or should it work naturally?

Correct. Effects that create/destroy domiciles directly are removed, instead you use an effect to create a landless title with a government type that has a domicile associated with it
 
  • 10
  • 1Like
Reactions:
Devs: explaining some (probably not very) complicated math

Me, a genius modder:

9q4u7n.jpg


And thank god for the combat effects, oh my heavens, that's so amazing.
 
  • 2Like
Reactions:
I still don't get those Fertility modifiers. Why don't you show the Equilibrium in the tooltip?

And I also do not get the difference between Struggles and Situations, mechanically speaking. A cursory read tells me they're functionally the same and the former could be adapted into the latter. What am I missing?
 
So I am correct, that a tributary, can only be of a level below you? Just like a duke-level steppe ruler can only have county-level tributaries?
 
Please, add proper math expressions to scripting language. Something like
Perl:
if = {
    limit = {
        @(a + b * scope:char.age + sqrt(3)]) < 10
    }
    # ...
}

# or

if = {
    limit = {
        [[a + b * scope:char.age + sqrt(3)]] < 10
    }
    # ...
}

# or

if = {
    limit = {
        @@[a + b * scope:char.age + sqrt(3)] < 10
    }
    # ...
}
Perl:
scope:actor = {
    add_prestige = @(abs(scope:recipient.age - this.age) + log(this.age))
    # or
    add_prestige = @{ abs(scope:recipient.age - this.age) + log(this.age) }
}
You have const expressions @[x + 1] but it is not the same.
Math inlined in script like this is indeed very limited in what it can do, but we use scripted math for this purpose all the time. If you're not aware, you can define a scripted calculated value in script_values and perform all these operations in sequence, even switch what algorithm or steps you use depending on scripted logic. Obedience, for example, is a fully scripted value in KotS, and while it may look like simple additive modifiers in most cases it's not limited to just that. Note that instead of log you have to use exp and invert.
 
  • 8
  • 2Like
Reactions:
Good dev diary. Thanks for the breakdown of the new game system.
 
  • 1Like
Reactions:
This looks cool, thank you as always for a look behind the curtain! Some questions, including a repeat from last time:

  • Will struggles be brought into situation code at some point, for simplicity / portability?
  • Are any struggles planned in Chapter IV?
Ok, were Situations mentioned before? Because that's the first time I heard of them and they sounds reall nice, this is actuall what I thought Struggles will be before it was revealed to be a heavily scripted thing and not procedually generated one. Nice to see this finally be realised.
Hello, thank you. I have a concern regarding the 'situations' — aren't you afraid of creating confusion by having them coexist with the 'struggles'? I read that you don’t plan to modify them, but this will create a redundant layer, two mechanisms serving roughly the same purpose. Are you planning to leave it like that?

And I also do not get the difference between Struggles and Situations, mechanically speaking. A cursory read tells me they're functionally the same and the former could be adapted into the latter. What am I missing?

Existing struggles will remain in the game as is, along with code support and modding features for it. There's enough differences between the systems to make transition of old content too risky and error-prone for very little benefit. All new content will be in the form of situations. Think of it as evolution of old struggles system into a better situations system.

Sometimes the only way to get an insight about how to make a good generic system - it to make lots of various use cases for it. Old struggles were only 2 examples with very specially tailored features. It was hard to scale it up and expand in the way designers need it now for Chapter 3. That's the reason for a fresh start
 
  • 22
  • 5Like
  • 1
Reactions:
Existing struggles will remain in the game as is, along with code support and modding features for it. There's enough differences between the systems to make transition of old content too risky and error-prone for very little benefit. All new content will be in the form of situations. Think of it as evolution of old struggles system into a better situations system.

Sometimes the only way to get an insight about how to make a good generic system - it to make lots of various use cases for it. Old struggles were only 2 examples with very specially tailored features. It was hard to scale it up and expand in the way designers need it now for Chapter 3. That's the reason for a fresh start
That's very good to know, and it makes perfect sense - thanks! As a follow-up, are there any Situations planned in Chapter 4 which have a Struggle-like ending - i.e. not just the permanently active seasons system?

Also, copying my other questions for any other devs to answer if they just skim the thread.
  1. Is there / will there be a way to designate some titles as coming after a name rather than before it - e.g. the title Khan?
  2. Will herders ever be selected from existing characters during a migration, or are they always generated fresh?
  3. Will struggles be brought into situation code at some point, for simplicity / portability?
  4. Are any struggles planned in Chapter IV?
  5. Is it possible (in code) for any character to have multiple different domiciles. To ask a different way, whilst all current domiciles are tied to title & government type, is it possible to tie them to something else (as well)?
 
Is it possible (in code) for any character to have multiple different domiciles. To ask a different way, whilst all current domiciles are tied to title & government type, is it possible to tie them to something else (as well)?

Yes and no. In order to keep existing script and content working, game's code and UI still treats only one domicile as active and current one - that one is used in links and triggers. On the other hand there's a new link from title to a domicile - so you can iterate over ruler's domain and try to do things on multiple domiciles that way. It was one of the potential benefits of the rework - not being limited by 1 domicile per person in theory. But as of now for release of Khans of the Steppe there's no promises and official support for multiple domiciles
 
Last edited:
  • 8
Reactions:
Existing struggles will remain in the game as is, along with code support and modding features for it. There's enough differences between the systems to make transition of old content too risky and error-prone for very little benefit. All new content will be in the form of situations. Think of it as evolution of old struggles system into a better situations system.

Sometimes the only way to get an insight about how to make a good generic system - it to make lots of various use cases for it. Old struggles were only 2 examples with very specially tailored features. It was hard to scale it up and expand in the way designers need it now for Chapter 3. That's the reason for a fresh start
Does this mean that new struggles going forward would use the situation system or that there are no planned new struggles going forward?
 
Does this mean that new struggles going forward would use the situation system or that there are no planned new struggles going forward?

I think there's a conflation of 2 separate things. There's code and script mechanics called old struggles and new situations that helps drive game content. There will be no new game content that uses old struggles code and script. There's game content about people having political struggles in various parts of the world. I don't know what kind of content about politics and people will be made in the future, whatever that content is going to be, it'll be based on the new situations system.
 
  • 9Like
  • 4
Reactions:
It was shown in the earlier dev diaries that the Steppe could be "expanded" to cover other regions through a decision. I suspect that that decision uses this new start_situation effect, with the dynamic sub_region creation depending on which region you chose for the decision.

When this is taken, will that new "Steppe" region appear in the same Great Steppe UI window shown before (possibly adding a scroll bar or something if a lot of regions are present), or will each new region get its own separate UI window?
 
I think there's a conflation of 2 separate things. There's code and script mechanics called old struggles and new situations that helps drive game content. There will be no new game content that uses old struggles code and script. There's game content about people having political struggles in various parts of the world. I don't know what kind of content about politics and people will be made in the future, whatever that content is going to be, it'll be based on the new situations system.
I think that answers my question. Basically all “struggles” going forward will be coded as situations, though the old ones for Iberia and Persia remain as they were originally coded.
 
  • 2
Reactions:
Perhaps for those of us who are truly mad, allow in code vassal held tributaries and tributary loops. It may break things yes, but it may also prove useful. Perhaps have a separate check where if a tributary loop does happen, remove map effects.
 
  • 2
Reactions: