| "Modding rules[1] state that DLC assets should not be made available via mods to users not owning that DLC. Thus DLC assets can be referenced in a custom portraits*.gfx file, so that the DLC is required to use the mod. But the sprites themselves cannot be added directly to the mod." |
Portraits are built by superposing layers of basic elements: background, generic head, facial elements (cheeks, hair, nose, ...), clothes, headgear, etc.
Each of these basic elements come with multiple variations or frames.
The choice of frame is either based on:
Children are an exception as they are created using a single image, hence children look similar.
There are two kind of characteristics: DNA and properties. Both are strings of letters (and possibly zeros for properties). They can be seen in-game by using console command charinfo.
DNA is a string of 11 letters inherited from the parents and doesn't change after birth.
For historical characters, their DNA string can be set in character history:
125501 = {
name="Temujin" # AKA: Genghis Khan
dynasty=11100
dna="bfimkolbecc"
(...)
}
Otherwise randomly generated characters will get random DNA strings, which are persisted in the game saves.
| Index | Used for |
|---|---|
| d0 | Neck |
| d1 | Chin |
| d2 | Mouth |
| d3 | Nose |
| d4 | Cheeks |
| d5 | Unused |
| d6 | Eyes |
| d7 | Ears |
| d8 | Hair Color |
| d9 | Eye Color |
| d10 | Unused |
So Genghis Khan's dna = "bfimkolbecc" means:
In case there are less frames than the index of the letter in alphabet, it wraps around. For instance, for chins there are usually 4 frames, so a = 1st frame and e = 1st frame as well.
Properties are a string of up to 14 letters (in vanilla). If the string is shorter, zeros will be added at the end.
Only hair (p1) and beards (p4) can be changed in-game via the Customization Pack, the other property values are derived from portrait_properties.txt file.
It is possible to add new properties with the following:
spriteType = {
name = "GFX_custom"
texturefile = "gfx\\characters\\shared\\new_property.dds"
noOfFrames = 2
norefcount = yes
can_be_lowres = yes
}
# p18
18 = {
0 = {
factor = 50
}
1 = {
factor = 50
}
}
"GFX_custom:p18"Based on player's experimentations, here is a description of how the rendering of portraits works in-game. Note that part of the logic has also been re-implemented in Portrait Builder tool, for an out-of-game rendering.
For child portraits:
The game renders feudal adult portraits as follows:
The rendering is the same as feudal characters, except for headgear and clothing layers:
The rendering is the same as feudal characters, except for headgear and clothing layers. It uses hardcoded sprites GFX_merchant_male_clothes, GFX_merchant_male_headgear, etc. instead of the sprites defined in portrait.gfx
With patch 2.7 a new mechanism was added to override the clothing layers based on rules.
The only examples in vanilla are from \interface\portraits\society_clothes.gfx in dlc070.zip
The general structure is the following:
portraitType = {
name = "PORTRAIT_<override_type>_clothing_male"
weight = {
additive_modifier = {
value = 10000
# Conditions (in portrait scope) for modifier to apply
}
}
layer = { # GFX_empty can be used to disable a layer
"GFX_xxx_male_clothing_behind:c0"
"GFX_xxx_male_headgear_behind:c1"
"GFX_xxx_male_clothing_front:c2"
"GFX_xxx_male_headgear_mid:c3"
"GFX_xxx_male_clothing_infront:c4"
"GFX_xxx_male_headgear_front:c5"
}
allow_property_values = {
<property_index> = {
<frame_index> = {
# Conditions (in portrait scope) for frame to be used
}
}
}
}
Notes:
Note: extra culture index cannot be added dynamically by modders.
allow_property_values block can be used in a similar way to portrait_properties.txt to select the frames for p3 (clothes) and p5 (headgear) in the overridden sprites of the layer block.A new scope is used, which is a sort of limited version of a character scope, with conditions prefixed with portrait_.
| Condition | Type | Used in vanilla | Description | Example |
|---|---|---|---|---|
| portrait_age | child/oldage | ✓ | Age of character compared to a portrait threshold (child, young, middle or old). As the thresholds are configurable, the numeric values are not directly hardcoded here. | portrait_age > child
|
| portrait_is_female | bool | ✓ | Whether character is a female | portrait_is_female = yes
|
| portrait_has_trait | trait | ✓ | Whether character has the trait | portrait_has_trait = vaishnavist_hindu
|
| portrait_religion | religion | X | [Seen in the .exe - to be tested] | |
| portrait_culture | culture | ✓ | Character culture | portrait_culture = greek
|
| portrait_culture_group | culture_group | ✓ | portrait_culture_group = latin
| |
| portrait_gfx_culture | ? | X | [Seen in the .exe - to be tested] | |
| portrait_government | government | X | Whether character has the specified government. Seems to only work on landed characters. | |
| portrait_tier | tier | ✓ | portrait_tier = king
| |
| portrait_title_tier | ? | X | [Seen in the .exe - to be tested] | |
| portrait_society | society | ✓ | portrait_society = monastic_order_benedictine
| |
| portrait_society_rank | int | ✓ | Character rank if member of a society | portrait_society_rank = 1
|
| portrait_clothing | bool | ✓ | Warning: portrait_clothing = no appears to be broken.
|
portrait_clothing = yes
|
| portrait_offmap | offmap_power | ✓ | Whether the character rules the given offmap. | portrait_offmap = offmap_china
|
| portrait_is_patrician | bool | X | Whether the character is in a merchant republic and their employer patrician or has a republic government form. | portrait_is_patrician = yes
|
| portrait_in_command | bool | X | Whether the character is in command and leading any troops. | portrait_in_command = yes
|
It is possible to create new ethnicities by creating new assets and/or mixing existing vanilla or DLC assets in portraitTypes layers.
For instance a customgfx ethnicity with norsegfx faces and byzantinegfx clothes.
If creating image sprites from scratch, you need to:
spriteTypes = {
spriteType = {
name = "GFX_gothic_male_clothes"
texturefile = "gfx\\characters\\gothic_male\\gothic_male_clothes.dds"
noOfFrames = 12
norefcount = yes
can_be_lowres = yes
}
...
}
Reusing DLC assets is easier than creating new one, but because the DLC assets cannot themselves be bundled into the mod,[2] users who don't own the DLC(s) containing these assets (ex: the Norse Portraits DLC) will see gothicgfx portraits with clothes but no heads.
The reason is that, as soon as some portraitTypes entry for gothicgfx are defined, the game will render them, even if the layers refer to unknown assets and will not show up properly The fallback to another ethnicity in graphical_cultures list (or default westerngfx) only happens if no portraitType entry is found at all !
There are some solutions to this problem:
To define a new gothicgfx ethnicity, here are the steps:
gothicgfx = {
skin_tone = 0
}
graphical_cultures = { gothicgfx occitangfx }
Note: if using sub-mods, it is important that the last culturegfx in the list be one of the vanilla base types (occitangfx, muslimgfx, byzantinegfx, westerngfx). In case it is westerngfx, it can be omitted as it is the default, or used as 3 layers of ethnicities. If using fallback portraitTypes, this is not required.
spriteTypes = {
spriteType = {
name = "PORTRAIT_gothicgfx_child_male"
}
spriteType = {
name = "PORTRAIT_gothicgfx_child_female"
}
portraitType = {
name = "PORTRAIT_gothicgfx_male"
}
portraitType = {
name = "PORTRAIT_gothicgfx_male1"
}
portraitType = {
name = "PORTRAIT_gothicgfx_male2"
}
portraitType = {
name = "PORTRAIT_gothicgfx_female"
}
portraitType = {
name = "PORTRAIT_gothicgfx_female1"
}
portraitType = {
name = "PORTRAIT_gothicgfx_female2"
}
}
portraitType = {
name = "PORTRAIT_gothicgfx_female"
effectFile = "gfx/FX/portrait.lua"
layer = { # GFX_TYPE:[d|p]INDEX:COLOR_LINK:DONT_REFRESH_IF_VALID:CULTURE_INDEX
"GFX_character_background:p0"
"GFX_byzantine_female_clothes_behind:p3:c0"
"GFX_byzantine_female_headgear_behind:p5:c1"
"GFX_norse_female_hair_behind:p1:h:y"
"GFX_norse_female_base:p2"
"GFX_norse_female_neck:d0"
"GFX_norse_female_mouth:d2"
"GFX_norse_female_nose:d3"
"GFX_norse_female_chin:d1"
"GFX_norse_female_cheeks:d4"
"GFX_norse_female_eyes:d6"
"GFX_norse_female_eyes2:d6:e"
"GFX_character_scars:p7:y"
"GFX_character_reddots:p8"
"GFX_character_boils:p9"
"GFX_character_blinded_eyes:p10"
"GFX_norse_female_ear:d7"
"GFX_byzantine_female_clothes:p3:c2"
"GFX_empty:p5:c3"
"GFX_norse_female_hair:p1:h:y"
"GFX_empty:p3:c4"
"GFX_byzantine_female_headgear:p5:c5"
"GFX_character_imprisoned:p6"
"GFX_player_overlay:p11"
}
To display static pre-rendered portraits, there are a few techniques:
| This technique has become obsolete with patch 2.6, given that new properties layers can now be modded, rather than modifying an existing layer. |
Using a miscellaneous layer (for instance blinded_eyes) and add frames for pre-rendered portraits:[3]
# p10 blinded
10 = {
0 = {
factor = 100
modifier = {
factor = 0
trait = blinded
}
modifier = {
factor = 0
#Either a character flag or a unique trait.
}
}
1 = {
factor = 100
modifier = {
factor = 0
NOT = {
trait = blinded
}
}
modifier = {
factor = 0
#Either a character flag or a unique trait.
}
}
2 = {
factor = 100
modifier = {
factor = 0
NOT = {
#Either a character flag or a unique trait.
}
}
}
}
Using occluded = yes in character history; this is used for Muhammad (The Prophet). Big limitation is that everyone with occluded = yes will have same portrait. It uses a single frame texture with hardcoded name Muhammad.tga:
spriteType = {
name = "GFX_Muhammad"
texturefile = "gfx\\characters\\Muhammad.tga"
noOfFrames = 1
norefcount = yes
}
Using a custom ethnicity, and setting it in character history, or via event using set_graphical_culture command.
Because the commands requires a culture as argument, a custom culture definition must be added too.
Also the ethnicity being randomly inherited from one of the parents at birth, some on_action events may be needed to control things.
The steps are:
special = {
graphical_cultures = { specialgfx }
...
}
spriteType = {
name = "GFX_special"
texturefile = "gfx\\characters\\special.tga"
noOfFrames = 1
norefcount = yes
}
portraitType = {
name = "PORTRAIT_specialgfx_male"
effectFile = "gfx/FX/portrait.lua"
layer = { # GFX_TYPE:[d|p]INDEX:COLOR_LINK:DONT_REFRESH_IF_VALID:CULTURE_INDEX
"GFX_character_background:p0"
"GFX_special:p2"
"GFX_character_imprisoned:p6"
}
hair_color = { { 10 10 10 } { 50 50 50 } { 255 255 255 } } #Must be included.
eye_color = { { 255 255 255} } # Leaving these out will crash the game.
}
portraitType = {
name = "PORTRAIT_specialgfx_female"
... #The rest is same as above. Both *_male and *_female portraitType are required, even for static portraits.
}
set_graphical_culture = special command and graphical_culture = specialgfx condition in events.| 历史 | 角色 • 家族 • 省份 • 头衔 • 剧本 |
| 脚本 | 指令 • 条件 • 作用域 • 修正 • 事件 • 决议 |
| 常规 | 定义 • 游戏规则 • 另类开局 • 宗教 • 文化 • 政体 • 特质 • 血脉 • 科技 • 法律 • 建筑 • 宣战理由 • 朝贡国 • 单位 • 目标 • 疾病 • 死亡 • 荣誉头衔 • 社团 • 宝物 • 地图外政权 • 内阁成员 • 贸易路线 • 继承 • 奇观 • 称号 |
| 图像/音效/本地化 | 地图 • 图形 • 盾徽 • 肖像 • 界面 • 小地图 • 音乐 • 本地化 |
| 其他 | 故障排除 • 验证器 • 控制台指令 • 编辑游戏存档 • Steam创意工坊 • EU4转档器模组制作 |
Character moddingCultureCulture moddingCustomization PackDNADefinesEU4转档器模组制作EthnicityGraphical DLCGraphics moddingPatch 2.6Patch 2.7Portrait BuilderScopeSteam创意工坊Triggers事件模组制作作用域修正内阁成员模组制作决议模组制作剧本模组制作单位模组制作历史模组制作另类开局模组制作图形模组制作地图外政权模组制作地图模组制作头衔模组制作奇观模组制作宗教模组制作定义宝物模组制作宣战理由模组制作家族模组制作小地图模组制作建筑模组制作指令控制台指令政体模组制作故障排除文化模组制作朝贡国类型模组制作本地化条件模组制作死亡模组制作法律模组制作游戏规则模组制作特质模组制作界面模组制作疾病模组制作目标模组制作盾徽模组制作省份模组制作社团模组制作科技模组制作称号模组制作继承模组制作编辑游戏存档