LSP Kit QoL Troop Diversification with Random Items - Bags & Bottles LSP Code Kit

Users who are viewing this thread

The purpose of this LSP Code Kit is to enable a bit of diversification of the looks of troops at the battles, to reduce a little bit the clone like look of them at the scenes. It contains code examples for different cases as well as example resource files (1 brf file + 1 texture) which can get used as a base. Note that I used some leather bags and bottles of the Grim Age OSP and have bundled them upon one texture for the ease of use. The resource files are neither containing a bump map nor has the texture mipmaps, it's purely for giving you a workable example file.

Difficulty level: Beginner/Intermediate
Required ModSys files: module_strings.py, module_items.py
Example resource files: https://www.moddb.com/games/mount-blade/downloads/bags-bottles-lsp-code-kit-resource-files
Credits: Earendil (Code), Furok (Grim Age, OSP)
LSP Restrictions: No commercial use

1) Resource Management
Add the texture into your texture folder. Make sure that you have
scan_module_textures = 1
set in your module.ini file. Add the brf file into your resource folder and the respective loading line
load_mod_resource = BagsBottlesLSP
to module.ini. Alternative setups could be to integrate the material and the texture entry at the respective material and textures brf file (often done for performance) or to integrate all three of them add the brf file which already contains the resources of the faction at which you want to use this Code Kit.

For the purpose of easy replication I use the Native armour mesh leather_armor_b and simply renamed it to example_armour in the Kit brf file. You can thus easily replace that mesh with any other of your armour meshes of your mod. Take however note that you need to position the submeshes of the bottles and bags accordingly. For this click in OpenBRF first on the armour mesh, click Ctr and click one of the submeshes which you want to position anew. Make sure that you have selected "multi-view: combo" to see both meshes at the same place. Rightclick on one of the marked meshes, select "Roto-translate-rescale..." and check at the bottom "Apply to last selected object only". It is important that you have selected the bottle or bag submesh after the armour mesh, so that you repositionate the submesh and not accidentally the armour mesh. Afterwards use Translation and Rotation for positioning of the submeshes until they fit nicely to your armour.

Important: The game will crash if you screw up the lods! You either need to specify extra parameters or make sure all your base and additional meshes have the same amount of .lod1 to .lod4! In my example brf file neither the armour nor the accessory items have lods, that's why it is working without problems here. For performance reasons it is however not recommened to not have lods for your meshes! It is called an example brf file for a reason.

2) One random accessory item
First you need to arrange the accessory items at module_strings.py, so that they can get called later accordingly. Add the following lines to module_strings.py:
Python:
  ("accessory_bagsbottles_random_0","accessory_bottle_a"),
  ("accessory_bagsbottles_random_1","accessory_bottle_b"),
  ("accessory_bagsbottles_random_2","accessory_bottle_c"),
  ("accessory_bagsbottles_random_3","accessory_bottles"),
  ("accessory_bagsbottles_random_4","accessory_bag_a"),
  ("accessory_bagsbottles_random_5","accessory_bag_b"),
  ("accessory_bagsbottles_random_6","accessory_bag_c"),
  ("accessory_bagsbottles_random_7","accessory_bag_d"),
  ("accessory_bagsbottles_random_8","accessory_bag_e"),
  ("accessory_bagsbottles_random_end", "accessory_bagsbottles_random_end"),

a) Adding one random accessory item to an armour
First, the simplest variant, every armour gets one random accessory item. Go to the wanted item entry at module_items.py or use the following one for the example item and add it anew (again, it is a renamed copy paste entry of padded_leather):
Python:
["example_armour_a", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth],
Add the code with the trigger ti_on_init_item behind imodbits_cloth, using a comma as separator:
Python:
["example_armour_a", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_random_0","str_accessory_bagsbottles_random_end"),    # Picking one random string and thus one random mesh
        (cur_item_add_mesh, ":rand_accessory"),])]    # Adding the random mesh to the item
],

b) Adding randomly up to one random accessory item to an armour
Now you might want to have a random chance that an accessory item gets added, so some troops will wear an armour without them. Add the following lines instead:
Python:
["example_armour_a", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_random_0","str_accessory_bagsbottles_random_end"),    # Picking one random string and thus one random mesh
        (store_random_in_range,":probability",0,100),
        (try_begin),
            (lt, ":probability", 50),    # The script only continues with a probability of 50 %
            (cur_item_add_mesh, ":rand_accessory"),    # Adding the random mesh to the item
        (try_end),])]
],

3) Two random accessory items
Notice that I now use different id names for the meshes while the mesh resource names itself are staying the same. This offers you to have a variety of different mini scripts addressing the same meshes on an easy and structured way. Notice also that I sorted the chosen meshes by the side they are attached to, so you have a presorted list of them. Add the following lines to module_strings.py:
Python:
  ("accessory_bagsbottles_randomleft_0","accessory_bottle_a"),
  ("accessory_bagsbottles_randomleft_1","accessory_bottle_b"),
  ("accessory_bagsbottles_randomleft_2","accessory_bag_e"),
  ("accessory_bagsbottles_randomleft_end", "accessory_bagsbottles_randomleft_end"),
  ("accessory_bagsbottles_randomright_0","accessory_bottles"),
  ("accessory_bagsbottles_randomright_1","accessory_bag_a"),
  ("accessory_bagsbottles_randomright_2","accessory_bag_b"),
  ("accessory_bagsbottles_randomright_3","accessory_bag_c"),
  ("accessory_bagsbottles_randomright_4","accessory_bag_d"),
  ("accessory_bagsbottles_randomright_end", "accessory_bagsbottles_randomright_end"),

a) Adding two random accessory items to an armour
It is basically the same procedure as in the case 2a), only with two random in range operations. Add following lines at module_items.py:
Python:
[CODE=python]
["example_armour_b", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_randomleft_0","str_accessory_bagsbottles_randomleft_end"),
        (cur_item_add_mesh, ":rand_accessory"),
        (store_random_in_range,":rand_accessory2","str_accessory_bagsbottles_randomright_0","str_accessory_bagsbottles_randomright_end"),
        (cur_item_add_mesh, ":rand_accessory2"),])]
],

b) Adding randomly up to two random accessory items to an armour
Now you might want again a random chance that a troop has none, one or two accessory items attached to its armour. It's in the same way simply the same procedure as in the case 2b), so simply add the following lines instead:
Python:
["example_armour_b", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_randomleft_0","str_accessory_bagsbottles_randomleft_end"),
        (store_random_in_range,":probability",0,100),
        (try_begin),
            (lt, ":probability", 50),     # The script only continues with a probability of 50 %
            (cur_item_add_mesh, ":rand_accessory"),
        (try_end),
        (store_random_in_range,":rand_accessory2","str_accessory_bagsbottles_randomright_0","str_accessory_bagsbottles_randomright_end"),
        (store_random_in_range,":probability2",0,100),
        (try_begin),
            (lt, ":probability2", 50),    # The script only continues with a probability of 50 %
            (cur_item_add_mesh, ":rand_accessory2"),
        (try_end),])]
],

4) Random number of accessory items
Now the last case, a random number of accessory items within the same range, adding also a probability that it becomes none. Note that we have again a list of preselected accessory items, selected such way that all of them can be combined together at the same time without overlapping with each other. Add the following lines to module_strings.py:
Python:
  ("accessory_bagsbottles_random2_0","accessory_bottle_c"),
  ("accessory_bagsbottles_random2_1","accessory_bottles"),
  ("accessory_bagsbottles_random2_2","accessory_bag_c"),
  ("accessory_bagsbottles_random2_3","accessory_bag_e"),
  ("accessory_bagsbottles_random2_end", "accessory_bagsbottles_random2_end"),
The applied procedure differs a bit of the ones before. Now a chance is getting checked for every single accessory item. Add following lines at module_items.py:
Python:
["example_armour_c", "Example Armour", [("example_armour",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(try_for_range, ":accessory_item", "str_accessory_bagsbottles_random2_0", "str_accessory_bagsbottles_random2_end"),    # Checks for every item within that range
            (store_random_in_range,":probability",0,100),
            (try_begin),
                (lt, ":probability", 50),     # The script only continues with a probability of 50 %
                (cur_item_add_mesh, ":accessory_item"),
            (try_end),
        (try_end),])]
],

Final remarks:
- While this Code Kit works beautiful easy for a handful of armouries it gets more and more complicated to keep it organised the more armours you want to apply it to. It is therefore recommended to keep notes for the individual troops or make comments at the module_mesh.py entries. It might be needed to have either multiple versions of the same accessory item in the brf files, fitting to the individual armouries.
- For the resource management: If you apply exactly the same meshes with the same textures to armouries of varying factions, it is recommended to keep the brf file with the accessory items on its own (for the material and texture entries, either keep them in the same file or in the respective main brf files containing those). Since you might have faction dependend accessory items (for example bags and bottles for Men and skulls and ceremonial sticks at Barbarian Dwarves) it is recommended to keep them in the same brf file as the armour for the ease of overview.
- Note that you need also to check for overlapping mesh conflicts with the weapons the troop is wearing, such as swords, axes or arrow and bolt bags getting holstered at the same area. Always check in-game how it looks like for the troop.

Feel free to make suggestions for improvement :grin:

Screenshots from in-game, you see the accessory tems in bright brown. I am not the best at it, so feel free to make better ones :razz:
Screenshot_Bags__Bottles_1.jpg
Screenshot_Bags__Bottles_2.jpg
 
Last edited:
This is great and it will improve the visual during battles.

Wondering though can that be used outside of battle? Let's say you are wondering a town, will it be possible to make the soldiers on patrol wear some random items as well?

and a great thanks for a great worker!
 
header_operations.py
Python:
cur_item_add_mesh                                = 2001

module_strings.py
Python:
  ("accessory_bagsbottles_randomleft_0","a_brigandine_narf_arms_plate"),
  ("accessory_bagsbottles_randomleft_1","a_brigandine_narf_arms_aketon"),
  ("accessory_bagsbottles_randomleft_2","a_hauberk_narf_arms_mail_plate"),
  ("accessory_bagsbottles_randomleft_end","accessory_bagsbottles_randomleft_end"),
  ("accessory_bagsbottles_randomright_0","o_hosen_hauberk_plate"),
  ("accessory_bagsbottles_randomright_1","o_hosen_hauberk_plate_full"),
  ("accessory_bagsbottles_randomright_2","o_hosen_brigandine"),
  ("accessory_bagsbottles_randomright_3","o_hosen_brigandine_plate"),
  ("accessory_bagsbottles_randomright_end","accessory_bagsbottles_randomright_end"),

module_items.py
Python:
["heraldic_brigandine_narf2", "Example Armour", [("heraldic_brigandine_narf",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
        [(store_trigger_param_1, ":agent_no"),(store_trigger_param_2, ":troop_no"),(call_script, "script_shield_item_set_banner", "tableau_tab_heraldic_brigandine_narf", ":agent_no", ":troop_no")],
        [(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_randomleft_0","str_accessory_bagsbottles_randomleft_end"),
        (store_random_in_range,":probability",0,100),
        (try_begin),
            (lt, ":probability", 50),     # The script only continues with a probability of 50 %
            (cur_item_add_mesh, ":rand_accessory"),
        (try_end),
        (store_random_in_range,":rand_accessory2","str_accessory_bagsbottles_randomright_0","str_accessory_bagsbottles_randomright_end"),
        (store_random_in_range,":probability2",0,100),
        (try_begin),
            (lt, ":probability2", 50),    # The script only continues with a probability of 50 %
            (cur_item_add_mesh, ":rand_accessory2"),
        (try_end),])]
],

and the added parts do not appear
 
Last edited by a moderator:
header_operations.py
Python:
cur_item_add_mesh = 2001
You don't need to add that line, it should already be present there.

module_items.py
Python:
["heraldic_brigandine_narf2", "Example Armour", [("heraldic_brigandine_narf",0)], itp_merchandise| itp_type_body_armor |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
[(store_trigger_param_1, ":agent_no"),(store_trigger_param_2, ":troop_no"),(call_script, "script_shield_item_set_banner", "tableau_tab_heraldic_brigandine_narf", ":agent_no", ":troop_no")],
[(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_randomleft_0","str_accessory_bagsbottles_randomleft_end"),
(store_random_in_range,":probability",0,100),
(try_begin),
(lt, ":probability", 50), # The script only continues with a probability of 50 %
(cur_item_add_mesh, ":rand_accessory"),
(try_end),
(store_random_in_range,":rand_accessory2","str_accessory_bagsbottles_randomright_0","str_accessory_bagsbottles_randomright_end"),
(store_random_in_range,":probability2",0,100),
(try_begin),
(lt, ":probability2", 50), # The script only continues with a probability of 50 %
(cur_item_add_mesh, ":rand_accessory2"),
(try_end),])]
],
You should have gotten an error message at compiling, the random item trigger part shouldn't be in separate brackets, it should be in the same as the heraldic snippet. It should be looking like this:
Python:
["heraldic_brigandine_narf2", "Example Armour", [("heraldic_brigandine_narf",0)], itp_merchandise| itp_type_body_armor |itp_covers_legs|itp_civilian,0,
454 , weight(12)|abundance(100)|head_armor(0)|body_armor(27)|leg_armor(10)|difficulty(0) ,imodbits_cloth,
[(ti_on_init_item,
[(store_trigger_param_1, ":agent_no"),(store_trigger_param_2, ":troop_no"),
(call_script, "script_shield_item_set_banner", "tableau_tab_heraldic_brigandine_narf", ":agent_no", ":troop_no"),
(store_random_in_range,":rand_accessory","str_accessory_bagsbottles_randomleft_0","str_accessory_bagsbottles_randomleft_end"),
(store_random_in_range,":probability",0,100),
(try_begin),
    (lt, ":probability", 50), # The script only continues with a probability of 50 %
    (cur_item_add_mesh, ":rand_accessory"),
(try_end),
(store_random_in_range,":rand_accessory2","str_accessory_bagsbottles_randomright_0","str_accessory_bagsbottles_randomright_end"),
(store_random_in_range,":probability2",0,100),
(try_begin),
    (lt, ":probability2", 50), # The script only continues with a probability of 50 %
    (cur_item_add_mesh, ":rand_accessory2"),
(try_end),])]
],
 
Back
Top Bottom