SP Tutorial Module System Complete Guide to Adding Factions

Users who are viewing this thread

This tutorial by Nord Champion has been the go-to guide for adding factions in warband for as long as I can remember, but it misses out a few a ton of vital scripts and bits of code that need to be added when you create a new faction. So here's a guide to adding new ones that should hopefully cover them all.

This tutorial was made by searching the entire 1.165 module system for fac_kingdom_1, fac_culture_1, p_town_1, p_castle_1, p_village_1, trp_knight_1_1, trp_kingdom_lord_1, banner_a01 and map_icon_1. This highlighted all the scripts that needed changing.

Step 1: Creating the faction, adding troops, assigning cultures
First of all you need to create your faction. (module_factions.py) Follow this template:

  ("kingdom_6",  "Sarranid Sultanate",  0, 0.9, [("outlaws",-0.05),("peasant_rebels", -0.1),("deserters", -0.02),("mountain_bandits", -0.05),("forest_bandits", -0.05)], [], 0xDDDD33),

kingdom_6: This is your faction ID. The scripts use this. Each ID has to be unique otherwise you'll come across errors, so just calling it kingdom_x where x is a different number to the previous kingdom is a failsafe option.
Sarranid Sultanate: Your faction name. This is what shows up in-game.
0, 0.9: Two numbers that don't do much. The second number is "faction cohesion" and setting it to zero will make lords in a faction hate each other, but it doesn't work too well.
("outlaws",-0.05),...("forest_bandits", -0.05): Relations with other factions at the start of each game. Don't bother changing this, a lot of it gets overridden at the start of each game.
0xDDDD33: Your faction colour. The latter six digits are an RGB hex code you can get from MS paint or the internet.

You can put it anywhere between player_supporters_faction and kingdoms_end, although it's usually a good idea to put it after kingdom_6 (the sarranids in native) and call it kingdom_7 so you don't have to memorise the IDs of the factions at a later date. You'll be typing in fac_kingdom_7 a lot, so naming it something intuitive will save you time.

Secondly, you will need to create kingdom-specific troops. (module_troops.py) This is fairly straightforward, gets covered in every other tutorial, and most people know it already, so I won't bother explaining it. Just make sure your troops come after the kingdom_6 troops so there's no confusion later.

Third, you'll need party templates. (module_party_templates.py) These are arrays of troops that tell AI lords what to recruit. kingdom_6_reinforcements_a and kingdom_6_reinforcements_b are recruited into garrisons, Lord parties and mecharnt caravans, while kingdom_6_reinforcements_c is only used for Lord parties. This allows you to prevent knights/elephants/space marines from spawning in merchant caravans or garrisons.
Use Morgh's editor to create a similar array of troops to the ones shown here:

  ("kingdom_6_reinforcements_a", "{!}kingdom_6_reinforcements_a", 0, 0, fac_commoners, 0, [(trp_sarranid_recruit,5,10),(trp_sarranid_footman,2,4)]),
  ("kingdom_6_reinforcements_b", "{!}kingdom_6_reinforcements_b", 0, 0, fac_commoners, 0, [(trp_sarranid_skirmisher,2,4),(trp_sarranid_veteran_footman,2,3),(trp_sarranid_footman,1,3)]),
  ("kingdom_6_reinforcements_c", "{!}kingdom_6_reinforcements_c", 0, 0, fac_commoners, 0, [(trp_sarranid_horseman,3,5)]),

Replace "kingdom_6" with "kingdom_7" (or whichever ID you're using in this instance).

Fourth, you'll need to create and assign a culture. (module_faction.py, module_scripts.py) Go back to module_factions and find this: ("culture_6",  "{!}culture_6", 0, 0.9, [], []),
Simply copy that line and replace 6 with whatever number you're using.

Now find these lines (around line 100) in module_scripts.py:

      (faction_set_slot, "fac_culture_6", slot_faction_tier_1_troop, "trp_sarranid_recruit"),
      (faction_set_slot, "fac_culture_6", slot_faction_tier_2_troop, "trp_sarranid_footman"),
      (faction_set_slot, "fac_culture_6", slot_faction_tier_3_troop, "trp_sarranid_archer"),
      (faction_set_slot, "fac_culture_6", slot_faction_tier_4_troop, "trp_sarranid_horseman"),
      (faction_set_slot, "fac_culture_6", slot_faction_tier_5_troop, "trp_sarranid_mamluke"),

Copy those lines and add your own troops. These tell the game what the player can get when he recruits from villages.
Immediately below this, there are similar lines that determine the people who walk around in town and village scenes:

      (faction_set_slot, "fac_culture_6", slot_faction_town_walker_male_troop, "trp_sarranid_townsman"),
      (faction_set_slot, "fac_culture_6", slot_faction_town_walker_female_troop, "trp_sarranid_townswoman"),
      (faction_set_slot, "fac_culture_6", slot_faction_village_walker_male_troop, "trp_sarranid_townsman"),
      (faction_set_slot, "fac_culture_6", slot_faction_village_walker_female_troop, "trp_sarranid_townswoman"),
      (faction_set_slot, "fac_culture_6", slot_faction_town_spy_male_troop, "trp_spy_walker_1"),
      (faction_set_slot, "fac_culture_6", slot_faction_town_spy_female_troop, "trp_spy_walker_2"),

Do the same with these as the tier troops, creating new troops if you want new villagers.

Do the same with these:

      (faction_set_slot, "fac_kingdom_6",  slot_faction_culture, "fac_culture_6"),
      (faction_set_slot, "fac_kingdom_6",  slot_faction_leader, "trp_kingdom_6_lord"),
     (troop_set_slot, "trp_kingdom_6_lord", slot_troop_renown, 1200),

Search for initialize_faction_troop_types, and scroll down to:

          (faction_slot_eq, ":faction_no", slot_faction_culture, "fac_culture_6"),
          (faction_set_slot, ":faction_no", slot_faction_deserter_troop, "trp_sarranid_deserter"),
          (faction_set_slot, ":faction_no", slot_faction_guard_troop, "trp_sarranid_castle_guard"),
          (faction_set_slot, ":faction_no", slot_faction_messenger_troop, "trp_sarranid_messenger"),
          (faction_set_slot, ":faction_no", slot_faction_prison_guard_troop, "trp_sarranid_prison_guard"),
          (faction_set_slot, ":faction_no", slot_faction_castle_guard_troop, "trp_sarranid_castle_guard"),
          (faction_set_slot, ":faction_no",  slot_faction_reinforcements_a, "pt_kingdom_6_reinforcements_a"),
          (faction_set_slot, ":faction_no",  slot_faction_reinforcements_b, "pt_kingdom_6_reinforcements_b"),
          (faction_set_slot, ":faction_no",  slot_faction_reinforcements_c, "pt_kingdom_6_reinforcements_c"),

Do the same, copying these lines and editing troop IDs where applicable; make sure you include the (else_try), at the beginning. Also ensure that the reinforcement party IDs are the same as the ones you added earlier.

Step 2: Creating the Lords, adding banners.
Step 1: Creating Lords and ladies. (module_troops.py)
Go to module_troops.py and find the troops named knight_1_3 and so on. Using the same ID naming convention as the others (doesn't exactly matter but makes things easier), create 20 of your own troops and place them after knight_6_20. These will be Lords.

Go further down to kingdom_6_lady_20 and add 20 lady troops (give them the tf_female flag even if you don't lean that way, otherwise there's potential for bugs. Also make sure they're given the correct kingdom).
You don't need to give them anything other than boots since the rest is assigned automatically at the beginning of the game -- see below:

Step 2: Lady Clothes. (module_scripts.py)
Go to add_lady_items in module_scripts.py. This requires some very basic knowledge of how the module system works, but basically as long as ":lady_no" of your new faction has clothes assigned to her by the end of the script, it'll work. The basic framework of this script allows you to differentiate between ambitious and adventurous ladies (who usually have nomad vests) and the rest (who get normal dresses).

Step 3: Making family relations. (module_scripts.py)
Go to initialize_aristocracy in module_scripts.py. This script sets fathers, sons and other relationships. Scroll down to the bit that reads:

         (is_between, ":cur_troop", "trp_knight_6_1", "trp_kingdom_1_pretender"),
         (store_sub, ":npc_seed", ":cur_troop", "trp_knight_6_1"),
         (assign, ":ancestor_seed", 31),

You'll actually have to edit this bit before copying it. Replace "trp_kingdom_1_pretender" with "knight_7_1" or whatever the ID of the first of your faction's lords is.

Then copy and paste that bit of the script below that, but before the (try_end), below. Add 6 to the number after ":ancestor_seed" and replace trp_knight_6_1 with trp_knight_7_1. Then put trp_kingdom_pretender back in the place you removed it from the previous bit.

Step 4: Banners. (banners.brf, textures.brf, materials.brf, module.ini, module_constants.py, module_scripts.py, module_meshes.py, module_scene_props.py, module_map_icons.py)

This is an absolutely insane pain in the arse, will probably make you loathe humankind and shorten your lifespan by several years. I hate Taleworlds so much for coding banners in this completely stupid and needlessly convoluted manner. There is infinite potential to make mistakes here and due to the annoying, clunky offset system they used, tiny mistakes affect everything and are really hard to detect.

But don't let that deter you. As long as you follow these rules it should work.

You'll have to create a bunch of banners. Go to banners.brf in the CommonRes folder (found in your warband folder). Copy one of the banner textures and make your own, making sure all the new banners you make align perfectly with the borders of the original banners. Good luck.

Once you've made the texture, save it as a DDS file, dxt1 format, in your mod's texture folder. Then copy banners.brf, texture.brf and materials.brf into your own resource folder if you haven't already, and go to module.ini, and find these three lines:

load_resource = textures
load_resource = materials
load_resource = banners

Replace them with these, keeping them in the exact same place you found them:

load_mod_resource = textures
load_mod_resource = materials
load_mod_resource = banners

Frustrated yet? Go to your new copied textures.brf, copy banners_g, and name it banners_h. Do the same in your materials.brf, except you'll also need to change the texture in the DiffuseA field to banners_h.

Now go to banners.brf and copy everything from banner_f01 to banner_f21. Paste them and rename them banner_h (I know that H doesn't come after F but that's just one of the nonsensical things you'll see in this section). Change their material to banners_h. Do the same with the "arms_" meshes below.

Sweating yet? Create a .brf and call it map_flags_mod or something, making sure it's referenced in module.ini. Open map_flags_c in CommonRes and copy everything that begins with map_flag_e, pasting it into your new brf. Change the material once again, renaming them to begin with map_flag_h.

Then go to module_meshes.py, find banner_kingdom_f and copy that line, call it banner_kingdom_h and set the mesh (the second thing in quotes) to the name of one of your banners in banners.brf. Do the same in module_map_icons.py and module_scene_props.py

Then go to module_map_icons.py. Copy the second-last "block" of banners (from banner_105 to banner_125 in native), and copy them. Rename their IDs so they fit with the sequence, and rename the banners after it (from banner_126 to banner_135 in native).

Go to module_constants.py and find these lines:

sarranid_banners_begin_offset = 105
sarranid_banners_end_offset = 125

Below them, add these lines:

kingdom_7_banners_begin_offset = 126
kingdom_7_banners_end_offset = 146

(if you've already added a faction, replace the numbers with the number of the first banner you added to module_map_icons, followed by the number after the number of the last banner you added to module_map_icons.)

This line is immediately below; add the total number of banners you added to this number.
banners_end_offset = 136

Now find these lines:

banner_map_icons_begin = "icon_banner_01"
banner_map_icons_end_minus_one = "icon_banner_136"

You should know what to do now. Replace the icon_banners accordingly. Note that you need to put "icon_" before the ID to tell the game that it's from module_map_icons.py.

Now go to module_meshes.py. Copy everything between banner_f01 and banner_f20, then paste them and replace F with H for each. Do the same in module_scene_props.py, and with the entires labelled "arms_" in both files.

We're almost finished with this nonsense. Go to around line 400 in module_scripts.py, and look for this:

(assign, ":num_sarranid_lords_assigned", 0),

Below that, add (assign, ":num_kingdom_7_lords_assigned", 0),. Remember what name you used for this local variable, you'll use it below.

Scroll down module_scripts.py a bit, or search for sarranid_banners. You'll find a block of code that looks like this:

          (eq, ":kingdom_hero_faction", "fac_kingdom_6"), #Sarranid Sultanate
          (store_add, ":kingdom_6_banners_begin", banner_scene_props_begin, sarranid_banners_begin_offset),
          (store_add, ":banner_id", ":kingdom_6_banners_begin", ":num_sarranid_lords_assigned"),
          (troop_set_slot, ":kingdom_hero", slot_troop_banner_scene_prop, ":banner_id"),
          (val_add, ":num_sarranid_lords_assigned", 1),

Copy that and paste it below, including the (else_try),.
Replace kingdom_6 with the ID of your new faction.
Replace ":kingdom_6_banners_begin" with ":kingdom_7_banners_begin" (doesn't matter what you call it, just makes you aware of what the code is doing if you ever decide to edit this mess).
Replace sarranid_banners_begin_offset with kingdom_7_banners_begin_offset.
Repace ":num_sarranid_lords_assigned" with ":num_kingdom_7_lords_assigned". (has to be the same name as the local variable you assigned above).

Now search for (gt, ":hero_offset", sarranid_banners_begin_offset),. You'll find this block of code:

            (gt, ":hero_offset", sarranid_banners_begin_offset),#Do not add sarranid banners to other lords
            (val_add, ":hero_offset", sarranid_banners_end_offset),
            (val_sub, ":hero_offset", sarranid_banners_begin_offset),

Copy this whole thing and copy it below. Replace sarranid_banners_begin_offset and sarranid_banners_end_offset with the constants you used in for the other scripts.

And that's it, you should be done on what is arguably one of the most complex bits of code in Warband. Get yourself a beer and a snickers bar.

Step 3: Adding Settlements
Now for something easier. Your faction will die on the first day of the game unless you give them a town. First, download Swyter's Cartographer. You'll need it to move towns and other static parties around.

Adding 1 Town, 1 Castle and 4 Villages (module_parties.py)

Go to module_parties.py and copy-paste town_22. Give it the ID town_23, and rename it something. Edit the numbers in the brackets slightly so they're not right on top of the parties you copied. Make sure it's in the right order with the rest of them otherwise scenes and other stuff won't work.
Copy castle_48, do the same.
Copy village_110 four times. You'll need 3+ villages for each town and 1 per castle.

Now load up swyter's cartographer and move your new villages and walled settlements around. Some of them will be almost on top of each other but this shouldn't be an issue.

Next, go to module_scenes.py and copy-paste-rename the scenes of the castles, villages and towns you just copied. Once again, make sure they're in the correct order. You'll have to make the scenes yourself, but there are tutorials elsewhere that tell you how to do that in detail.

Next, go to module_troops.py and copy-paste-rename the troops used by the castles, villages and towns you just copied. Once again, make sure they're in the correct order.
For Towns, you need to find and copy troops with the suffixes:

For castles, you only need to copy:

And for villages, it's just

If you want any of the scenes to have siege towers, search for slot_center_siege_with_belfry inmodule_scripts.py and add (party_set_slot,"p_castle_101", slot_center_siege_with_belfry, 1), (replacing p_castle_101 with the party ID of the castle or town you want to have a siege tower). You will need to place entry points 50-55 in the scene for it to work, along with the tower prop and an AI mesh on the position the siege tower's going to be when it lands on the wall.

Now for the "fun". Search for (call_script, "script_give_center_to_faction_aux", "p_town_1", "fac_kingdom_4"), and you'll see a bunch of near-identical lines. These assign towns and castles to factions. Pretty self-explanatory. Copy these lines and replace the ID with one of your own towns.

Lower down, the line becomes (call_script, "script_give_center_to_lord", "p_town_1",  "trp_kingdom_4_lord", 0),. Do the same here to assign specific lords to be the rulers of towns.
This isn't strictly necessary, but without assigning Lords to towns/castles, they all pop out of the same town at the beginning of the game and it looks ugly.

Search for initialize_trade_routes. Here you'll see a script that sets trade routes between towns. Admittedly I haven't played with this much to see how extensive or sparse trade affects the economy, but without these scripts, cavarans won't visit towns. It might be a good idea to draw a map and work this out beforehand to avoid confusion.

Search for initialize_town_arena_info. Here you'll see a script that sets the number and size of teams in tournaments. Just copy-paste these and add your own values to the town(s) you added.

Search for initialize_economic_information. Here you'll see a script that sets what a town produces. For example:
	#Tihr (salt, smoked fish, linen)
	(party_set_slot, "p_town_2", slot_center_salt_pans, 3),
	(party_set_slot, "p_town_2", slot_center_fishing_fleet, 25), 	
	(party_set_slot, "p_town_2", slot_center_linen_looms, 15),

Once again, copy-paste these, but bear in mind that there are several "produces" available. They are:


They produce and consume different goods, which affects trade, prosperity and the items you get in marketplaces.

Scroll down a little and you'll come across this block of code:

(try_for_range, ":village_no", villages_begin, villages_end),
	    (this_or_next|eq, ":village_no", "p_village_93"), #mazigh
		(this_or_next|eq, ":village_no", "p_village_94"), #sekhtem
		(this_or_next|eq, ":village_no", "p_village_108"), #mit nun
		(eq, ":village_no", "p_village_92"), #dhibbain

		(assign, ":village_is_at_desert", 1),
		(assign, ":village_is_at_desert", 0),

Put (this_or_next|eq, ":village_no", "p_village_100"), #new village somewhere before the end of this block if you want the village to be a desert village. It affects the invisible number of sheep and cows, as well as tweaking the production values slightly. Not strictly necessary, but helps prevent the economy stagnating by diversifying the market slightly.

Search for #Sargoth (village productions : Ambean, Fearichen and Fenada). This precedes a script that determines the invisible amount of land a town's villages have. Copy this for each of your towns. Here are the slots you can use:


You can also assign "production" slots like the ones previously mentioned for towns.

Lower down is another block of scripts that determine whether a village has fishing capabilties or not. Search for (party_set_slot, "p_village_1", slot_center_fishing_fleet, 15), #Yaragar, and copy this line for your own villages if they're near the sea. Also not necessary, but allows fish to show up in villages.

That's it. Most of this isn't strictly necessary, but can cause large-scale issues if you're adding 100 towns and there are no fish to drive the economy.

Step 4: Important tidbits that usually get ignored
Assigning the correct music (module_scripts.py)

Go to get_culture_with_faction_for_music, and you'll see a sort of list that assigns "music cultures" like mtf_culture_1. Don't bother adding any of your own, instead find a faction you think would share music with the new one (doesn't matter too much), and add (this_or_next|eq, ":faction_no", "fac_kingdom_x"), to that block. The result should be something like this:
        (this_or_next|eq, ":faction_no", "fac_kingdom_7")
        (eq, ":faction_no", "fac_kingdom_4"),
        (assign, ":result", mtf_culture_4),

This will make sure you don't just get default/random music for your faction.

Assigning troops to custom battles (module_scripts.py, module_presentations.py)

Go to module_scripts.py and search for game_quick_start. Scroll down and you'll see that slots (entity-specific values) for factions are being assigned. Copy one of the blocks of code, like this:

(faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_1_infantry, "trp_swadian_footman"),
      (faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_2_infantry, "trp_swadian_infantry"),
      (faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_1_archer, "trp_swadian_skirmisher"),
      (faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_2_archer, "trp_swadian_crossbowman"),
      (faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_1_cavalry, "trp_swadian_man_at_arms"),
      (faction_set_slot, "fac_kingdom_1", slot_faction_quick_battle_tier_2_cavalry, "trp_swadian_knight"),

And paste it, using the ID of your own kingdom and your own troops. This will prevent naked dudes showing up in custom battles if you select your new faction.

To make the correct icon show up when you're selecting a new faction, go to module_presentation.py and search for (eq, "$g_quick_battle_team_2_faction", "fac_kingdom_1"),. Copy this, including the (else_try),:
        (eq, "$g_quick_battle_team_2_faction", "fac_kingdom_6"),
        (assign, ":cur_troop", "trp_sarranid_mamluke"),

And paste it below, changing the troop and faction ID.

Assigning Kingdom Adjectives (module_strings.py, module_scripts.py)
One of the guild master scripts demands an "adjective", or "demonym" for each faction; i.e. Swadian, Vaegir, Rebel (for pretenders). Search for  ("kingdom_1_adjective",                    "Swadian"), in module_strings.py, and add your own.

Go to module_scripts.py, and search for (faction_set_slot, "fac_kingdom_1", slot_faction_adjective, "str_kingdom_1_adjective"),. You'll have to do the same here, copying the line and assigning the adjective string to your new faction.

Disclaimer: This tutorial does not take overhauls like diplomacy and FormAI into account. Diplomacy is more notable as it adds dozens more scripts like the ones above -- thankfully they're all quite simple and straightforward. Search your entire module system for fac_kingdom_2 (it's the first "trivial" faction) and look for anything that hasn't been covered above. Alternatively, if you hate me, you could do this for a native module system and find if there's anything I've missed.
Awesome, thanks for doing this!
Looking forward to the final tutorial.
If I just re-use Lords does that mean I'll have to re-create new banners?

For example, for new kings I'm just taking previous swadian vassals and turning them into faction leaders. And for their lords I'm just splitting up the swadians and using them. So in short no "new" lords are being created, just moved around.

Note* I think I still get an error ingame despite this
Moving lords, or troops in general around is error-prone. Ignoring the issues with initialize_aristocracy messing all the relationships up, a lot of the scripts expect there to be 20 lords in each faction and for there to be simple boundaries between them.

Also please do post exactly what the error is. "Opcode 23 missing line 2 invalid ID -1" might look like a bunch of gibberish but you can basically tell someone exactly what the problem is. Otherwise it's just a wild guess.
Question: the personality for the various lords/kings/ladies, how is set? How you choose to give a specific lord/king a specific behaviour? For example Martial or Debauched
jacobhinds said:
It's assigned automatically, but you can do it manually by setting the slot slot_lord_reputation_type in script_game_start. The different personality types you can use are shown in module_constants.py, named lrep_debauched and lrep_goodnatured etc.

Yeah, I already noticed the script in game_start which assigns personalities... and I've added some personalities in the module_constants, however, I've simply enlisted the personalities and gave them an index number (as default personalities stop at 11 and then continue from 21 for the ladies) and added them to the random assigner in game_start. But I think I don't get how you assign a specific personality to, per say, a specific lord (for example I'd like Harlaus to be Debauched/Martial/whatever) and the only thing I thought is to create a new troop name for that specific Lord, and then use the same script but with ":nameofthetroophere" instead of ":party_leader", would this be enough to assign it fixed?
I've used several resources on the Forums to make my own mod with a new faction. The compiler output has been giving me all kinds of errors I had not foreseen, including a particularly difficult indentation error, which I finally murdered. With an axe. However, when one problem is fixed, another pops up.
  File "C:\Users\User1\Desktop\NOT EVEN SLIGHTLY PORN\ModSys\Module_system 1.16
5\module_troops.py", line 2157
SyntaxError: invalid syntax
The syntax here is identical to the surrounding, and I didn't even change it.

File "C:\Users\User1\Desktop\NOT EVEN SLIGHTLY PORN\ModSys\Module_system 1.16
5\module_party_templates.py", line 159

SyntaxError: invalid syntax
The problem on line 159 of the templates bugs the poor compiler too, thing is that line 159 of the module_party_templates file does not exist.
I'm very grateful to this community for any assistance available.
When the syntax error points to the end of the very end of the file like that it means there's a missing or superfluous bracket (square [ or round ( or even both). If you're using notepad++ you can select the last bracket and press ctrl+b, which should take you to the "opposite" bracket, a very useful tool for preventing this kind of thing.

I'd recommend using morgh's editor to edit module_party_templates and module_troops, if you aren't already. There's a lot of potential for mistakes in those files because of how many fields there are, so using the editor eliminates human error.

I'd also recommend using lav's compiler which is a lot faster than the default one and gives far more useful error messages, among other things.
Is having 20 lords absolutely necessary? I'm making a 1-town-faction, having that many lords is overkill.
Top Bottom