It took me a very long time, but I finally managed - using publicly available resources as a base (and highly modifying most of them) and creating some things from scratch (for example male piercing) I have created a replacer for male and female that covers:
- bodies (incl. hands and feet)
- faces (meshes, textures)
- hairstyles (vanilla hairstyles are not replaced, just reshaped to fit the heads where necessary, new hairstyles are also added, but they don't replace anything)
- beards (vanilla beards are not replaced, just reshaped to fit heads)
- jewelry (jewelry pieces are added as beards, meaning that women can use them no problem, but for men it's a choice between a beard and a piercing)
- missing female voices
Screenshots and files are available here, code necessary to implement it in your mod is below.
Big thanks to SupaNinjaMan who helped me get those male piercings working.
First make sure to put all the downloaded resources in your mod folder: Data, Resources and Textures.
Then modify module.ini so the game reads the added files.
Because we're adding jewelry to beard slot, we should rename the button from Beard to something else. May I suggest "Face Detail" (personal choice) or "Extra" (like in Napoleonic Wars).
If you don't have languages/en/ui.csv in your mod folder, then copy it from game's root folder. Then open ui.csv, find ui_change_beard|Beard and change it to:
Next let's declare new sound files in module_sounds.py:
The rest of the work happens in module_skins.py. Because it's not a big file and almost all the lines get changed or touched one way or another, I'm just gonna paste all of it here, with descriptive comments in the code (double hash, ##, means a vanilla line that I commented out as part of the mod changes):
One thing worth pointing out is the order of face declarations. The order I pasted above is not vanilla - it will replace all black faces with mid-east looking ones. This is intended, because:
1. vanilla Warband has no skins for mid-east Sarraninds
2. black people are less likely to be found in Europe-based Calradia, than arabs/turks
So I give priority to them, especially because my intention is to change the face codes in module_troops.py too, for better fit. This isn't covered here, I'm planning a separate post for that.
If you want to keep things vanilla, you should have the faces like this instead:
men:
women:
Edit 2023.05.18:
1 vanilla hairstyle (the one Klethi uses) had clipping issues on the forehead, so I fixed the mesh and included it in the BRF.
To avoid name conflicts, it has a new name, which means an update to module_skins.py as well. Code above updated.
Edit 2023.05.19:
Testing shows a weird, hardcoded limit of 22 hairstyles for NPCs, making hairstyles #23 and later available only for the player... I'm changing the order of hairstyles in the module_skins.py to make sure NPCs can access the hairstyles which I consider the most lore-friendly.
Also, hairstyle rndl_w_hair_24 had some bad UV mapping on the hair tie, so I fixed that too.
Edit 2023.05.27:
Thanks to @Cokjan I've got my hands on a better female head mesh with more sliders - I'm updating the pack to replace the existing resources with better replacements. There is no rose without thorns though - the new head mesh deforms earrings more than the previous one, because it has sliders affecting that area. To compensate, I had to reduce the size of the biggest earrings by 38%. Another side effect of the new head mesh is that females no longer look like pretty top models - now only a certain combination of sliders results in pretty faces, and I honestly haven't been able to re-create with sliders the level of beauty the previous mesh was offering... So, no more top models in your game. On the other hand, with the previous mesh all women looked like clones of the same top model, so I still mark this as improvement. A bittersweet victory, but victory nonetheless.
Also, I've updated the aged female textures so they look a bit more like they are old and less like zombies... Whether I succeeded or not - you be the judge. I'm not very happy with how they look, but I was even less happy with the previous ones, so... I'll take it.
- bodies (incl. hands and feet)
- faces (meshes, textures)
- hairstyles (vanilla hairstyles are not replaced, just reshaped to fit the heads where necessary, new hairstyles are also added, but they don't replace anything)
- beards (vanilla beards are not replaced, just reshaped to fit heads)
- jewelry (jewelry pieces are added as beards, meaning that women can use them no problem, but for men it's a choice between a beard and a piercing)
- missing female voices
Screenshots and files are available here, code necessary to implement it in your mod is below.
Big thanks to SupaNinjaMan who helped me get those male piercings working.
First make sure to put all the downloaded resources in your mod folder: Data, Resources and Textures.
Then modify module.ini so the game reads the added files.
make sure these are both set to 1:
Below all the load_resource commands add these:
You could also change this line from 0 to 1, but it's strictly cosmetic, towards users that might read your module.ini.
My testing shows that female accessories will work without this change just fine.
INI:
scan_module_sounds = 1
scan_module_textures = 1
INI:
#MOD BEGIN - better bodies and faces
load_mod_resource = rndl_common
load_mod_resource = rndl_m_body
load_mod_resource = rndl_m_head
load_mod_resource = rndl_w_body
load_mod_resource = rndl_w_head
#MOD END - better bodies and faces
INI:
has_accessories_for_female = 1
Because we're adding jewelry to beard slot, we should rename the button from Beard to something else. May I suggest "Face Detail" (personal choice) or "Extra" (like in Napoleonic Wars).
If you don't have languages/en/ui.csv in your mod folder, then copy it from game's root folder. Then open ui.csv, find ui_change_beard|Beard and change it to:
Code:
ui_change_beard|Face Detail
Next let's declare new sound files in module_sounds.py:
Python:
#MOD BEGIN - more female voices
("rndl_woman_grunt",sf_priority_6|sf_vol_4,["DR_fem_attack.ogg","MW_woman_hit_11.ogg","DR_femgrunt1.ogg","DR_femgrunt2.ogg","DR_femgrunt6.ogg","DR_femgrunt8.ogg","DR_femgrunt9.ogg","DR_femgrunt10.ogg"]),
("rndl_woman_grunt_long",sf_priority_6|sf_vol_7,["freesound_org_439516_23.ogg","freesound_org_439516_24.ogg","freesound_org_439516_25.ogg","freesound_org_439516_31.ogg","freesound_org_439516_32.ogg","freesound_org_439516_33.ogg"]),
("rndl_woman_stun",sf_priority_3|sf_vol_8,["MW_woman_hit_1.ogg","DR_gruntfem1.ogg","DR_gruntfem3.ogg","DR_gruntfem7.ogg"]),
("rndl_woman_victory",sf_priority_5|sf_vol_10,["freesound_org_222646.ogg","freesound_org_256156_08.ogg","freesound_org_439516_26.ogg","freesound_org_520264.ogg","SWC_womancheer1_2.ogg","SWC_wooaao.ogg","woman_yell_1.ogg","woman_yell_2.ogg"]),
#MOD END - more female voices
The rest of the work happens in module_skins.py. Because it's not a big file and almost all the lines get changed or touched one way or another, I'm just gonna paste all of it here, with descriptive comments in the code (double hash, ##, means a vanilla line that I commented out as part of the mod changes):
Python:
###################################################################################
#Prefix: none #
#Each skin record contains the following fields: #
#1) Skin id: used for referencing skins. #
#2) Skin flags. Not used yet. Should be 0. #
#3) Body mesh. #
#4) Calf mesh (left one). #
#5) Hand mesh (left one). #
#6) Head mesh. #
#7) Face keys (list). #
#8) List of hair meshes. #
#9) List of beard meshes. #
#10) List of hair materials. #
#11) List of beard materials. #
#12) List of face materials. #
#13) List of voices. #
#14) Skeleton name. #
#15) Scale (doesn't fully work yet). #
#16) Blood particles 1 (do not add this if you wish to use the default particles).#
#17) Blood particles 2 (do not add this if you wish to use the default particles).#
#17) Face key constraints (do not add this if you do not wish to use it). #
###################################################################################
from header_skins import *
from ID_particle_systems import *
man_face_keys = [
#MOD BEGIN - better bodies and faces
##( 20,0, 0.70,-0.60,"Chin Size"),
##(260,0,-0.60, 1.40,"Chin Shape"),
##( 10,0,-0.50, 0.90,"Chin Forward"),
##(240,0, 0.90,-0.80,"Jaw Width"),
##(210,0,-0.50, 1.00,"Jaw Position"),
##(250,0, 0.80,-1.00,"Mouth-Nose Distance"),
##(200,0,-0.30, 1.00,"Mouth Width"),
##( 50,0,-1.50, 1.00,"Cheeks"),
##( 60,0,-0.40, 1.35,"Nose Height"),
##( 70,0,-0.60, 0.70,"Nose Width"),
##( 80,0, 1.00,-0.10,"Nose Size"),
##(270,0,-0.50, 1.00,"Nose Shape"),
##( 90,0,-0.20, 1.40,"Nose Bridge"),
##(100,0,-0.30, 1.50,"Cheek Bones"),
##(150,0,-0.20, 3.00,"Eye Width"),
##(110,0, 1.50,-0.90,"Eye to Eye Dist"),
##(120,0, 1.90,-1.00,"Eye Shape"),
##(130,0,-0.50, 1.10,"Eye Depth"),
##(140,0, 1.00,-1.20,"Eyelids"),
##(160,0, 1.30,-0.20,"Eyebrow Position"),
##(170,0,-0.10, 1.90,"Eyebrow Height"),
##(220,0,-0.10, 0.90,"Eyebrow Depth"),
##(180,0,-1.10, 1.60,"Eyebrow Shape"),
##(230,0, 1.20,-0.70,"Temple Width"),
##( 30,0,-0.60, 0.90,"Face Depth"),
##( 40,0, 0.90,-0.60,"Face Ratio"),
##(190,0, 0.00, 0.95,"Face Width"),
##(280,0, 0.00, 1.00,"Post-Edit"),
#they are in different order now too, and some vanilla sliders are missing, some are new
(240,0,-0.40, 0.30,"Chin Size"),
(230,0,-0.40, 0.80,"Chin Shape"),
(250,0,-0.25, 0.55,"Chin Forward"),
(130,0,-0.50, 1.00,"Jaw Width"),
(120,0,-0.50, 0.60,"Lower Lip"),
(110,0,-0.20, 0.60,"Upper Lip"),
(100,0, 0.20,-0.20,"Mouth-Nose Distance"),
( 90,0, 0.55,-0.55,"Mouth Width"),
( 30,0,-0.30, 0.30,"Nostril Size"),
( 60,0, 0.25,-0.25,"Nose Height"),
( 40,0,-0.20, 0.30,"Nose Width"),
( 70,0,-0.30, 0.40,"Nose Size"),
( 50,0, 0.20,-0.30,"Nose Shape"),
( 80,0,-0.30, 0.65,"Nose Bridge"),
(160,0,-0.20, 0.25,"Eye Width"),
(190,0,-0.25, 0.15,"Eye to Eye Dist"),
(170,0,-0.85, 0.85,"Eye Shape"),
(200,0,-0.30, 0.70,"Eye Depth"),
(180,0,-1.50, 1.50,"Eyelids"),
( 20,0, 0.60,-0.25,"Cheeks"),
(260,0,-0.60, 0.50,"Cheek Bones"),
(220,0, 0.80,-0.80,"Eyebrow Height"),
(210,0,-0.75, 0.75,"Eyebrow Shape"),
( 10,0,-0.60, 0.50,"Temple Width"),
(270,0,-0.30, 1.00,"Face Depth"),
(150,0,-0.25, 0.45,"Face Ratio"),
(140,0,-0.40, 0.50,"Face Width"),
(280,0, 1.00, 1.00,"Post-Edit"),
#MOD END - better bodies and faces
]
woman_face_keys = [
#MOD BEGIN - better bodies and faces
##(230,0, 0.8,-1.0, "Chin Size"),
##(220,0,-1.0, 1.0, "Chin Shape"),
##( 10,0,-1.2, 1.0, "Chin Forward"),
##( 20,0,-0.6, 1.2, "Jaw Width"),
##( 40,0,-0.7, 1.0, "Jaw Position"),
##(270,0, 0.9,-0.9, "Mouth-Nose Distance"),
##( 30,0,-0.5, 1.0, "Mouth Width"),
##( 50,0,-0.5, 1.0, "Cheeks"),
##( 60,0,-0.5, 1.0, "Nose Height"),
##( 70,0,-0.5, 1.1, "Nose Width"),
##( 80,0, 1.5,-0.3, "Nose Size"),
##(240,0,-1.0, 0.8, "Nose Shape"),
##( 90,0, 0.0, 1.1, "Nose Bridge"),
##(100,0,-0.5, 1.5, "Cheek Bones"),
##(150,0,-0.4, 1.0, "Eye Width"),
##(110,0, 1.0, 0.0, "Eye to Eye Dist"),
##(120,0,-0.2, 1.0, "Eye Shape"),
##(130,0,-0.1, 1.6, "Eye Depth"),
##(140,0,-0.2, 1.0, "Eyelids"),
##(160,0,-0.2, 1.2, "Eyebrow Position"),
##(170,0,-0.2, 0.7, "Eyebrow Height"),
##(250,0,-0.4, 0.9, "Eyebrow Depth"),
##(180,0,-1.5, 1.2, "Eyebrow Shape"),
##(260,0, 1.0,-0.7, "Temple Width"),
##(200,0,-0.5, 1.0, "Face Depth"),
##(210,0,-0.5, 0.9, "Face Ratio"),
##(190,0,-0.4, 0.8, "Face Width"),
##(280,0, 0.0, 1.0, "Post-Edit"),
#female mesh has a very limited slider functionality
( 40,0,-1.0, 0.0, "Caucassian 2"),
( 30,0, 0.0, 1.0, "Caucassian 1"),
( 10,0, 0.0, 1.0, "Forehead"),
(280,0, 0.0, 1.0, "Post-Edit"),
#MOD END - better bodies and faces
]
chin_size = 0
chin_shape = 1
chin_forward = 2
jaw_width = 3
jaw_position = 4
mouth_nose_distance = 5
mouth_width = 6
cheeks = 7
nose_height = 8
nose_width = 9
nose_size = 10
nose_shape = 11
nose_bridge = 12
cheek_bones = 13
eye_width = 14
eye_to_eye_dist = 15
eye_shape = 16
eye_depth = 17
eyelids = 18
eyebrow_position = 19
eyebrow_height = 20
eyebrow_depth = 21
eyebrow_shape = 22
temple_width = 23
face_depth = 24
face_ratio = 25
face_width = 26
comp_less_than = -1;
comp_greater_than = 1;
skins = [
("man",0,
#MOD BEGIN - better bodies and faces
##"man_body","man_calf_l","m_handL","male_head", #body/calf/hand/head meshes
"rndl_m_body","rndl_m_calf_l","rndl_m_hand_l","rndl_m_head", #body/calf/hand/head meshes
#MOD END - better bodies and faces
man_face_keys, #face keys
[
#hair meshes - theoretical limit is 63 items, that's how many the face key can store without value overflow
#however, for NPCs (tested on NPCs with set face codes, not with random in range) the game engine seems to have a hardcoded limit of 22 items, and setting the face code to anything higher results in the character having no hair
#for player the above limit of 22 doesn't apply, so if you want more hairstyles than 22, then think which ones should only be accessible for the player and put them at the end of the list
#MOD BEGIN - better bodies and faces
#00 = bald
"rndl_m_hair_s", #01 ##"man_hair_s",
"rndl_m_hair_m", #02 ##"man_hair_m",
"rndl_m_hair_n", #03 ##"man_hair_n",
"rndl_m_hair_o", #04 ##"man_hair_o",
"rndl_m_hair_y10", #05 ##"man_hair_y10",
"rndl_m_hair_y12", #06 ##"man_hair_y12",
"rndl_m_hair_p", #07 ##"man_hair_p",
"rndl_m_hair_r", #08 ##"man_hair_r",
"rndl_m_hair_q", #09 ##"man_hair_q",
"rndl_m_hair_v", #10 ##"man_hair_v",
"rndl_m_hair_t", #11 ##"man_hair_t",
"rndl_m_hair_y6", #12 ##"man_hair_y6",
"rndl_m_hair_y3", #13 ##"man_hair_y3",
"rndl_m_hair_y7", #14 ##"man_hair_y7",
"rndl_m_hair_y9", #15 ##"man_hair_y9",
"rndl_m_hair_y11", #16 ##"man_hair_y11",
"rndl_m_hair_u", #17 ##"man_hair_u",
"rndl_m_hair_y", #18 ##"man_hair_y",
"rndl_m_hair_y2", #19 ##"man_hair_y2",
"rndl_m_hair_y4", #20 ##"man_hair_y4",
"rndl_m_hair_1", #21
"rndl_m_hair_2", #22 (last hairstyle available for NPCs, if we add more they will be strictly player-exclusive)
#MOD END - better bodies and faces
],
[
#beard meshes - theoretical limit is 63 items, that's how many the face key can store without value overflow
#if there is a lower hardcoded limit in the engine, like there is for hair, then I haven't found it (I tested a list of 38 meshes)
#for men the non-beard mesh names must start with "accessory_" in this file and in BRF, otherwise they will change color according to hair color, like beards do)
#MOD BEGIN - better bodies and faces
#00 = no beard, no accessories
"rndl_beard_e", #01 ##"beard_e",
"rndl_beard_d", #02 ##"beard_d",
"rndl_beard_k", #03 ##"beard_k",
"rndl_beard_l", #04 ##"beard_l",
"rndl_beard_i", #05 ##"beard_i",
"rndl_beard_j", #06 ##"beard_j",
"rndl_beard_z", #07 ##"beard_z",
"rndl_beard_m", #08 ##"beard_m",
"rndl_beard_n", #09 ##"beard_n",
"rndl_beard_y", #10 ##"beard_y",
"rndl_beard_p", #11 ##"beard_p",
"rndl_beard_o", #12 ##"beard_o",
"rndl_beard_v", #13 ##"beard_v",
"rndl_beard_f", #14 ##"beard_f",
"rndl_beard_b", #15 ##"beard_b",
"rndl_beard_c", #16 ##"beard_c",
"rndl_beard_t", #17 ##"beard_t",
"rndl_beard_u", #18 ##"beard_u",
"rndl_beard_r", #19 ##"beard_r",
"rndl_beard_s", #20 ##"beard_s",
"rndl_beard_a", #21 ##"beard_a",
"rndl_beard_h", #22 ##"beard_h",
"rndl_beard_g", #23 ##"beard_g",
"accessory_rndl_m_nose_side_silver", #24
"accessory_rndl_m_nose_cow_silver", #25
"accessory_rndl_m_ear_right_silver", #26
"accessory_rndl_m_ears_x1_silver", #27
"accessory_rndl_m_ears_x5_silver", #28
"accessory_rndl_m_nose_side_gold", #29
"accessory_rndl_m_nose_cow_gold", #30
"accessory_rndl_m_ear_right_gold", #31
"accessory_rndl_m_ears_x1_gold", #32
"accessory_rndl_m_ears_x5_gold", #33
"accessory_rndl_m_nose_side_copper", #34
"accessory_rndl_m_nose_cow_copper", #35
"accessory_rndl_m_ear_right_copper", #36
"accessory_rndl_m_ears_x1_copper", #37
"accessory_rndl_m_ears_x5_copper", #38
#MOD END - better bodies and faces
],
#MOD BEGIN - better bodies and faces
#just a cleanup here - leaving necessary materials, removing the ones ignored by game engine
##["hair_blonde","hair_red","hair_brunette","hair_black","hair_white"],
##["beard_blonde","beard_red","beard_brunette","beard_black","beard_white"],
["hair_blonde"],
["beard_blonde"],
#MOD END - better bodies and faces
[
#face materials
#MOD BEGIN - better bodies and faces
("rndl_m_face_00",0xFFB2AE9D,["hair_blonde"],[0xFFFFFFFF,0xFFD6AF9E,0xFFAD603E,0xFF7E452B,0xFF502A19]), #00 blonde young ##("manface_young_2", 0xFFCBE0E0,["hair_blonde"],[0xFFFFFFFF, 0xFFB04717, 0xFF502A19]),
("rndl_m_face_01",0xFFB2B39E,["hair_blonde"],[0xFFFFFFFF,0xFFD7A38B,0xFFB04717,0xFF803818,0xFF502A19]), #01 blonde midage ##("manface_midage", 0xFFDFEFE1,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF632E18,0xFF502A19,0xFF19100C]),
("rndl_m_face_02",0xFFC0CFCF,["hair_blonde"],[0xFFB04717,0xFF983F17,0xFF803818,0xFF683118,0xFF502A19]), #02 ginger ##("manface_young", 0xFFD0E0E0,["hair_blonde"],[0xFF83301A, 0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_m_face_03",0xFFD1E1E1,["hair_blonde"],[0xFF341D12,0xFF19100C,0xFF16100D,0xFF13100F,0xFF111111]), #03 brunette white ##("manface_young_3", 0xFFDCEDED,["hair_blonde"],[0xFF2F180E, 0xFF171313, 0xFF07080C]),
("rndl_m_face_04",0xFFA8B4AF,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #04 brunette dark ##("manface_7", 0xFFC0C8C8,["hair_blonde"],[0xFF171313, 0xFF07080C]),
("rndl_m_face_05",0xFFC2B9C8,["hair_blonde"],[0xFF502A19,0xFF341D12,0xFF19100C,0xFF111111,0xFF0C0D19]), #05 heavy drinker ##("manface_midage_2",0xFDE4C8D8,["hair_blonde"],[0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_m_face_06",0xFF9E99A3,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #06 steppe skin ##("manface_rugged", 0xFFB0AAB5,["hair_blonde"],[0xFF171313, 0xFF07080C]),
("rndl_m_face_08",0xFF948D7D,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #07 new: mid-east 1 <-- putting these before african face will mess up facecodes of troops that look african, but: 1. it will make for more usable facecode ranges, 2. we'd be removing black faces anyway, and now for women we don't have to
("rndl_m_face_09",0xFFA19691,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #08 new: mid-east 2 <-- putting these before african face will mess up facecodes of troops that look african, but: 1. it will make for more usable facecode ranges, 2. we'd be removing black faces anyway, and now for women we don't have to
("rndl_m_face_10",0xFFA8A8A8,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #09 new: mid-east 3 <-- putting these before african face will mess up facecodes of troops that look african, but: 1. it will make for more usable facecode ranges, 2. we'd be removing black faces anyway, and now for women we don't have to
("rndl_m_face_07",0xFF706D79,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #10 african ##("manface_african", 0xFF807C8A,["hair_blonde"],[0xFF120808, 0xFF07080C]),
("rndl_m_face_11",0xFFB3BABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #11 new: white 1
("rndl_m_face_12",0xFFBEBABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #12 new: white 2
("rndl_m_face_13",0xFFB3BABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #13 new: white 3
("rndl_m_face_14",0xFFCCC5A9,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #14 new: asian 1
("rndl_m_face_15",0xFFC7C5B4,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #15 new: asian 2
("rndl_m_face_16",0xFFA87F60,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #16 new: asian 3
("rndl_m_face_17",0xFF7A5D4E,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #17 new: african 1
("rndl_m_face_18",0xFF8C7263,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #18 new: african 2
("rndl_m_face_19",0xFF816C57,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #19 new: african 3
#MOD END - better bodies and faces
],
[
#vocalization sounds
(voice_die,"snd_man_die"),
(voice_hit,"snd_man_hit"),
(voice_grunt,"snd_man_grunt"),
(voice_grunt_long,"snd_man_grunt_long"),
(voice_yell,"snd_man_yell"),
(voice_stun,"snd_man_stun"),
(voice_victory,"snd_man_victory"),
],
"skel_human",1.0,psys_game_blood,psys_game_blood_2,
[
#MOD BEGIN - better bodies and faces
##[1.7,comp_greater_than,(1.0,face_width),(1.0,temple_width)], #constraints: ex: 1.7 > (face_width + temple_width)
##[0.3,comp_less_than,(1.0,face_width),(1.0,temple_width)],
##[1.7,comp_greater_than,(1.0,face_width),(1.0,face_depth)],
##[0.3,comp_less_than,(1.0,eyebrow_height),(1.0,eyebrow_position)],
##[1.7,comp_greater_than,(1.0,eyebrow_height),(1.0,eyebrow_position)],
##[-0.7,comp_less_than,(1.0,nose_size),(-1.0,nose_shape)],
##[0.7,comp_greater_than,(1.0,nose_size),(-1.0,nose_shape)],
##[2.7,comp_greater_than,(1.0,chin_size),(1.0,mouth_nose_distance),(1.0,nose_height),(-1.0,face_width)],
[1.6,comp_greater_than,(1.0,eye_to_eye_dist),(1.0,temple_width)],
[0.6,comp_less_than,(1.0,eye_to_eye_dist),(1.0,temple_width)],
[1.5,comp_greater_than,(1.0,face_ratio),(1.0,mouth_width)],
[0.6,comp_greater_than,(-1.0,nose_width),(1.0,mouth_width)],
[-1.0,comp_less_than,(-1.0,nose_width),(1.0,mouth_width)],
#MOD END - better bodies and faces
]
),
("woman",skf_use_morph_key_10,
#MOD BEGIN - better bodies and faces
##"woman_body","woman_calf_l","f_handL","female_head", #body/calf/hand/head meshes
"rndl_w_body","rndl_w_calf_l","rndl_w_hand_l","rndl_w_head", #body/calf/hand/head meshes
#MOD END - better bodies and faces
woman_face_keys, #face keys
#MOD BEGIN - better bodies and faces
[
#hair meshes
#hair meshes - theoretical limit is 63 items, that's how many the face key can store without value overflow
#however, for NPCs (tested on NPCs with set face codes, not with random in range) the game engine seems to have a hardcoded limit of 22 items, and setting the face code to anything higher results in the character having no hair
#for player the above limit of 22 doesn't apply, so if you want more hairstyles than 22, then think which ones should only be accessible for the player and put them at the end of the list
"woman_hair_p", #01
"woman_hair_n", #02
"woman_hair_o", #03
"woman_hair_q", #04
"woman_hair_r", #05
"woman_hair_t", #06
#MOD BEGIN - better bodies and faces
"rndl_woman_hair_s", #07 ##"woman_hair_s", #had to be replaced with tweaked mesh due to hair clipping
"rndl_w_hair_01", #08
"rndl_w_hair_02", #09
"rndl_w_hair_23", #10
"rndl_w_hair_24", #11
"rndl_w_hair_09", #12
"rndl_w_hair_13", #13
"rndl_w_hair_16", #14
"rndl_w_hair_21", #15
"rndl_w_hair_18", #16
"rndl_w_hair_20", #17
"rndl_w_hair_04", #18
"rndl_w_hair_11", #19
"rndl_w_hair_12", #20
"rndl_w_hair_17", #21
"rndl_w_hair_15", #22 (last hairstyle available for NPCs)
"rndl_w_hair_05", #23 (first player-exclusive hairstyle)
"rndl_w_hair_19", #24
"rndl_w_hair_25", #25
"rndl_w_hair_26", #26
"rndl_w_hair_03", #27
"rndl_w_hair_06", #28
"rndl_w_hair_07", #29
"rndl_w_hair_08", #30
"rndl_w_hair_10", #31
"rndl_w_hair_14", #32
"rndl_w_hair_22", #33
"rndl_w_hair_27", #34
#MOD END - better bodies and faces
],
[
#beard meshes - theoretical limit is 63 items, that's how many the face key can store without value overflow
#if there is a lower hardcoded limit in the engine, like there is for hair, then I haven't found it (I tested a list of 38 meshes)
#for women the jewelry mesh names don't have to start with "accessory_" in this file nor in BRF, but let's use this prefix anyway, for consistency
#MOD BEGIN - better bodies and faces
#jewelry meshes in beard slot
"accessory_rndl_w_ears_byzantine", #01
"accessory_rndl_w_ears_big_loops", #02
"accessory_rndl_w_ears_thick_loops", #03
"accessory_rndl_w_ears_ruby", #04
"accessory_rndl_w_ears_amethyst", #05
"accessory_rndl_w_ears_turquoise", #06
"accessory_rndl_w_ears_sapphire", #07
"accessory_rndl_w_ears_jade", #08
"accessory_rndl_w_ears_obsidian", #09
"accessory_rndl_w_ears_moonstone", #10
"accessory_rndl_w_ears_bronze", #11
"accessory_rndl_w_forehead_ruby", #12
"accessory_rndl_w_forehead_moonstone", #13
"accessory_rndl_w_forehead_amber", #14
"accessory_rndl_w_forehead_painted_bindi", #15
#MOD END - better bodies and faces
],
["hair_blonde"], #hair materials
[], #beard materials
[
#face materials
#MOD BEGIN - better bodies and faces
#fields are:
#1. id
#2. special code that tells the game what to do with the body mesh, format: 0xAARRGGBB
# RRGGBB part tells the game how to change colors of the body texture, where FFFFFF means no change to body texture, 7F7F7F means darker by 50% (all body pixel colors get cut in half, so FF becomes 7F, 88 becomes 44, 00 becomes 00 etc.)
# the AA component works in a way unclear to me - if a body consists of several meshes (eg. woman_body.0 and woman_body.1), setting the value to FF makes the game display all elements, setting it to less than FF means skipping some elements or all that aren't ".0", and it also makes hands kinda weird semi-transparent
#3. deprecated, must be "hair_blonde" or game will crash
#4. hair color spectrum
# id body color (don't touch!) hair color spectrum
("rndl_w_face_0",0xFFDFDFE6,["hair_blonde"],[0xFFFFFFFF,0xFFD6AF9E,0xFFAD603E,0xFF7E452B,0xFF502A19]), #0 blonde ##("womanface_young", 0xFFE3E8EF,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF502A19,0xFF19100C]),
("rndl_w_face_1",0xFFDFF2FF,["hair_blonde"],[0xFFEBD1C5,0xFFB04717,0xFF903D17,0xFF703318,0xFF502A19]), #1 ginger ##("womanface_b", 0xFFDFDFDF,["hair_blonde"],[0xFFA5481F,0xFF502A19,0xFF19100C,0xFF0C0D19]),
("rndl_w_face_2",0xFFD2CCBF,["hair_blonde"],[0xFF6B371F,0xFF502A19,0xFF341D12,0xFF19100C,0xFF111111]), #2 brunette ##("womanface_a", 0xFFE8DFE5,["hair_blonde"],[0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_w_face_3",0xFF9F8059,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #3 asian ##("womanface_brown", 0xFFAF9F7E,["hair_blonde"],[0xFF19100C, 0xFF0C0D19, 0xFF07080C]),
("rndl_w_face_5",0xFFA69999,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #4 new: mid-east <-- putting this before african face will mess up facecodes of troops that look african, but: 1. it will make for more usable facecode ranges, 2. we'd be removing black faces anyway, and now for women we don't have to
("rndl_w_face_4",0xFF534653,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #5 african ##("womanface_african",0xFF808080,["hair_blonde"],[0xFF120808, 0xFF07080C]),
#MOD END - better bodies and faces
],
[
#vocalization sounds
(voice_die,"snd_woman_die"),
(voice_hit,"snd_woman_hit"),
#MOD BEGIN - more female voices
(voice_grunt,"snd_rndl_woman_grunt"),
(voice_grunt_long,"snd_rndl_woman_grunt_long"),
#MOD END - more female voices
(voice_yell,"snd_woman_yell"),
#MOD BEGIN - more female voices
(voice_stun,"snd_rndl_woman_stun"),
(voice_victory,"snd_rndl_woman_victory"),
#MOD END - more female voices
],
#MOD BEGIN - better bodies and faces
##"skel_human",1.0,psys_game_blood,psys_game_blood_2,
"skel_rndl_human_female",0.95,psys_game_blood,psys_game_blood_2,
#MOD END - better bodies and faces
),
]
One thing worth pointing out is the order of face declarations. The order I pasted above is not vanilla - it will replace all black faces with mid-east looking ones. This is intended, because:
1. vanilla Warband has no skins for mid-east Sarraninds
2. black people are less likely to be found in Europe-based Calradia, than arabs/turks
So I give priority to them, especially because my intention is to change the face codes in module_troops.py too, for better fit. This isn't covered here, I'm planning a separate post for that.
If you want to keep things vanilla, you should have the faces like this instead:
men:
Python:
("rndl_m_face_00",0xFFB2AE9D,["hair_blonde"],[0xFFFFFFFF,0xFFD6AF9E,0xFFAD603E,0xFF7E452B,0xFF502A19]), #00 blonde young ##("manface_young_2", 0xFFCBE0E0,["hair_blonde"],[0xFFFFFFFF, 0xFFB04717, 0xFF502A19]),
("rndl_m_face_01",0xFFB2B39E,["hair_blonde"],[0xFFFFFFFF,0xFFD7A38B,0xFFB04717,0xFF803818,0xFF502A19]), #01 blonde midage ##("manface_midage", 0xFFDFEFE1,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF632E18,0xFF502A19,0xFF19100C]),
("rndl_m_face_02",0xFFC0CFCF,["hair_blonde"],[0xFFB04717,0xFF983F17,0xFF803818,0xFF683118,0xFF502A19]), #02 ginger ##("manface_young", 0xFFD0E0E0,["hair_blonde"],[0xFF83301A, 0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_m_face_03",0xFFD1E1E1,["hair_blonde"],[0xFF341D12,0xFF19100C,0xFF16100D,0xFF13100F,0xFF111111]), #03 brunette white ##("manface_young_3", 0xFFDCEDED,["hair_blonde"],[0xFF2F180E, 0xFF171313, 0xFF07080C]),
("rndl_m_face_04",0xFFA8B4AF,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #04 brunette dark ##("manface_7", 0xFFC0C8C8,["hair_blonde"],[0xFF171313, 0xFF07080C]),
("rndl_m_face_05",0xFFC2B9C8,["hair_blonde"],[0xFF502A19,0xFF341D12,0xFF19100C,0xFF111111,0xFF0C0D19]), #05 heavy drinker ##("manface_midage_2",0xFDE4C8D8,["hair_blonde"],[0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_m_face_06",0xFF9E99A3,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #06 steppe skin ##("manface_rugged", 0xFFB0AAB5,["hair_blonde"],[0xFF171313, 0xFF07080C]),
("rndl_m_face_07",0xFF706D79,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #10 african ##("manface_african", 0xFF807C8A,["hair_blonde"],[0xFF120808, 0xFF07080C]),
("rndl_m_face_08",0xFF948D7D,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #07 new: mid-east 1
("rndl_m_face_09",0xFFA19691,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #08 new: mid-east 2
("rndl_m_face_10",0xFFA8A8A8,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #09 new: mid-east 3
("rndl_m_face_11",0xFFB3BABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #11 new: white 1
("rndl_m_face_12",0xFFBEBABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #12 new: white 2
("rndl_m_face_13",0xFFB3BABA,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF83301A,0xFF502A19,0xFF19100C]), #13 new: white 3
("rndl_m_face_14",0xFFCCC5A9,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #14 new: asian 1
("rndl_m_face_15",0xFFC7C5B4,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #15 new: asian 2
("rndl_m_face_16",0xFFA87F60,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #16 new: asian 3
("rndl_m_face_17",0xFF7A5D4E,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #17 new: african 1
("rndl_m_face_18",0xFF8C7263,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #18 new: african 2
("rndl_m_face_19",0xFF816C57,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #19 new: african 3
Python:
("rndl_w_face_0",0xFFDFDFE6,["hair_blonde"],[0xFFFFFFFF,0xFFD6AF9E,0xFFAD603E,0xFF7E452B,0xFF502A19]), #0 blonde ##("womanface_young", 0xFFE3E8EF,["hair_blonde"],[0xFFFFFFFF,0xFFB04717,0xFF502A19,0xFF19100C]),
("rndl_w_face_1",0xFFDFF2FF,["hair_blonde"],[0xFFEBD1C5,0xFFB04717,0xFF903D17,0xFF703318,0xFF502A19]), #1 ginger ##("womanface_b", 0xFFDFDFDF,["hair_blonde"],[0xFFA5481F,0xFF502A19,0xFF19100C,0xFF0C0D19]),
("rndl_w_face_2",0xFFD2CCBF,["hair_blonde"],[0xFF6B371F,0xFF502A19,0xFF341D12,0xFF19100C,0xFF111111]), #2 brunette ##("womanface_a", 0xFFE8DFE5,["hair_blonde"],[0xFF502A19, 0xFF19100C, 0xFF0C0D19]),
("rndl_w_face_3",0xFF9F8059,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #3 asian ##("womanface_brown", 0xFFAF9F7E,["hair_blonde"],[0xFF19100C, 0xFF0C0D19, 0xFF07080C]),
("rndl_w_face_4",0xFF534653,["hair_blonde"],[0xFF120808,0xFF0E0909,0xFF0A0A0A,0xFF08090B,0xFF07080C]), #5 african ##("womanface_african",0xFF808080,["hair_blonde"],[0xFF120808, 0xFF07080C]),
("rndl_w_face_5",0xFFA69999,["hair_blonde"],[0xFF19100C,0xFF15100E,0xFF111111,0xFF0E0F15,0xFF0C0D19]), #4 new: mid-east
Edit 2023.05.18:
1 vanilla hairstyle (the one Klethi uses) had clipping issues on the forehead, so I fixed the mesh and included it in the BRF.
To avoid name conflicts, it has a new name, which means an update to module_skins.py as well. Code above updated.
Edit 2023.05.19:
Testing shows a weird, hardcoded limit of 22 hairstyles for NPCs, making hairstyles #23 and later available only for the player... I'm changing the order of hairstyles in the module_skins.py to make sure NPCs can access the hairstyles which I consider the most lore-friendly.
Also, hairstyle rndl_w_hair_24 had some bad UV mapping on the hair tie, so I fixed that too.
Edit 2023.05.27:
Thanks to @Cokjan I've got my hands on a better female head mesh with more sliders - I'm updating the pack to replace the existing resources with better replacements. There is no rose without thorns though - the new head mesh deforms earrings more than the previous one, because it has sliders affecting that area. To compensate, I had to reduce the size of the biggest earrings by 38%. Another side effect of the new head mesh is that females no longer look like pretty top models - now only a certain combination of sliders results in pretty faces, and I honestly haven't been able to re-create with sliders the level of beauty the previous mesh was offering... So, no more top models in your game. On the other hand, with the previous mesh all women looked like clones of the same top model, so I still mark this as improvement. A bittersweet victory, but victory nonetheless.
Also, I've updated the aged female textures so they look a bit more like they are old and less like zombies... Whether I succeeded or not - you be the judge. I'm not very happy with how they look, but I was even less happy with the previous ones, so... I'll take it.
Last edited: