OSP Code SP In-Game Armour Customization with Tutorial

Users who are viewing this thread

Somebody

Code Pope
Baron
WBWF&S
Introduction

Many mods add variation by re-texturing the same base mesh and having duplicate item entries - this project intends to address that by simplifying game assets and re-using them where possible. This OSP is a demonstration of the
Code:
cur_item_add_mesh
and
Code:
cur_item_set_material
operations added in 1.158. It takes some time to set up but allows you to unify resources and save a lot of room at the expense of set-up time. It also gives players more control over their in-game appearance compared to having only a certain amount of pre-set loadouts. I'll be uploading the actual assets over the next few days so you can test it out before deciding if this is right for your mod.




2p3n4.png

Getting Started
yaWEX.jpg
First of all you need to find something you want the player to customize, typically a piece of armor. Split up your mesh into several logical parts, using OpenBRF or an external 3d editor. Remember that these meshes won't be sorted by proximity to eachother. Don't forget to copy rigging/fix the frames. Remember that most of the complicated meshes have dozens of components, so don't forget to rotate the camera and gather the submeshes which have no backfaces. While you're doing this you might as well optimize the mesh and clean it up a bit to prepare it for the next step. If your armor has frames, those need to be split up and reimplemented later (for working feminized armor).
tjeBU.jpg
In the images above (from the Grim Age OSP) you can see armor being broken up into several parts. You should always keep in mind whether a mesh can be shared - in the above example the cloth arms and trouser components are re-used throughout the mod. Keep in mind that some meshes while visually similar will use different material atlas - the existing multimesh structure gives you a starting point.
Then you need to make sure all the assets have the same number of .LOD meshes. While OpenBRF can do this for you, hand-making lods allow you have finer artistic control to re-use them. Of course you can always be lazy and just not make any at all, but this will lead to greatly reduced performance if you allow the armor to be used by NPCs.

Basic Coding
Code:
["aketon", "Aketon", [("aketon",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs|itp_civilian,0,
 325 , weight(3)|abundance(100)|head_armor(0)|body_armor(22)|leg_armor(6)|difficulty(0) ,imodbits_cloth,
 [(ti_on_init_item, 
  [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (call_script, "script_init_aketon", ":agent_no", ":troop_no", 1),
    (cur_item_add_mesh, s1), #submesh 1
    (call_script, "script_init_aketon", ":agent_no", ":troop_no", 2),
    (cur_item_add_mesh, s1), #submesh 2
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":color", "itm_aketon", slot_item_player_color),
      (gt, ":color", -1),
    (else_try),
      (store_random_in_range, ":color", 0, 6),
    (try_end),

    (val_mod, ":color", 6),
    (str_clear, s1),
    (val_add, ":color", "str_hose_r"),
    (str_store_string, s1, ":color"),
    (cur_item_set_material, s1, 2), #second mesh = legs
    ])
  ]],
  • ti_on_init_item is the trigger which is called whenever an item is loaded. This can be in a scene, or even in the inventory. However there are engine limitations - while it launches for every item in the inventory, actual testing found that it did not trigger for horses, gloves and boots. This means that realistically we can only hope to change weapons/head/body armor, but there exists code to override the other items. You can also use WSE which allows it to work for horse last I checked.
  • Code:
    (cur_item_add_mesh, s)
    takes one parameter, a string register. The mesh stored in that string register then gets added to the base mesh, which I recommend you set up as a static part of the mesh (a belt shared between armors for example). You can add as many as you want up to a reasonable limit, again keeping in mind that the number of .LOD should match.
  • Code:
    (cur_item_set_material, s, n)
    takes an additional parameter, with the string register holding the material reference and the second parameter being the index of the sub-mesh to apply the material (from 0). I have found some difficulty allowing it to apply to a higher index higher than 2 than before the game crashes.
  • You can set the .LOD as optional parameters for both operations but then it gets messy to code. This can interact with tableau operations to apply dynamic vertex colouring but I feel like they would not play nice together.
An easy experiment is to make the code work for toggling Native materials

Code:
["coat_of_plates_red", "Arena Coat of Plates", [("coat_of_plates_red",0)], itp_merchandise| itp_type_body_armor  |itp_covers_legs ,0,
 3828 , weight(25)|abundance(100)|head_armor(0)|body_armor(52)|leg_armor(16)|difficulty(8) ,imodbits_armor,
 [(ti_on_init_item,
    [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (try_begin),
      (item_get_slot, ":color", "itm_coat_of_plates_red", slot_item_player_color),
      (eq, ":color", -1),
      (try_begin),
        (troop_is_hero, ":troop_no"),
        (store_add, ":color", ":troop_no", 1),
      (else_try),
        (agent_is_active, ":agent_no"),
        (store_add, ":color", ":agent_no", 2),
      (else_try), #Black, Red, RBGY
        (store_random_in_range, ":color", 0, 5),
      (try_end),
    (try_end),
    (val_mod, ":color", 6),
    (str_clear, s1),
    (val_add, ":color", "str_cop_material"),
    (str_store_string, s1, ":color"),
    (cur_item_set_material, s1, 0),
    ])
  ]],
Code:
    (item_set_slot, "itm_coat_of_plates_red", slot_item_materials_begin, "str_cop_material"),
    (item_set_slot, "itm_coat_of_plates_red", slot_item_materials_end, "str_platemail_cloak_1"),
    (item_set_slot, "itm_coat_of_plates_red", slot_item_num_components, 1),
Code:
  #coat of plate reskins
  ("cop_material", "coat_of_plates_a"),
  ("cop_red", "coat_of_plates_red"),
  ("cop_1", "coat_of_plates_arena"),
  ("cop_2", "coat_of_plates_blue"),
  ("cop_3", "coat_of_plates_green"),
  ("cop_4", "coat_of_plates_yellow"),
Setting up
We need to define a lot of constants and set the proper slots for our armour to work. We have a presentation which allows the player to preview their settings and change them (involving a custom tableau). We have a script which dumps out strings. Finally we have the item initialization script itself, which puts the armour together dynamically. For debugging purposes I have split this up into several item slots, one for each option. If you want different degrees of customization for kings and such they should be bound to one troop slots instead, which you can achieve by masking the individual values and unpacking as needed. Because we are working across multiple game objects, we need to use some globals to pass them around :fruity: especially in presentations.
Categorizing meshes
OQ146.jpg

Example of options
lunLC.jpg
The code works like this: The item checks its own slots, and if a value is set it calls a script requesting a string. Here we just check if the agent wearing the armor is a hero, but you can impose any condition. The script compartmentalizes the various meshes and keeps everything tidy and also returns meta-data after storing the result in s1. This is used by the presentation to decide whether the mesh is a mandatory part of the item or not, or if it's one of several options. These are then displayed and the player can change them from the default values. Mandatory ones are represented by combo-boxes and optional ones are check boxes. You should still do error checking for the range in the script and for the return value to make sure the game doesn't crash when slots have improper values.

And without further ado, here's the basic framework. I will get around to packaging the actual meshes and adding links to them.
Code:
armor_cloth                   = 0
armor_armor                   = 1
armor_plate                   = 2

custom_armor_maximum_submaterial = 7 #armor_plate + 4, thanks platemail
slot_item_materials_begin = 81
slot_item_materials_end = 82
slot_item_num_components = 83
slot_item_init_script = 84
#mandatory + optional | color
slot_item_player_slots_begin = 85
slot_item_player_slots_end = slot_item_player_slots_begin + custom_armor_maximum_submaterial
slot_item_player_color = slot_item_player_slots_end

custom_item_color_mask = 0xf
custom_item_color_bits = 4

message_positive = 0x33FF33
message_negative = 0xFF3333
message_neutral = 0xFFFF33
Code:
  ("cheat_find_item",0,
   "{!}Current item range: {reg5} to {reg6}",
   "none",
   [
     (assign, reg5, "$cheat_find_item_range_begin"),
     (store_add, reg6, "$cheat_find_item_range_begin", max_inventory_items),
     (val_min, reg6, "itm_items_end"),
     (val_sub, reg6, 1),
 
     (assign, ":end", ek_foot), #should add a global as iterator
     (try_for_range, ":item_slot", ek_item_0, ":end"),
       (troop_get_inventory_slot, ":item_no", "$g_player_troop", ":item_slot"),
       (gt, ":item_no", -1),
       (item_slot_ge, ":item_no", slot_item_num_components, 1),
       (assign, "$g_current_opened_item_details", ":item_no"),
       (assign, ":end", -1),
     (try_end),
    
     ],
    [
      ("custom_armor",[
        (item_slot_ge, "$g_current_opened_item_details", slot_item_num_components, 1),
        (str_store_item_name, s0, "$g_current_opened_item_details"),
      ],"Customize {s0}",
        [
        (start_presentation, "prsnt_customize_armor"),
        ]),
Code:
  #takes g_current_opened_item_details as parameter
  ("customize_armor", prsntf_manual_end_only, 0, [ 
    (ti_on_presentation_load,
     [(set_fixed_point_multiplier, 1000),

      (assign, "$g_presentation_credits_obj_1", -1),
      (assign, "$g_presentation_credits_obj_2", -1),
      (assign, "$g_presentation_credits_obj_3", -1),
      (assign, "$g_presentation_credits_obj_4", -1),
      (assign, "$g_presentation_credits_obj_5", -1),
      (assign, "$g_presentation_obj_item_select_1", -1),
      (assign, "$g_presentation_obj_item_select_2", -1),
      (assign, "$g_presentation_obj_item_select_3", -1),

      (try_begin),
        (create_mesh_overlay, reg0, "mesh_cb_ui_main"),
        (position_set_x, pos1, 0),
        (position_set_y, pos1, 0),
        (overlay_set_position, reg0, pos1),
        (position_set_x, pos1, 1000),
        (position_set_y, pos1, 1000),
        (overlay_set_size, reg0, pos1),
      (try_end),
      #background for menu
      (try_begin),
        (create_mesh_overlay, reg0, "mesh_mp_score_a"),
        (position_set_x, pos1, 295),
        (position_set_y, pos1, 115),
        (overlay_set_position, reg0, pos1),
        (position_set_x, pos1, 1000),
        (position_set_y, pos1, 1000),
        (overlay_set_size, reg0, pos1),
      (try_end),
      #clear arrays - use a for radio buttons, b for dropdowns, c for text
      (try_for_range, ":slot_no", 0, custom_armor_maximum_submaterial),
        (troop_set_slot, "trp_temp_array_a", ":slot_no", -1),
        (troop_set_slot, "trp_temp_array_b", ":slot_no", -1),
        (troop_set_slot, "trp_temp_array_c", ":slot_no", -1),
      (try_end),
      
      # (item_get_slot, ":item_variation", "$g_current_opened_item_details", slot_item_player_color),
      (item_get_slot, ":sub_mesh_total", "$g_current_opened_item_details", slot_item_num_components),
      (item_get_slot, ":script_no", "$g_current_opened_item_details", slot_item_init_script),
      (try_begin),
        (gt, ":script_no", 0),
        (assign, ":cur_combobox", 0),
        (assign, ":cur_checkbox", 0),
        (assign, ":cur_textbox", 0),
        (try_for_range, ":sub_mesh", 0, ":sub_mesh_total"),
          (call_script, ":script_no", -1, "$g_player_troop", ":sub_mesh", 0), #get upper bound
          (assign, ":sub_total", "$g_custom_armor_param_count"),
          (assign, ":overlay", -1),
          (try_begin), #only 1 mesh, just a text overlay
            (eq, ":sub_total", 1),
            (eq, "$g_custom_armor_mandatory", 1),
            (create_text_overlay, ":overlay", s1, tf_single_line|tf_left_align),
            # (overlay_set_text, ":overlay", s1),
            (troop_set_slot, "trp_temp_array_c", ":cur_textbox", ":overlay"),
            (val_add, ":cur_textbox", 1),
          (else_try), #assume if first one passes at 0 index, the rest are also mandatory
            (gt, ":sub_total", 1),
            (eq, "$g_custom_armor_mandatory", 1),
            (create_combo_button_overlay, ":overlay"),
            (troop_set_slot, "trp_temp_array_b", ":cur_combobox", ":overlay"),
            (overlay_add_item, ":overlay", "str_randomize"), #default -1 value, "random" depends on item
            (overlay_add_item, ":overlay", s1), #from calling sub_material 0
            (val_add, ":cur_combobox", 1),
            (try_for_range, ":sub_material", 1, ":sub_total"),
                (str_clear, s1),
                (call_script, ":script_no", -1, "$g_player_troop", ":sub_mesh", ":sub_material"),
                (neg|str_is_empty, s1),
                (overlay_add_item, ":overlay", s1),
            (try_end),
          (else_try), #optional mesh, assume all the following can and will apply
            (gt, ":sub_total", 0),
            (try_for_range, ":sub_material", 0, ":sub_total"),
                (str_clear, s1),
                (call_script, ":script_no", -1, "$g_player_troop", ":sub_mesh", ":sub_material"),
                (eq, "$g_custom_armor_mandatory", 0),
                (neg|str_is_empty, s1),
                (create_check_box_overlay, ":overlay", "mesh_checkbox_off", "mesh_checkbox_on"),
                # (overlay_set_tooltip, ":overlay", s1),
                (troop_set_slot, "trp_temp_array_a", ":cur_checkbox", ":overlay"),
                #create a text directly after
                (create_text_overlay, ":overlay", s1, tf_single_line|tf_left_align),
                (val_add, ":cur_checkbox", 1),
            (try_end),
          (try_end),
        (try_end),
        
        #arrange overlays, set values now that we have all of them
        #TODO add 2xcontainer on either side
        (assign, ":cur_x", 150),
        (assign, ":cur_y", 600),
        (position_set_x, pos1, ":cur_x"),
        (assign, ":cur_mesh_slot", slot_item_player_slots_begin),
        (try_for_range, ":slot_no", 0, ":cur_combobox"),
          (troop_get_slot, ":overlay", "trp_temp_array_b", ":slot_no"),
          (gt, ":overlay", -1),
          (position_set_y, pos1, ":cur_y"),
          (overlay_set_position, ":overlay", pos1),
          (try_begin),
            (item_get_slot, ":cur_value", "$g_current_opened_item_details", ":cur_mesh_slot"),
            (val_add, ":cur_value", 1), #should probably cap this somewhere
            (overlay_set_val, ":overlay", ":cur_value"),
            (val_add, ":cur_mesh_slot", 1),
          (try_end),
          (val_sub, ":cur_y", 100), #resize this depending on amount in each combo?
          (try_begin),
            (le, ":cur_y", 100),
            (assign, ":cur_y", 800),
            (val_add, ":cur_x", 100),
            (position_set_x, pos1, ":cur_x"),
          (try_end),
        (try_end),
        
        (try_begin), #no 2nd column boxes so we apply labels in original column
          (eq, ":cur_x", 150),
          (val_sub, ":cur_x", 125),
        (try_end),
        # (assign, ":cur_y", 600),
        (position_set_x, pos1, ":cur_x"),
        (try_for_range, ":slot_no", 0, ":cur_textbox"),
          (troop_get_slot, ":overlay", "trp_temp_array_c", ":slot_no"),
          (gt, ":overlay", -1),
          (position_set_y, pos1, ":cur_y"),
          (overlay_set_position, ":overlay", pos1),
          (overlay_set_color, ":overlay", 0xFFFFFF),
          (val_sub, ":cur_y", 50),
          (try_begin), #reset to top
            (le, ":cur_y", 200),
            (assign, ":cur_y", 800),
            (val_add, ":cur_x", 50),
            (position_set_x, pos1, ":cur_x"),
          (try_end),
        (try_end),

        (assign, ":cur_x", 750),
        (assign, ":cur_y", 600),
        (position_set_x, pos2, 800),
        (position_set_y, pos2, 800),
        (store_sub, ":cur_mesh_slot", slot_item_player_slots_end, 1),
        (try_for_range, ":slot_no", 0, ":cur_checkbox"),
          (troop_get_slot, ":overlay", "trp_temp_array_a", ":slot_no"),
          (gt, ":overlay", -1),
          (position_set_x, pos1, ":cur_x"),
          (position_set_y, pos1, ":cur_y"),
          (overlay_set_position, ":overlay", pos1),
          (try_begin),
            (item_get_slot, ":cur_value", "$g_current_opened_item_details", ":cur_mesh_slot"),
            (neq, ":cur_value", -1), #checkboxes only have 2 states unfortnately
            (overlay_set_val, ":overlay", ":cur_value"),
          (try_end),
          
          #move text
          (val_add, ":overlay", 1),
          (try_begin),
            (eq, ":cur_value", 1),
            (assign, ":color", message_positive),
          (else_try),
            (eq, ":cur_value", 0),
            (assign, ":color", message_negative),
          (else_try),
            (assign, ":color", message_neutral),
          (try_end),
          (overlay_set_color, ":overlay", ":color"),
          (store_add, ":text_x", ":cur_x", 50),
          (position_set_x, pos1, ":text_x"),
          (overlay_set_position, ":overlay", pos1),
          (overlay_set_size, ":overlay", pos2),
          (val_sub, ":cur_mesh_slot", 1),
          (val_sub, ":cur_y", 75),
          (try_begin),
            (le, ":cur_y", 200),
            (assign, ":cur_y", 800),
            (val_add, ":cur_x", 100),
            (position_set_x, pos1, ":cur_x"),
          (try_end),
        (try_end),
        #store these as globals
        (assign, "$g_presentation_obj_item_select_1", ":cur_combobox"),
        (assign, "$g_presentation_obj_item_select_2", ":cur_checkbox"),
        (assign, "$g_presentation_obj_item_select_3", ":cur_textbox"),
      (try_end),
      (store_sub, reg1, ":sub_mesh_total", 1),
      (val_max, reg1, 1),
      (str_store_item_name, s1, "$g_current_opened_item_details"),
      (create_text_overlay, reg0, "@{s1} has {reg1} component meshes", tf_center_justify|tf_single_line|tf_with_outline),
      (position_set_x, pos1, 500),
      (position_set_y, pos1, 700),
      (overlay_set_position, reg0, pos1),
      (overlay_set_color, reg0, 0xFFFFFF),
  
      # (try_for_range, ":slot_no", slot_item_player_slots_begin, slot_item_player_slots_end + 1),
        # (item_get_slot, reg1, "$g_current_opened_item_details", ":slot_no"),
        # (assign, reg2, ":slot_no"),
        # (display_message, "@[{reg2}]:{reg1}"),
      # (try_end),
      #rearrange components, mandatory on left and toggles on right
      
      (create_image_button_overlay_with_tableau_material, "$g_presentation_credits_obj_1", -1, "tableau_custom_armor_window", "$g_player_troop"),
      (position_set_x, pos1, 380),
      (position_set_y, pos1, 200),
      (overlay_set_position, "$g_presentation_credits_obj_1", pos1),
      # (position_set_x, pos1, 1500),
      # (position_set_y, pos1, 1500),
      # (overlay_set_size, "$g_presentation_credits_obj_1", pos1),
      (try_begin),
        (item_get_slot, ":colors_begin", "$g_current_opened_item_details", slot_item_materials_begin),
        (gt, ":colors_begin", 0),
        (item_get_slot, ":colors_end", "$g_current_opened_item_details", slot_item_materials_end),
        (create_combo_label_overlay, "$g_presentation_credits_obj_3"),
        (position_set_x, pos1, 500),
        (position_set_y, pos1, 135),
        (overlay_set_position, "$g_presentation_credits_obj_3", pos1),
        (overlay_add_item, "$g_presentation_credits_obj_3", "str_color"), #default label
        (try_for_range, ":color", ":colors_begin", ":colors_end"),
          (overlay_add_item, "$g_presentation_credits_obj_3", ":color"),
        (try_end),
        # (troop_get_slot, ":cur_color", "$g_player_troop", ),
        (item_get_slot, ":cur_color", "$g_current_opened_item_details", slot_item_player_color),
        (val_add, ":cur_color", 1),
        # (try_begin), #player set this somewhere
          # (gt, ":cur_color", -1),
        (overlay_set_val, "$g_presentation_credits_obj_3", ":cur_color"),
        # (try_end),
      (try_end),
      
      (position_set_y, pos1, 90),
      (store_sub, ":item_no", "$g_current_opened_item_details", 1),
      (try_begin),
        (item_slot_ge, ":item_no", slot_item_num_components, 1),
        (str_store_item_name, s0, ":item_no"),
        (create_button_overlay, "$g_presentation_credits_obj_4", s0),
        (position_set_x, pos1, 250),
        (overlay_set_position, "$g_presentation_credits_obj_4", pos1),
      (try_end),
      (store_add, ":item_no", "$g_current_opened_item_details", 1),
      (try_begin),
        (item_slot_ge, ":item_no", slot_item_num_components, 1),
        (str_store_item_name, s0, ":item_no"),
        (create_button_overlay, "$g_presentation_credits_obj_5", s0),
        (position_set_x, pos1, 575),
        (overlay_set_position, "$g_presentation_credits_obj_5", pos1),
      (try_end),
      (create_game_button_overlay, "$g_presentation_obj_profile_banner_selection_1", "str_reset_to_default"),
      (create_game_button_overlay, "$g_presentation_obj_profile_banner_selection_2", "str_done"),
      (position_set_y, pos1, 50),
      (position_set_x, pos1, 425),
      (overlay_set_position, "$g_presentation_obj_profile_banner_selection_1", pos1),
      (position_set_x, pos1, 575),
      (overlay_set_position, "$g_presentation_obj_profile_banner_selection_2", pos1),
      
      (presentation_set_duration, 999999),
      ]),
      
    (ti_on_presentation_mouse_enter_leave,
       [(store_trigger_param_1, ":object"),
        (try_begin),
          (eq, ":object", "$g_presentation_credits_obj_1"),
          (store_trigger_param_2, ":enter_leave"),
          (try_begin),
            (eq, ":enter_leave", 0),
            (try_begin),
              (assign, ":item_modifier", imod_plain),
              (item_get_type, ":item_type", "$g_current_opened_item_details"),
              (try_begin),
                (is_between, ":item_type", itp_type_head_armor, itp_type_pistol), #head/body/foot/hand
                (val_add, ":item_type", ek_head - itp_type_head_armor),
              (else_try), #pretty sure you can't customize ammo but w/e
                (this_or_next|is_between, ":item_type", itp_type_one_handed_wpn, itp_type_goods),
                (is_between, ":item_type", itp_type_pistol, itp_type_animal),
                #find it on the troop
                (try_for_range, ":slot_no", ek_item_0, ek_head),
                  (troop_get_inventory_slot, ":item_no", "$g_player_troop", ":slot_no"),
                  (eq, ":item_no", "$g_current_opened_item_details"),
                  (assign, ":item_type", ":slot_no"),
                (try_end),
              (try_end),
              (is_between, ":item_type", ek_item_0, ek_horse), #validate input
              (troop_get_inventory_slot_modifier, ":item_modifier", "$g_player_troop", ":item_type"),
              # (overlay_get_position, pos0, ":object"),
              (mouse_get_position, pos0),
              (show_item_details_with_modifier, "$g_current_opened_item_details", ":item_modifier", pos0, 100),
            (try_end),
          (else_try),
            (eq, ":enter_leave", 1),
            (close_item_details),
          (try_end),
        (try_end),
        ]),

    (ti_on_presentation_event_state_change,
      [
        (store_trigger_param_1, ":object"),
        (store_trigger_param_2, ":value"),
        (assign, ":continue", 0),

        (try_begin), #color toggler
          (gt, "$g_presentation_credits_obj_3", -1),
          (eq, ":object", "$g_presentation_credits_obj_3"), #combolabel, switch colours
          # (item_get_slot, ":cur_color", "$g_current_opened_item_details", slot_item_player_color),
          (store_sub, ":color", ":value", 1), #actual value, 0 is default
          (item_set_slot, "$g_current_opened_item_details", slot_item_player_color, ":color"),
        (else_try), #actual item tableau
          (eq, ":object", "$g_presentation_credits_obj_1"), #tableau, switch view sides
          (val_add, "$g_custom_armor_angle", 1),
          (val_mod, "$g_custom_armor_angle", 6), #60x6
          # #apply current colour settings
          # (try_begin),
            # (gt, "$g_presentation_credits_obj_3", -1),
            # (overlay_get_value, ":value", "$g_presentation_credits_obj_3"),
            # (item_set_slot, "$g_current_opened_item_details", slot_item_player_color, ":value"),
          # (try_end),
        (else_try), #reset to default, refresh
          (eq, ":object", "$g_presentation_obj_profile_banner_selection_1"),
          (try_for_range, ":slot_no", slot_item_player_slots_begin, slot_item_player_slots_end + 1),
            (item_set_slot, "$g_current_opened_item_details", ":slot_no", -1),
          (try_end),
        (else_try), #prev
          (eq, ":object", "$g_presentation_credits_obj_4"),
          (val_sub, "$g_current_opened_item_details", 1),
        (else_try), #next
          (eq, ":object", "$g_presentation_credits_obj_5"),
          (val_add, "$g_current_opened_item_details", 1),
        (else_try), #close
          (eq, ":object", "$g_presentation_obj_profile_banner_selection_2"),
          (assign, ":continue", -1),
          (presentation_set_duration, 0),
        (else_try), #go after presentation object stored in arrays, left side combos
          (gt, "$g_presentation_obj_item_select_1", 0),
          (assign, ":cur_mesh_slot", slot_item_player_slots_begin - 1),
          (try_for_range, ":slot_no", 0, "$g_presentation_obj_item_select_1"),
            (val_add, ":cur_mesh_slot", 1), #pre-increment
            (troop_slot_eq, "trp_temp_array_b", ":slot_no", ":object"),
            # (assign, reg0, ":slot_no"),
            # (assign, reg1, ":cur_mesh_slot"),
            (store_sub, ":color", ":value", 1),
            # (assign, reg2, ":color"),
            # (display_message, "@{reg0} setting [{reg1}] to {reg2}"),
            (item_set_slot, "$g_current_opened_item_details", ":cur_mesh_slot", ":color"),
            (assign, "$g_presentation_obj_item_select_1", -1), #loop break
          (try_end),
          (eq, "$g_presentation_obj_item_select_1", -1), #pass on to next block if not fulfilled
        (else_try), #start from other end of sub_mesh_total, right side checkbox
          (gt, "$g_presentation_obj_item_select_2", 0),
          (assign, ":cur_mesh_slot", slot_item_player_slots_end),
          (try_for_range, ":slot_no", 0, "$g_presentation_obj_item_select_2"),
            (val_sub, ":cur_mesh_slot", 1),
            (troop_slot_eq, "trp_temp_array_a", ":slot_no", ":object"),
            (item_set_slot, "$g_current_opened_item_details", ":cur_mesh_slot", ":value"),
            # (assign, reg0, ":slot_no"),
            # (assign, reg1, ":cur_mesh_slot"),
            # (assign, reg2, ":value"),
            # (display_message, "@{reg0} setting [{reg1}] to {reg2}"),
            (assign, "$g_presentation_obj_item_select_2", -1), #loop break
          (try_end),
        (try_end),
        (try_begin),
          (eq, ":continue", 0),
          (start_presentation, "prsnt_customize_armor"),
          (try_begin), #refresh me
            # (in_meta_mission),
            (get_player_agent_no, ":player_agent"),
            (gt, ":player_agent", -1),
            (agent_has_item_equipped, ":player_agent", "$g_current_opened_item_details"),
            (agent_unequip_item, ":player_agent", "$g_current_opened_item_details"),
            (agent_equip_item, ":player_agent", "$g_current_opened_item_details"),
          (try_end),
        (try_end),
      ]),
    ]),
Code:
    (item_set_slot, "itm_plate_custom", slot_item_materials_begin, "str_platemail_cloak_1"),
    (item_set_slot, "itm_plate_custom", slot_item_materials_end, "str_platemail_heraldic"),
    (item_set_slot, "itm_plate_custom", slot_item_num_components, 7),
    (item_set_slot, "itm_plate_custom", slot_item_init_script, "script_init_plate_custom"),
    (try_for_range, ":slot_no", slot_item_player_slots_begin, slot_item_player_slots_end + 1),
      (item_set_slot, "itm_plate_custom", ":slot_no", -1),
    (try_end),
Code:
  ("init_plate_custom",
    [
    (store_script_param, ":agent_no", 1),
    (store_script_param, ":troop_no", 2),
    (store_script_param, ":sub_mesh", 3),
    (store_script_param, ":sub_mats", 4),
    (str_clear, s1),
    (assign, ":value", -1),
    (assign, "$g_custom_armor_param_count", 3),
    (assign, "$g_custom_armor_mandatory", 1),

    (try_begin), #torso
      (eq, ":sub_mesh", 0),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_heraldic"),
      # (assign, "$g_custom_armor_param_count", 3),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #pauldrons
      (eq, ":sub_mesh", 1),
      (is_between, ":sub_mats", 0, 4),
      (store_add, ":value", ":sub_mats", "str_platemail_pauldron_1"),
      (assign, "$g_custom_armor_param_count", 4),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #rondels
      (eq, ":sub_mesh", 2),
      (is_between, ":sub_mats", 0, 4),
      (store_add, ":value", ":sub_mats", "str_platemail_rondel_0"),
      (assign, "$g_custom_armor_param_count", 4),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #knees
      (eq, ":sub_mesh", 3),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_knees_0"),
    (else_try), #elbows
      (eq, ":sub_mesh", 4),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_elbows_0"),
    (else_try), #accessories
      (eq, ":sub_mesh", 5),
      (is_between, ":sub_mats", 0, 2),
      (store_add, ":value", ":sub_mats", "str_platemail_accessory_1"),
      (assign, "$g_custom_armor_param_count", 2),
      (assign, "$g_custom_armor_mandatory", 0),
    (else_try),
      (assign, "$g_custom_armor_param_count", 0),
      (assign, "$g_custom_armor_mandatory", 0),
    (try_end),
    
    (try_begin),
      (neq, ":value", -1),
      (str_store_string, s1, ":value"),
    (try_end),
    
    ]
  ),
Code:
  #script_add_troop_to_custom_armor_tableau
  # INPUT: troop_no, item (g_current_opened_item_details), side (g_custom_armor_angle)
  # OUTPUT: none
  ("add_troop_to_custom_armor_tableau",
    [
       (store_script_param, ":troop_no",1),
       (store_mul, ":side", "$g_custom_armor_angle", 60), #add some more sides
       
       (set_fixed_point_multiplier, 100),

       (cur_tableau_clear_override_items),
       (cur_tableau_set_override_flags, af_override_weapons),

       (init_position, pos2),
       (position_rotate_z, pos2, ":side"),
       (cur_tableau_set_camera_parameters, 1, 4, 6, 10, 10000),

       (init_position, pos5),
       (assign, ":cam_height", 105),
#       (val_mod, ":camera_distance", 5),
       (assign, ":camera_distance", 380),
       (assign, ":camera_yaw", -15),
       (assign, ":camera_pitch", -18),
       (val_clamp, "$g_custom_armor_angle", 0, anim_walk_forward_crouch - anim_walk_backward),
       (store_add, ":animation", "$g_custom_armor_angle", "anim_walk_backward"),

       (position_set_z, pos5, ":cam_height"),

       # camera looks towards -z axis
       (position_rotate_x, pos5, -90),
       (position_rotate_z, pos5, 180),

       # now apply yaw and pitch
       (position_rotate_y, pos5, ":camera_yaw"),
       (position_rotate_x, pos5, ":camera_pitch"),
       (position_move_z, pos5, ":camera_distance", 0),
       (position_move_x, pos5, 5, 0),

       (try_begin), #shouldn't be necessary, it's already on the troop (player character)
         (gt, "$g_current_opened_item_details", -1),
         (cur_tableau_add_override_item, "$g_current_opened_item_details"),
       (try_end),
       
       (cur_tableau_add_troop, ":troop_no", pos2, ":animation", -1),
       (cur_tableau_set_camera_position, pos5),

       (copy_position, pos8, pos5),
       (position_rotate_x, pos8, -90), #y axis aligned with camera now. z is up
       (position_rotate_z, pos8, 30),
       (position_rotate_x, pos8, -60),
       (cur_tableau_add_sun_light, pos8, 155,155,155),
     ]),
Code:
      (ti_inventory_key_pressed, 0, 0,
      [
        (game_key_is_down, gk_view_char),
        # (set_trigger_result,1),
      ], [
        (get_player_agent_no, ":player_agent"),
        (assign, ":end", ek_foot), #should add a global as iterator
        (try_for_range, ":item_slot", ek_item_0, ":end"),
          (agent_get_item_slot, ":item_no", ":player_agent", ":item_slot"),
          (gt, ":item_no", -1),
          (item_slot_ge, ":item_no", slot_item_num_components, 1),
          (assign, "$g_current_opened_item_details", ":item_no"),
          (assign, ":end", -1),
          (start_presentation, "prsnt_customize_armor"),
        (try_end),
        (try_begin), #none found
          (eq, ":end", ek_foot),
          (display_message, "str_cant_use_inventory_tutorial"),
          (assign, "$g_current_opened_item_details", -1),
        (try_end),
      ]),
Code:
  ("custom_armor_window", 0, "tableau_with_transparency", 1024, 1024, 0, 0, 240, 400,
   [
       (store_script_param, ":troop_no", 1),
       (cur_tableau_set_background_color,0xFF888888),
       (cur_tableau_set_ambient_light, 15,14,13),
       (set_fixed_point_multiplier, 100),
       (cur_tableau_set_camera_parameters, 0, 40, 40, 0, 100000),

       (init_position, pos1),
       (position_set_z, pos1, 100),
       (position_set_x, pos1, -20),
       (position_set_y, pos1, -20),
       (cur_tableau_add_tableau_mesh, "tableau_custom_armor_color", ":troop_no", pos1, 0, 0),
       (position_set_z, pos1, 200),
       (cur_tableau_add_tableau_mesh, "tableau_custom_armor_alpha_mask", ":troop_no", pos1, 0, 0),
       (position_set_z, pos1, 300),
       ]),
  ("custom_armor_alpha_mask", 0, "mat_troop_portrait_mask", 1024, 1024, 0, 0, 400, 400,
   [
       (store_script_param, ":troop_no", 1),
       (cur_tableau_set_background_color, 0x00888888),
       (cur_tableau_set_ambient_light,15,14,13),
       (cur_tableau_render_as_alpha_mask),
       (call_script, "script_add_troop_to_custom_armor_tableau", ":troop_no"),
       ]),

  ("custom_armor_color", 0, "mat_troop_portrait_color", 1024, 1024, 0, 0, 400, 400,
   [
       (store_script_param, ":troop_no", 1),
       (cur_tableau_set_background_color, 0xFF888888), #random colour
       (cur_tableau_set_ambient_light,15,14,13),
       (call_script, "script_add_troop_to_custom_armor_tableau", ":troop_no"),
       ]),
Download & Credits
Narf's Men-at-Arms OSP uploaded here and there
Baraban's platemail OSP uploaded here
Crusader: Way to Expiation uploaded here
Grim Age OSP
 

Somebody

Code Pope
Baron
WBWF&S
The plate armour in the first picture has been uploaded. These include some of the armour packaged by Baraban (originally from A2K?) as shown below, but if you left them out the BRF file would be less than a quarter of the size.
S39w6.png

Code:
# Dunde's 1 Liner Heraldic Code
def heraldic(item_tableau):
  return (ti_on_init_item, [(store_trigger_param_1, ":agent_no"),(store_trigger_param_2, ":troop_no"),(call_script, "script_shield_item_set_banner", item_tableau, ":agent_no", ":troop_no")])
Code:
["plate_custom", "Knightly Plate Harness", [("platemail_legs",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs ,0,
 10000, weight(27.5)|abundance(10)|head_armor(0)|body_armor(62)|leg_armor(21)|difficulty(16), imodbits_armor,
 [(ti_on_init_item, [
  (store_trigger_param_1, ":agent_no"),
  (store_trigger_param_2, ":troop_no"),
  (str_clear, s1),

  #add torso first
  (try_begin), #heraldic, ornate, harness
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin),
    (eq, ":value", -1),
    (store_random_in_range, ":value", 0, 3),
  (try_end),
  (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 0, ":value"),
  (cur_item_add_mesh, s1),
  
  #then pauldrons
  (try_begin), #2 "gothic" variants
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 1),
    (eq, ":value", -1),
    (store_random_in_range, ":value", 0, 4),
  (try_end),
  (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 1, ":value"),
  (cur_item_add_mesh, s1),
  
  #then optional selections
  (try_begin), #3x rondels
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 2),
    (eq, ":value", -1),
    (store_random_in_range, ":value", 0, 3),
    (val_add, ":value", 1), #skip "none"
  (try_end),
  (try_begin),
    (neq, ":value", 0),
    (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 2, ":value"),
    (cur_item_add_mesh, s1),
  (try_end),
  
  (try_begin), #2x knees
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 3),
    (eq, ":value", -1),
    (store_random_in_range, ":value", 0, 2),
    (val_add, ":value", 1), #skip "none"
  (try_end),
  (try_begin),
    (neq, ":value", 0),
    (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 3, ":value"),
    (cur_item_add_mesh, s1),
  (try_end),
  
  (try_begin), #2x elbows
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 4),
    (eq, ":value", -1),
    (store_random_in_range, ":value", 0, 2),
    (val_add, ":value", 1), #skip "none"
  (try_end),
  (try_begin),
    (neq, ":value", 0),
    (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 4, ":value"),
    (cur_item_add_mesh, s1),
  (try_end),
  
  (try_begin), #2x accessory
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 5),
    (eq, ":value", 1),
    (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 5, 1),
    (cur_item_add_mesh, s1),
  (try_end),
  (try_begin), #(shoulder/thigh plates)
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_slots_begin + 6),
    (eq, ":value", 1),
    (call_script, "script_init_plate_custom", ":agent_no", ":troop_no", 5, 0),
    (cur_item_add_mesh, s1),
  (try_end),
  

  (try_begin), #3x cloaks
    (item_get_slot, ":value", "itm_plate_custom", slot_item_player_color),
    (is_between, ":value", 0, 3),
    (store_add, ":color", ":value", "str_platemail_cloak_1"),
    (str_store_string, s1, ":color"),
    (cur_item_add_mesh, s1),
  (try_end),
  ])
]],
Code:
#platemail harnesses
["plate_armor_new1", "Plate Harness", [("platemail_harness_01",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 7315 , weight(26)|abundance(50)|head_armor(0)|body_armor(60)|leg_armor(20)|difficulty(15) ,imodbits_plate ],
["plate_armor_new2", "Plate Harness", [("platemail_harness_02",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 7153 , weight(27)|abundance(50)|head_armor(1)|body_armor(61)|leg_armor(18)|difficulty(15) ,imodbits_plate ],
["plate_armor_new3", "Ornate Platemail", [("platemail_ornate_03",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 8553 , weight(28)|abundance(30)|head_armor(0)|body_armor(62)|leg_armor(20)|difficulty(16) ,imodbits_plate ],
["plate_armor_new4", "Ornate Platemail", [("platemail_ornate_04",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 8535 , weight(27.5)|abundance(30)|head_armor(0)|body_armor(63)|leg_armor(18)|difficulty(16) ,imodbits_plate ],
["plate_armor_new5", "Ornate Platemail with Cloak", [("platemail_ornate",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 9553 , weight(30)|abundance(25)|head_armor(2)|body_armor(65)|leg_armor(22)|difficulty(18) ,imodbits_plate ],
["plate_armor_new6", "Plate Harness with Cloak", [("platemail_harness",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs, 0,
 8153 , weight(26.5)|abundance(40)|head_armor(3)|body_armor(61)|leg_armor(19)|difficulty(17) ,imodbits_plate ],
#15th century plates
["heraldic_platemail_01", "Heraldic Platemail", [("platemail_heraldic_02",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs ,0,
 7000 , weight(25)|abundance(25)|head_armor(1)|body_armor(58)|leg_armor(18)|difficulty(15),imodbits_armor,
 [heraldic("tableau_platemail_harness_heraldic")]],

["heraldic_platemail_02", "Heraldic Platemail with Cloak", [("platemail_heraldic",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs ,0,
 7500 , weight(26)|abundance(20)|head_armor(2)|body_armor(58)|leg_armor(18)|difficulty(15), imodbits_armor,
 [heraldic("tableau_platemail_harness_heraldic")]],

["heraldic_plate_01", "Heraldic Plate Harness", [("platemail_heraldic_01",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs ,0,
 8000 , weight(25)|abundance(15)|head_armor(0)|body_armor(59)|leg_armor(20)|difficulty(15), imodbits_armor,
 [heraldic("tableau_platemail_harness_heraldic")]],

["heraldic_plate_02", "Heraldic Plate Harness", [("platemail_heraldic_03",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs ,0,
 8500 , weight(26)|abundance(15)|head_armor(0)|body_armor(59)|leg_armor(20)|difficulty(15), imodbits_armor,
 [heraldic("tableau_platemail_harness_heraldic")]],
Code:
    (item_set_slot, "itm_plate_custom", slot_item_materials_begin, "str_platemail_cloak_1"),
    (item_set_slot, "itm_plate_custom", slot_item_materials_end, "str_platemail_heraldic"),
    (item_set_slot, "itm_plate_custom", slot_item_num_components, 7),
    (item_set_slot, "itm_plate_custom", slot_item_init_script, "script_init_plate_custom"),
    (try_for_range, ":slot_no", slot_item_player_slots_begin, slot_item_player_slots_end + 1),
      (item_set_slot, "itm_plate_custom", ":slot_no", -1),
    (try_end),
Code:
  ("init_plate_custom",
    [
    (store_script_param, ":agent_no", 1),
    (store_script_param, ":troop_no", 2),
    (store_script_param, ":sub_mesh", 3),
    (store_script_param, ":sub_mats", 4),
    (str_clear, s1),
    (assign, ":value", -1),
    (assign, "$g_custom_armor_param_count", 3),
    (assign, "$g_custom_armor_mandatory", 1),

    (try_begin), #torso
      (eq, ":sub_mesh", 0),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_heraldic"),
      # (assign, "$g_custom_armor_param_count", 3),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #pauldrons
      (eq, ":sub_mesh", 1),
      (is_between, ":sub_mats", 0, 4),
      (store_add, ":value", ":sub_mats", "str_platemail_pauldron_1"),
      (assign, "$g_custom_armor_param_count", 4),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #rondels
      (eq, ":sub_mesh", 2),
      (is_between, ":sub_mats", 0, 4),
      (store_add, ":value", ":sub_mats", "str_platemail_rondel_0"),
      (assign, "$g_custom_armor_param_count", 4),
      # (assign, "$g_custom_armor_mandatory", 1),
    (else_try), #knees
      (eq, ":sub_mesh", 3),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_knees_0"),
    (else_try), #elbows
      (eq, ":sub_mesh", 4),
      (is_between, ":sub_mats", 0, 3),
      (store_add, ":value", ":sub_mats", "str_platemail_elbows_0"),
    (else_try), #accessories
      (eq, ":sub_mesh", 5),
      (is_between, ":sub_mats", 0, 2),
      (store_add, ":value", ":sub_mats", "str_platemail_accessory_1"),
      (assign, "$g_custom_armor_param_count", 2),
      (assign, "$g_custom_armor_mandatory", 0),
    (else_try),
      (assign, "$g_custom_armor_param_count", 0),
      (assign, "$g_custom_armor_mandatory", 0),
    (try_end),
    
    (try_begin),
      (neq, ":value", -1),
      (str_store_string, s1, ":value"),
    (try_end),
    
    ]
  ),
Code:
  ("platemail_cloak_1", "platemail_cloak_white"),
  ("platemail_cloak_2", "platemail_cloak_fur"),
  ("platemail_cloak_3", "platemail_cloak_purple"),
  
  ("platemail_heraldic", "platemail_heraldic_body"),
  ("platemail_harness", "platemail_harness_body"),
  ("platemail_ornate", "platemail_ornate_body_fix"),

  ("platemail_pauldron_1", "platemail_pauldron_heraldic"),
  ("platemail_pauldron_2", "platemail_pauldron_harness"),
  ("platemail_pauldron_3", "platemail_pauldron_gothic_backface"),
  ("platemail_pauldron_4", "platemail_pauldron_gothic"),

  ("platemail_rondel_0", "No Rondels"),
  ("platemail_rondel_1", "platemail_rondel_round"),
  ("platemail_rondel_2", "platemail_rondel_gold"),
  ("platemail_rondel_3", "platemail_rondel_shell"),
  
  ("platemail_knees_0", "No Knees"),
  ("platemail_knees_1", "platemail_knees_spades"),
  ("platemail_knees_2", "platemail_knees_hearts"),
  
  ("platemail_elbows_0", "No Elbows"),
  ("platemail_elbows_1", "platemail_elbows_round"),
  ("platemail_elbows_2", "platemail_elbows_spiky"),
  
  ("platemail_accessory_1", "platemail_shoulder"),
  ("platemail_accessory_2", "platemail_thigh"),
Code:
("tableau_mesh_platemail_banner", 0, "tableau_mesh_platemail_banner",  0, 0, 0, 0, 0, 0, 1, 1, 1),
Code:
  ("platemail_harness_heraldic", 0, "platemail_08", 1024, 1024, 0, 0, 0, 0,
   [
       (store_script_param, ":banner_mesh", 1),

       (set_fixed_point_multiplier, 100),
       # (store_random_in_range, ":banner_mesh", arms_meshes_begin, arms_meshes_end_minus_one),
       (store_sub, ":background_slot", ":banner_mesh", arms_meshes_begin),
       (troop_get_slot, ":background_color", "trp_banner_background_color_array", ":background_slot"),
       (cur_tableau_set_background_color, ":background_color"),

       (init_position, pos1),
       (cur_tableau_add_mesh_with_vertex_color, "mesh_heraldic_armor_bg", pos1, 200, 100, ":background_color"),
       (init_position, pos1),
       (position_set_z, pos1, 50),
       (position_set_x, pos1, 65),
       (position_set_y, pos1, -9),
       (cur_tableau_add_mesh, ":banner_mesh", pos1, 40, 0),
       (init_position, pos1),
       (position_set_z, pos1, 100),
       (cur_tableau_add_mesh, "mesh_tableau_mesh_platemail_banner", pos1, 0, 0),
       (cur_tableau_set_camera_parameters, 0, 200, 200, 0, 100000),
    ]
  ),
 

xenoargh

Grandmaster Knight
This is a really interesting idea!

How hard would it be to get this to work in a standardized fashion with some Python?  I.E., armor names with a naming-convention pattern for the extras, standardized? 

Also, this is just cosmetic atm, not a gameplay enhancement as well, I presume?  Also, is there code to send a template pattern to Agents and / or randomize it per Agent when spawned?  What about the cost of the gear?

I mean, since I'm pretty tempted to get rid of Gloves and Boots anyhow... to free up Item Slots, clean up some performance stuff, etc.- and this might be a good approach that gives players customized looks while achieving those goals. 

I hate to think about how much work it'll entail, though.  That's a heck of a lot of setup.
 

Somebody

Code Pope
Baron
WBWF&S
It would be a lot of set up, yes. I have written macros to help but they don't replace hard work. The ti_on_init_item does the bulk of the logic including error checking and randomization so it would be hard to generate that via python. You have access to troop/agents in ti_on_init_item so you can easily customize it on a per-faction basis for example like the heraldic items (which you got rid of :razz:)

It's all cosmetic because it's code slapped on the same item template, although you could definitely add extra armor, set it up in the agent slots, and add ti_on_agent_hit triggers calculating hits to certain bones to that effect. Costs would involve changing the buy/sell modifiers, but it wouldn't affect the base. You can, of course simply create new item variants with pre-defined settings using this system for kings instead of using troop slots (because NPCs usually only have 1 body armor) but that's no fun.

As to performance - it work with .LOD and the game engine's multimesh performance is adequate once they're on the scene, but the calculations for finding the appropriate meshes will add a bit of overhead when agents spawn. I recommend just making customization available to player and having semi-random setup for other NPCS (based on DNA, troop id, levels etc) and static loadouts for non-hero troops.
 

xenoargh

Grandmaster Knight
Hmm.  I may be barking up the wrong tree, here.  I haven't messed with the new mesh / material operations at all.

Maybe the fast / best way (for my purposes) is to simply use ti_on_init_item to "attach" assigned boot / glove / extra doodad meshes to the armors; then I can have, say, one main armor mesh, with attachments, and all refined to exactly match what I want, at a savings in RAM (less total BRFs loaded, basically).  I could also do this for Materials, where the armor's just a paint-swap; that's really attractive, honestly; it'd save dozens of MB, in theory, given how that data is statically allocated...

Multimesh is all right, performance-wise, but only if done pretty carefully (10 different things on 10 Materials is a Bad Idea, I found out at one point).

And I think I just thought up a way to re-incorporate heraldic stuff that would not have all of the inherent performance problems it did (basically, sending a custom Material to a mesh).
 

Somebody

Code Pope
Baron
WBWF&S
Yep, the main idea is to condense those BRF files and you could totally get rid of mismatching glove/boots. As long as they're rigged you're fine (may want to keep a glove unrigged for the inventory mesh). I've edited the main post to have an example of armor re-skinning (coat of plates). While it's faster than the tableaus projecting the mesh all the time you'll still need to load textures. You can try something like this system with shields, but separate the shields from the frames and map the surface to the whole texture instead of going through the tableau system.
 

xenoargh

Grandmaster Knight
Right; I was thinking I'd set up a special Material for the shields, where diffuse2 would be the heraldry (this won't work for Player heraldry unless I want a ton of Materials, however, that's not the big issue anyhow).  Or heck, just near-duplicate Materials and eat the cost of the textures.  It's not very important.

The only big catch I found is that attaching boots to armor works 100% fine and respects rigging and all that; what doesn't work perfectly is that then it doesn't hide the default, ugly foot mesh.  Whoops.

Easily solved; I can just make feet / hands part of the base body and use invisible 0-length meshes for them so the engine doesn't crash, like I did with the Sirens.

This would mean that armors are "sets" and get rid of a lot of the paper-doll, but I could multiply the number of armors available by the number of parts-combos I wanted to use (in theory) which would mean that the paper-doll wouldn't be quite so necessary in the first place.  And, oh darn, I wouldn't need to balance gloves and boots against body armors any more, or make players have to search for Leather Gloves all the time when their parties are all low-level Heroes and they really want that 5 extra points of body-armor  :roll:
 

xenoargh

Grandmaster Knight
I took the plunge, and converted the entire B&S armor system to use the cur_item_add_mesh stuff.

Results look good thus far, but I learned something rather weird is going on that I want to write here so people know about it later.  Apparently, Boot and Glove LODs are invoked earlier than Armor LODs... but (and this is the weird part) only if they're invoked via cur_item_add_mesh

I found this out because all my Armors have just LOD2 and LOD3, to cut down junk memory usage (I mean, seriously, who cares about LOD1 for 99% of the use cases, it is just an egregious waste of RAM, imo).

But the boots forced to load via this method were getting to LOD2 and then to LOD3 (which is an invisible mesh, so, like, obvious) really really early.  Then I put in LOD1's, and all is well again.  Basically, whoever wrote that code made the assumption that everybody would use LOD1; meshes added via that operation need to have it, or they'll load LOD2 when they should load LOD1, etc.  Weird, indeed, but I've seen stranger assumptions in this engine...

This was kind of irksome, but once I knew what was up... not a big deal (especially when I consider what an epic amount of text-entries lies ahead of me to make all the armors have corresponding boots / gloves that are sensibly-stylish, sigh).  It does the same thing with gloves added this way, too, so I presume it effects everything but that is less-obvious because well, hands can disappear and nobody can really see them.  So, smallish detail items might want LOD0 / LOD1 to be identical, then LOD2 to be invisible to save CPU; LOD2's really crucial for performance.
 

Ruthven

Baron
WBM&BVC
xenoargh said:
I took the plunge, and converted the entire B&S armor system to use the cur_item_add_mesh stuff.

Results look good thus far, but I learned something rather weird is going on that I want to write here so people know about it later.  Apparently, Boot and Glove LODs are invoked earlier than Armor LODs... but (and this is the weird part) only if they're invoked via cur_item_add_mesh

I found this out because all my Armors have just LOD2 and LOD3, to cut down junk memory usage (I mean, seriously, who cares about LOD1 for 99% of the use cases, it is just an egregious waste of RAM, imo).

But the boots forced to load via this method were getting to LOD2 and then to LOD3 (which is an invisible mesh, so, like, obvious) really really early.  Then I put in LOD1's, and all is well again.  Basically, whoever wrote that code made the assumption that everybody would use LOD1; meshes added via that operation need to have it, or they'll load LOD2 when they should load LOD1, etc.  Weird, indeed, but I've seen stranger assumptions in this engine...

This was kind of irksome, but once I knew what was up... not a big deal (especially when I consider what an epic amount of text-entries lies ahead of me to make all the armors have corresponding boots / gloves that are sensibly-stylish, sigh).  It does the same thing with gloves added this way, too, so I presume it effects everything but that is less-obvious because well, hands can disappear and nobody can really see them.  So, smallish detail items might want LOD0 / LOD1 to be identical, then LOD2 to be invisible to save CPU; LOD2's really crucial for performance.
Did the main armor have a LOD1?
 

Somebody

Code Pope
Baron
WBWF&S
If the main armor (whatever mesh you specify in the module_items entry) has .lod then all the submeshes should match the number of .lod available. What you can try is experiment with the optional parameters.
Code:
cur_item_add_mesh                      = 1964   # (cur_item_add_mesh, <mesh_name_string_no>, [<lod_begin>], [<lod_end>]), #only call inside ti_on_init_item in module_items # lod values are optional. lod_end is not included.
 

xenoargh

Grandmaster Knight
Yeah, that's the expected behavior, but it doesn't work quite that way.  Checked it thoroughly.  Which is why the whole thing's... weird. 

Basically, my Armors are "hosting" the boots and gloves now- I've freed up both Boots and Gloves slots for, well, everything (thank you, grep-parser...).  The Armor, Boot and Glove meshes all have .LOD2 and .LOD3 defined... but not .LOD1.  When I observed my first test of this, I had some unexpected results.  Like, "oops, my guys apparently float in midair", lol.  It was harder to see w/ gloves, but it was occurring there, too.

It appears that, instead of having the engine code do:

Code:
IF (submesh LOD mesh exists when LOD condition == true) THEN (swap submesh)

The engine code, instead, says:

Code:
IF(LOD condition == true) THEN (swap to next submesh, ignore submesh LOD spec)

...checking to see whether the LOD mesh exists for that LOD is trivial; it works for regular sub-meshes; kind of mystified why this doesn't appear to adhere to the same rules. 

Anyhow, sorry for taking up room in this discussion; the code here is a pretty nifty idea.  This is about the only "catch" I've found with using cur_item_add_mesh; I fully believe your warnings about trying to set Materials too deep into the sub-meshes; this whole feature feels like it was added quickly, for a specific use-case, and TW never expected this to come up.
 

xenoargh

Grandmaster Knight
Some further notes about Technical Wrinkles of using sub-meshes via this method:

1.  My theory above is correct.  I know that's absolutely true, now.  Should probably become a bug report, but who knows if TW's interested in fixing bugs like this at this late date.

2.  The engine has mysterious problems if there aren't matching #'s of LODs, but it doesn't matter what their designation is, because this will get ignored anyway. 

It doesn't allow for control.  But if they don't match, errors can pile up and you can experience crashes due to Buffers being reset (which is a death-spiral... what I wouldn't give for this engine to go 64-bits and for the buffer sizes to quit being statically allocated, sigh).

3.  If you only have 3 LODs, like I'm running, then that means you'll only see the meshes at LODs 0-2.  This worked out for me quite nicely... once I figured out what was up.

4.  The "traditional method" of doing this, where sub-meshes are attached to specific meshes in the BRF, doesn't have these functional issues.  Tested that, too.  But this method is way, way, way more flexible.
 

Somebody

Code Pope
Baron
WBWF&S
Condensed the European armors from Crusader: Way to Expiation OSP (You'll need the textures)

Click on the above for the .BRF
wpq9Q.png
wz9aD.png
DN_r4.png
Code:
def custom_reskin(item):
  return (ti_on_init_item, [(store_trigger_param_1, ":agent_no"),(store_trigger_param_2, ":troop_no"),
    (str_clear, s1),
    (item_get_slot, ":start", item, slot_item_materials_begin),
    (item_get_slot, ":end", item, slot_item_materials_end),
    (store_sub, ":total", ":end", ":start"),
    (gt, ":total", 0),
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":value", item, slot_item_player_color),
      (neq, ":value", -1),
      (val_mod, ":value", ":total"),
    (else_try),
      (store_random_in_range, ":value", ":start", ":end"),
    (try_end),
  (str_store_string, s1, ":value"),(cur_item_set_material, s1, 0),])
Code:
["cwe_monk", "Robe with Mail", [("armor_monk",0)], itp_merchandise| itp_type_body_armor|itp_covers_legs|itp_civilian,0,
 242, weight(3.5)|abundance(50)|head_armor(0)|body_armor(15)|leg_armor(7)|difficulty(0), imodbits_cloth,
 [
  (ti_on_init_item, [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (str_clear, s1),

    (store_random_in_range, ":value", 0, 6), #6 variants
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":value", "itm_cwe_monk", slot_item_player_color),
      (eq, ":value", -1),
      (store_random_in_range, ":value", 0, 6), #6 variants
    (try_end),
    (val_mod, ":value", 6),
    (val_add, ":value", "str_cwe_monk_a"),
    (str_store_string, s1, ":value"),
    (cur_item_set_material, s1, 0),
    #2 accessories
    (try_begin),
      (neg|item_slot_eq, "itm_cwe_monk", slot_item_player_slots_end - 1, 0),
      (call_script, "script_init_cwe_monk", ":agent_no", ":troop_no", 0, 0),
      (cur_item_add_mesh, s1),
    (try_end),
    (try_begin),
      (neg|item_slot_eq, "itm_cwe_monk", slot_item_player_slots_end - 2, 0),
      (call_script, "script_init_cwe_monk", ":agent_no", ":troop_no", 0, 1),
      (cur_item_add_mesh, s1),
    (try_end),
   ])
 ]], 
["cwe_novici", "Aketon", [("armor_novici",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs|itp_civilian,0,
 265 , weight(5)|abundance(100)|head_armor(0)|body_armor(21)|leg_armor(5)|difficulty(0), imodbits_cloth,
 [custom_reskin("itm_cwe_novici")]], 
["cwe_archer", "Archer Gambeson", [("armor_archer",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs|itp_civilian, 0,
 303 , weight(10)|abundance(100)|head_armor(1)|body_armor(22)|leg_armor(5)|difficulty(0), imodbits_cloth,
 [custom_reskin("itm_cwe_archer")]], 
["cwe_infantry", "Infantry Gambeson", [("armor_infantry",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs|itp_civilian,0,
 297 , weight(12)|abundance(100)|head_armor(0)|body_armor(24)|leg_armor(6)|difficulty(0), imodbits_cloth,
 [custom_reskin("itm_cwe_infantry")]], 
["cwe_sergeant", "Gambeson over Mail", [("armor_sergeant",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs,0,
 690 , weight(15)|abundance(100)|head_armor(0)|body_armor(36)|leg_armor(6)|difficulty(6) ,imodbits_armor,
 [custom_reskin("itm_cwe_sergeant")]], 

["cwe_deserter_a", "Outlaw Gambeson", [("armor_sergeant",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs,0,
 654 , weight(14)|abundance(50)|head_armor(0)|body_armor(35)|leg_armor(5)|difficulty(6), imodbits_armor,
 [custom_reskin("itm_cwe_deserter_a")]], 
["cwe_deserter_b", "Deserter Surcoat", [("knight_armor_e",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs ,0,
 1234 , weight(22)|abundance(50)|head_armor(0)|body_armor(40)|leg_armor(12)|difficulty(7), imodbits_armor,
 [custom_reskin("itm_cwe_deserter_b")]],

["cwe_knight_a", "Mail with Surcoat", [("knight_armor_e",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs,0,
 1544 , weight(23)|abundance(60)|head_armor(0)|body_armor(42)|leg_armor(14)|difficulty(7) ,imodbits_armor,
 [
  (ti_on_init_item, [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (str_clear, s1),
    (str_clear, s2),

    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":value", "itm_cwe_knight_a", slot_item_player_color),
      (neq, ":value", -1),
    (else_try),
      (store_random_in_range, ":value", 0, 10), #armor_e has 10 skins
    (try_end),
    (val_mod, ":value", 10),
    (val_add, ":value", "str_cwe_knight_e1"),
    (str_store_string, s1, ":value"),
    (cur_item_set_material, s1, 0),
    #2 accessories, they need to be mapped for materials
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":cloak", "itm_cwe_knight_a", slot_item_player_slots_begin),
      (neq, ":cloak", 0), #no cloak
      (try_begin), #randomize, skip 0-value
        (eq, ":cloak", -1),
        (store_random_in_range, ":cloak", 1, 5),
      (try_end),
      (call_script, "script_init_cwe_knight_ab", ":agent_no", ":troop_no", armor_cloth, ":cloak"),
      (cur_item_add_mesh, s1),
      (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_a", ":value", armor_cloth),
      (cur_item_set_material, s2, 1),
      (try_begin),
        (neg|item_slot_eq, "itm_cwe_knight_a", slot_item_player_slots_end - 1, 0),
        (call_script, "script_init_cwe_knight_ab", ":agent_no", ":troop_no", armor_armor, 0),
        (cur_item_add_mesh, s1),
        (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_a", ":value", armor_armor),
        (cur_item_set_material, s2, 2),
      (try_end),
    (try_end),
   ])
 ]],
["cwe_knight_b", "Surcoat over Mail", [("knight_armor_a",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs,0,
 1720 , weight(22)|abundance(40)|head_armor(0)|body_armor(43)|leg_armor(14)|difficulty(8) ,imodbits_armor,
 [
  (ti_on_init_item, [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (str_clear, s1),
    (str_clear, s2),

    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":value", "itm_cwe_knight_b", slot_item_player_color),
      (neq, ":value", -1),
    (else_try),
      (store_random_in_range, ":value", 0, 15), #armor_a has 16 variants
    (try_end),
    (val_mod, ":value", 16),
    (val_add, ":value", "str_cwe_knight_a1"),
    (str_store_string, s1, ":value"),
    (cur_item_set_material, s1, 0),
    #2 accessories, they need to be mapped for materials
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":cloak", "itm_cwe_knight_b", slot_item_player_slots_begin),
      (neq, ":cloak", 0), #no cloak
      (try_begin), #randomize, skip 0-value
        (eq, ":cloak", -1),
        (store_random_in_range, ":cloak", 1, 5),
      (try_end),
      (call_script, "script_init_cwe_knight_ab", ":agent_no", ":troop_no", armor_cloth, ":cloak"),
      (cur_item_add_mesh, s1),
      (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_b", ":value", armor_cloth),
      (cur_item_set_material, s2, 1),
      (try_begin),
        (neg|item_slot_eq, "itm_cwe_knight_b", slot_item_player_slots_end - 1, 0),
        (call_script, "script_init_cwe_knight_ab", ":agent_no", ":troop_no", armor_armor, 0),
        (cur_item_add_mesh, s1),
        (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_b", ":value", armor_armor),
        (cur_item_set_material, s2, 2),
      (try_end),
    (try_end),
   ])
 ]], 
["cwe_knight_c", "Knightly Mail with Tabard", [("armor_master_order",0)], itp_merchandise|itp_type_body_armor|itp_covers_legs,0,
 3654 , weight(24)|abundance(20)|head_armor(0)|body_armor(51)|leg_armor(15)|difficulty(9) ,imodbits_armor,
 [
  (ti_on_init_item, [
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":troop_no"),
    (str_clear, s1),
    (str_clear, s2),

    (try_begin),
      (troop_is_hero, ":troop_no"),
      (item_get_slot, ":value", "itm_cwe_knight_c", slot_item_player_color),
      (neq, ":value", -1),
    (else_try),
      (store_random_in_range, ":value", 0, 4), #jerusalem + 3 holy orders
    (try_end),
    (val_mod, ":value", 4),
    (val_add, ":value", "str_cwe_knight_master_a"),
    (str_store_string, s1, ":value"),
    (cur_item_set_material, s1, 0),
    #2 accessories, they need to be mapped for materials
    (try_begin),
      (troop_is_hero, ":troop_no"),
      (neg|item_slot_eq, "itm_cwe_knight_c", slot_item_player_slots_end - 1, 0),
      (call_script, "script_init_cwe_knight_c", ":agent_no", ":troop_no", armor_cloth, 0),
      (cur_item_add_mesh, s1),
      (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_c", ":value", armor_cloth),
      (cur_item_set_material, s2, 1),
      (try_begin),
        (neg|item_slot_eq, "itm_cwe_knight_c", slot_item_player_slots_end - 2, 0),
        (call_script, "script_init_cwe_knight_c", ":agent_no", ":troop_no", armor_armor, 0),
        (cur_item_add_mesh, s1),
        (call_script, "script_map_cwe_knight_accessories", "itm_cwe_knight_c", ":value", armor_armor),
        (cur_item_set_material, s2, 2),
      (try_end),
    (try_end),

   ])
 ]],
Code:
    (try_for_range, ":item_no", "itm_cwe_monk", "itm_bandit_hunter_a"),
      (try_for_range, ":slot_no", slot_item_player_slots_begin, slot_item_player_slots_end + 1),
        (item_set_slot, ":item_no", ":slot_no", -1),
      (try_end),
      (item_set_slot, ":item_no", slot_item_num_components, 1), #allows it to be customized
    (try_end),
    (item_set_slot, "itm_cwe_monk", slot_item_materials_begin, "str_cwe_monk_a"),
    (item_set_slot, "itm_cwe_monk", slot_item_materials_end, "str_cwe_novice_a"),
    (item_set_slot, "itm_cwe_monk", slot_item_init_script, "script_init_cwe_monk"),
    (item_set_slot, "itm_cwe_monk", slot_item_num_components, 3),
    
    (item_set_slot, "itm_cwe_novici", slot_item_materials_begin, "str_cwe_novice_a"),
    (item_set_slot, "itm_cwe_novici", slot_item_materials_end, "str_cwe_archer_a1"),
    (item_set_slot, "itm_cwe_archer", slot_item_materials_begin, "str_cwe_archer_a1"),
    (item_set_slot, "itm_cwe_archer", slot_item_materials_end, "str_cwe_infantry_a1"),
    (item_set_slot, "itm_cwe_infantry", slot_item_materials_begin, "str_cwe_infantry_a1"),
    (item_set_slot, "itm_cwe_infantry", slot_item_materials_end, "str_cwe_sergeant_a1"),
    (item_set_slot, "itm_cwe_sergeant", slot_item_materials_begin, "str_cwe_sergeant_a1"),
    (item_set_slot, "itm_cwe_sergeant", slot_item_materials_end, "str_cwe_cloak_meshes_begin"),
    
    (item_set_slot, "itm_cwe_knight_b", slot_item_init_script, "script_init_cwe_knight_ab"),
    (item_set_slot, "itm_cwe_knight_b", slot_item_materials_begin, "str_cwe_knight_a1"),
    (item_set_slot, "itm_cwe_knight_b", slot_item_materials_end, "str_cwe_knight_e1"),
    (item_set_slot, "itm_cwe_knight_b", slot_item_num_components, 3),
    (item_set_slot, "itm_cwe_knight_a", slot_item_init_script, "script_init_cwe_knight_ab"),
    (item_set_slot, "itm_cwe_knight_a", slot_item_materials_begin, "str_cwe_knight_e1"),
    (item_set_slot, "itm_cwe_knight_a", slot_item_materials_end, "str_cwe_knight_cloak_a"),
    (item_set_slot, "itm_cwe_knight_a", slot_item_num_components, 3),
    (item_set_slot, "itm_cwe_knight_c", slot_item_init_script, "script_init_cwe_knight_c"),
    (item_set_slot, "itm_cwe_knight_c", slot_item_materials_begin, "str_cwe_knight_master_a"),
    (item_set_slot, "itm_cwe_knight_c", slot_item_materials_end, "str_cwe_cloak_master_a"),
    (item_set_slot, "itm_cwe_knight_c", slot_item_num_components, 3),
    
    (item_set_slot, "itm_cwe_deserter_a", slot_item_materials_begin, "str_cwe_deserter_s1"),
    (item_set_slot, "itm_cwe_deserter_a", slot_item_materials_end, "str_cwe_monk_a"),
    (item_set_slot, "itm_cwe_deserter_a", slot_item_num_components, 1),
    (item_set_slot, "itm_cwe_deserter_b", slot_item_materials_begin, "str_cwe_deserter_k1"),
    (item_set_slot, "itm_cwe_deserter_b", slot_item_materials_end, "str_cwe_deserter_s1"),
    (item_set_slot, "itm_cwe_deserter_b", slot_item_num_components, 1),
Code:
 #deserter stuff
 ("cwe_deserter_k1", "dethertir_knight_a"),
 ("cwe_deserter_k2", "dethertir_knight_b"),
 ("cwe_deserter_k3", "dethertir_knight_e"),
 ("cwe_deserter_k4", "dethertir_knight_d"),
 ("cwe_deserter_s1", "dethertir_sergeant_c"),
 ("cwe_deserter_s2", "dethertir_sergeant_f"),
 ("cwe_deserter_s3", "dethertir_sergeant_g"),
 ("cwe_deserter_s4", "dethertir_sergeant_h"),
 #cwe crusader materials : monk, novici, archer, infantry, sergeant, knight_a, knight_e, master, cloaks
 ("cwe_monk_a", "armor_monie_hospitaller_a"), 
 ("cwe_monk_b", "armor_monie_hospitaller_b"), 
 ("cwe_monk_c", "armor_monie_templar_a"), 
 ("cwe_monk_d", "armor_monie_templar_b"), 
 ("cwe_monk_e", "armor_monie_tevton_a"), 
 ("cwe_monk_f", "armor_monie_tevton_b"),
 
 ("cwe_novice_a", "novici_antioh_armor"), 
 ("cwe_novice_b", "novici_hospitaller"), 
 ("cwe_novice_c", "novici_ibelin"), 
 ("cwe_novice_d", "novici_jerusalem"), 
 ("cwe_novice_e", "novici_templar"), 
 ("cwe_novice_f", "novici_tevton"),
 ("cwe_novice_g", "novici_tripoli_armor"),
 
 ("cwe_archer_a1", "archer_antioh_armor_a"), 
 ("cwe_archer_a2", "archer_antioh_armor_b"), 
 ("cwe_archer_b1", "archer_hospitaller_armor_a"), 
 ("cwe_archer_b2", "archer_hospitaller_armor_b"), 
 ("cwe_archer_c1", "archer_ibelin_armor_a"), 
 ("cwe_archer_c2", "archer_ibelin_armor_b"), 
 ("cwe_archer_d1", "archer_jerusalem_armor_a"), 
 ("cwe_archer_d2", "archer_jerusalem_armor_b"), 
 ("cwe_archer_e1", "archer_templar_armor_a"), 
 ("cwe_archer_e2", "archer_templar_armor_a"), 
 ("cwe_archer_f1", "archer_tevton_armor_a"), 
 ("cwe_archer_f2", "archer_tevton_armor_a"), 
 ("cwe_archer_g1", "archer_tripoli_armor_a"), 
 ("cwe_archer_g2", "archer_tripoli_armor_a"), 
 
 ("cwe_infantry_a1", "armor_infantry_antioh_a"), 
 ("cwe_infantry_a2", "armor_infantry_antioh_b"), 
 ("cwe_infantry_b1", "armor_infantry_hospitaller_a"), 
 ("cwe_infantry_b2", "armor_infantry_hospitaller_b"), 
 ("cwe_infantry_c1", "armor_infantry_ibelin_a"), 
 ("cwe_infantry_c2", "armor_infantry_ibelin_b"), 
 ("cwe_infantry_d1", "armor_infantry_jerusalem_a"), 
 ("cwe_infantry_d2", "armor_infantry_jerusalem_b"), 
 ("cwe_infantry_e1", "armor_infantry_templar_a"), 
 ("cwe_infantry_e2", "armor_infantry_templar_a"), 
 ("cwe_infantry_f1", "armor_infantry_tevton_a"), 
 ("cwe_infantry_f2", "armor_infantry_tevton_a"), 
 ("cwe_infantry_g1", "armor_infantry_tripoli_a"), 
 ("cwe_infantry_g2", "armor_infantry_tripoli_a"), 
 
 ("cwe_sergeant_a1", "sergeant_antioh_armor_a"), 
 ("cwe_sergeant_a2", "sergeant_antioh_armor_b"), 
 ("cwe_sergeant_b1", "sergeant_hospitaller_armor_a"), 
 ("cwe_sergeant_b2", "sergeant_hospitaller_armor_b"), 
 ("cwe_sergeant_c",  "sergeant_ibelin_armor"), 
 ("cwe_sergeant_d",  "sergeant_jerusalem_armor"), 
 ("cwe_sergeant_e1", "sergeant_templar_armor_a"), 
 ("cwe_sergeant_e2", "sergeant_templar_armor_b"), 
 ("cwe_sergeant_f1", "sergeant_tevton_armor_a"), 
 ("cwe_sergeant_f2", "sergeant_tevton_armor_b"), 
 ("cwe_sergeant_g1", "sergeant_tripoli_armor_a"), 
 ("cwe_sergeant_g2", "sergeant_tripoli_armor_b"), 
 
#these 6 are mesh names, not materials
("cwe_cloak_meshes_begin", "No Cloak"),
("cwe_cloak_a", "knight_a_cloak"),
("cwe_cloak_b", "knight_b_cloak"),
("cwe_cloak_c", "knight_c_cloak"),
("cwe_cloak_d", "knight_d_cloak"),
("cwe_cloak_e", "armor_master_cloak"),
#knight_armor_a
 ("cwe_knight_a1", "knight_armor_antioh_c"), 
 ("cwe_knight_a2", "knight_armor_antioh_d"), 
 ("cwe_knight_a3", "knight_armor_hospitaller_a"), 
 ("cwe_knight_a4", "knight_armor_hospitaller_b"), 
 ("cwe_knight_a5", "knight_armor_hospitaller_c"), 
 ("cwe_knight_a6", "knight_armor_hospitaller_d"), 
 ("cwe_knight_a7", "knight_armor_ibelin_b"), 
 ("cwe_knight_a8", "knight_armor_jerusalem_b"), 
 ("cwe_knight_a9", "knight_armor_templar_a"), 
 ("cwe_knight_a10","knight_armor_templar_b"), 
 ("cwe_knight_a11","knight_armor_templar_c"), 
 ("cwe_knight_a12","knight_armor_templar_d"), 
 ("cwe_knight_a13","knight_armor_tevton_a"), 
 ("cwe_knight_a14","knight_armor_tevton_b"), 
 ("cwe_knight_a15","knight_armor_tripolli_b"), 
 
#knight_armor_e
 ("cwe_knight_e1", "knight_armor_antioh_e"),
 ("cwe_knight_e2", "knight_armor_hospitaller_e"),
 ("cwe_knight_e3", "knight_armor_hospitaller_f"),
 ("cwe_knight_e4", "knight_armor_ibelin_c"),
 ("cwe_knight_e5", "knight_armor_jerusalem_c"),
 ("cwe_knight_e6", "knight_armor_templar_e"),
 ("cwe_knight_e7", "knight_armor_templar_f"),
 ("cwe_knight_e8", "knight_armor_tevton_c"),
 ("cwe_knight_e9", "knight_armor_tevton_d"),
 ("cwe_knight_e10","knight_armor_tripolli_c"),
 
 #cloak materials
("cwe_knight_cloak_a", "cloak_antioh"),
("cwe_knight_cloak_b", "cloak_hospitaller"),
("cwe_knight_cloak_c", "cloak_ibelin"),
("cwe_knight_cloak_d", "cloak_jerusalem"),
# ("cwe_knight_cloak_e", "cloak_jerusalem_securiti"), #unused
("cwe_knight_cloak_e", "cloak_templar"),
("cwe_knight_cloak_f", "cloak_tevton"),
("cwe_knight_cloak_g", "cloak_tripoli_ibelin"),

#armor_master_order + kings
("cwe_knight_master_a", "{!}armor_king_jerusalem"),
("cwe_knight_master_b", "{!}armor_master_order_hospitaller"),
("cwe_knight_master_c", "{!}armor_master_order_templar"),
("cwe_knight_master_d", "{!}armor_master_order_tevton"),

#cloak materials
("cwe_cloak_master_a", "cloak_king_jerusalem"),
("cwe_cloak_master_b", "cloak_master_order_hospitaller"),
("cwe_cloak_master_c", "cloak_master_order_templar"),
("cwe_cloak_master_d", "cloak_master_order_tevton"),
#cloak clasps
("cwe_clasp_master_a", "orden_king_jerusalem"),
("cwe_clasp_master_b", "orden_master_order_hospitaller"),
("cwe_clasp_master_c", "orden_master_order_templar"),
("cwe_clasp_master_d", "orden_master_order_tevton"),

HarryPham123 said:
is this for single or multi  :???:
Right now it's for SP but you can probably make it work for MP using player's slots. The problem is whether other players would be able to see it if the item code is only executed server-side.
 
Top Bottom