OSP Code QoL Sorting Troops for M&B Warband

Users who are viewing this thread

Arris Rumi

Recruit
Hi everybody,

As the title says, this OSP implements some basic sorting for Warband. Now you can sort by troop level, faction or class (infantry, archer, any custom class, etc.), and even combine a few of them. This is very useful for when you have all kinds of troops and just want some order, to help you decide what troops will enter battle first, and even in some mods that have many factions and tens of troops types. This is an OSP, so you can use it freely as long as credit is given. The complete files are in this github.


The OSP includes a new presentation, a new entry in the "take action" submenu of the Camping menu, some new scripts for sorting, and a couple of temp troops that work as extra arrays.

The presentation:

Python:
#Arris
("sort_troops", 0, mesh_load_window,[
        (ti_on_presentation_load,
        [ 
            (presentation_set_duration,999999),
            (set_fixed_point_multiplier, 1000),
          
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_c", ":i", 0), #factions in party
            (try_end),     
          
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_d", ":i", -1), #classes in party
            (try_end), 

            (assign, "$g_st_param_asc", 0),
            (assign, "$g_st_param_fixcomp", 0),
          
            (party_get_num_companion_stacks , ":num_stacks", "p_main_party"),
          
            #list factions in party
            (assign, ":indx_faction", -1),
            (try_for_range, ":i", 1,  ":num_stacks"),
              
                (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
                (store_troop_faction, reg0, ":troop"),
                      
                (assign, ":flag_found", 0),
                (try_for_range, ":i", 0, 100),
                    (troop_get_slot, ":temp1", "trp_temp_array_c", ":i"),
                    (try_begin),
                        (eq, ":temp1", reg0),
                        (assign, ":flag_found", 1),
                    (try_end),
                (try_end),
                (try_begin),
                    (neq, ":flag_found", 1),
                    (val_add, ":indx_faction", 1),
                    (troop_set_slot, "trp_temp_array_c", ":indx_faction", reg0),
                (try_end),
            (try_end),
          
            (store_add, "$tot_factions", ":indx_faction", 1),
          
            #list classes in party     
            (assign, ":indx_class", -1),
            (try_for_range, ":i", 1,  ":num_stacks"),
              
                (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
                (troop_get_class, reg0, ":troop"),
                      
                (assign, ":flag_found", 0),
                (try_for_range, ":i", 0, 100),
                    (troop_get_slot, ":temp1", "trp_temp_array_d", ":i"),
                    (try_begin),
                        (eq, ":temp1", reg0),
                        (assign, ":flag_found", 1),
                    (try_end),
                (try_end),
                (try_begin),
                    (neq, ":flag_found", 1),
                    (val_add, ":indx_class", 1),
                    (troop_set_slot, "trp_temp_array_d", ":indx_class", reg0),
                (try_end),
            (try_end),
          
            (store_add, "$tot_classes", ":indx_class", 1),

            #indx elems to exchange
            (assign, "$g_elem1", -1), (assign, "$g_elem2", -1), (assign, "$g_elem3", -1), (assign, "$g_elem4", -1),
          
            #Title 
            (create_text_overlay, "$g_presentation_obj_16","@Sort your Troops",tf_center_justify),
            (position_set_x, pos1, 500), (position_set_y, pos1, 650),
            (overlay_set_position, "$g_presentation_obj_16", pos1),
            (position_set_x, pos2,1200), (position_set_y, pos2,1200),
            (overlay_set_size,"$g_presentation_obj_16",pos2),
          
            # Button Return
            (create_game_button_overlay,"$g_st_cancel","@_Return_",tf_center_justify),
            (position_set_x, pos1, 500),(position_set_y, pos1, 50),
            (overlay_set_position, "$g_st_cancel", pos1),
          
            # Button Sort by Level
            (create_game_button_overlay,"$g_st_sort_lvl","@By Level",tf_center_justify),
            (position_set_x, pos1, 500),(position_set_y, pos1, 570),
            (overlay_set_position, "$g_st_sort_lvl", pos1),
          
            # Button Sort by Faction
            (create_game_button_overlay,"$g_st_sort_fac","@By Faction",tf_center_justify),
            (position_set_x, pos1, 500),(position_set_y, pos1, 520),
            (overlay_set_position, "$g_st_sort_fac", pos1),
          
            # Button Sort by Classes
            (create_game_button_overlay,"$g_st_sort_class","@By Class",tf_center_justify),
            (position_set_x, pos1, 500),(position_set_y, pos1, 470),
            (overlay_set_position, "$g_st_sort_class", pos1),         
          
            #Checkbox Asc/Desc
            (create_check_box_overlay, "$g_st_asc", "mesh_checkbox_off", "mesh_checkbox_on"),
            (position_set_x, pos1, 600),(position_set_y, pos1, 585),
            (overlay_set_position, "$g_st_asc", pos1),
          
            #Label Ascending
            (create_text_overlay, reg0, "@Ascending"),
            (position_set_x, pos1, 630),(position_set_y, pos1, 580),
            (overlay_set_position, reg0, pos1),     
                      
            #Checkbox Fix Companions
            (create_check_box_overlay, "$g_st_fix", "mesh_checkbox_off", "mesh_checkbox_on"),
            (position_set_x, pos1, 430),(position_set_y, pos1, 430),
            (overlay_set_position, "$g_st_fix", pos1),
          
            #Label Fix Companions
            (create_text_overlay, reg0, "@Fixed Companions"),
            (position_set_x, pos1, 460),(position_set_y, pos1, 425),
            (overlay_set_position, reg0, pos1), 
          
            #Label faction order
            (create_text_overlay, reg0, "@Faction Order"),
            (position_set_x, pos1, 180),(position_set_y, pos1, 380),
            (overlay_set_position, reg0, pos1), 

            #Faction List

            (str_clear, s0),
            (create_text_overlay, ":list_factions", s0, tf_scrollable),
            (position_set_x, pos1, 140),    (position_set_y, pos1, 120),
            (overlay_set_position, ":list_factions", pos1),
          
            (position_set_x, pos1, 300), (position_set_y, pos1, 3000), #later adjust y to fit #buttons exactly
            (overlay_set_size, ":list_factions", pos1),
          
            (position_set_x, pos1, 230), (position_set_y, pos1, 250),
            (overlay_set_area_size, ":list_factions", pos1),
            (set_container_overlay, ":list_factions"),
          
            (assign, ":x_pos", 80),    (assign, ":y_pos", 2900),

            (try_for_range, ":i", 0, "$tot_factions"),
                (troop_get_slot, ":id_faction", "trp_temp_array_c", ":i"),
                (str_store_faction_name, s0, ":id_faction"),
                (create_game_button_overlay, reg1 , "@{s0}", tf_center_justify),
              
                (try_begin),
                    (eq, ":i", 0),
                    (assign, "$first_faction_btn", reg1),
                (try_end),
              
                (position_set_x, pos3, ":x_pos"), (position_set_y, pos3, ":y_pos"),
                (overlay_set_position, reg1, pos3),
                (position_set_x, pos3, 200), (position_set_y, pos3, 30),
                (overlay_set_size, reg1, pos3),
                (val_sub, ":y_pos", 30),
            (try_end),
          
            (assign, "$last_faction_btn", reg1),
            (set_container_overlay, -1),
          
          
            #Label Class Order
            (create_text_overlay, reg0, "@Class Order"),
            (position_set_x, pos1, 620),(position_set_y, pos1, 380),
            (overlay_set_position, reg0, pos1), 
          
            #Classes List
          
            (str_clear, s0),
            (create_text_overlay, ":list_classes", s0, tf_scrollable),
            (position_set_x, pos1, 580),    (position_set_y, pos1, 120),
            (overlay_set_position, ":list_classes", pos1),
          
            (position_set_x, pos1, 300), (position_set_y, pos1, 3000), #later adjust y to fit #buttons exactly
            (overlay_set_size, ":list_classes", pos1),
          
            (position_set_x, pos1, 230), (position_set_y, pos1, 250),
            (overlay_set_area_size, ":list_classes", pos1),
            (set_container_overlay, ":list_classes"),
          
            (assign, ":x_pos", 80),    (assign, ":y_pos", 2900),

            (try_for_range, ":i", 0, "$tot_classes"),
                (troop_get_slot, ":id_class", "trp_temp_array_d", ":i"),
                (str_store_class_name, s0, ":id_class"),
                (create_game_button_overlay, reg1 , "@{s0}", tf_center_justify),
              
                (try_begin),
                    (eq, ":i", 0),
                    (assign, "$first_class_btn", reg1),
                (try_end),
              
                (position_set_x, pos3, ":x_pos"), (position_set_y, pos3, ":y_pos"),
                (overlay_set_position, reg1, pos3),
                (position_set_x, pos3, 200), (position_set_y, pos3, 30),
                (overlay_set_size, reg1, pos3),
                (val_sub, ":y_pos", 30),
            (try_end),
          
            (assign, "$last_class_btn", reg1),
            (set_container_overlay, -1),         
          
        ]),
      
        (ti_on_presentation_event_state_change,
        [
            (store_trigger_param_1, ":object"),
            (store_trigger_param_2, ":value"),

            (try_begin),
                (eq,"$g_st_cancel",":object"),   
                (presentation_set_duration,0),   
            (try_end),
          
            (try_begin),
                (eq,"$g_st_asc",":object"),
                (assign, "$g_st_param_asc", ":value"), 
            (try_end),
          
            (try_begin),
                (eq,"$g_st_fix",":object"),
                (assign, "$g_st_param_fixcomp", ":value"), 
            (try_end),
          
            (try_begin),         
                (eq,"$g_st_sort_lvl",":object"),
              
                (call_script, "script_position_companions"),
                (call_script, "script_sort_troops_by_level", "$g_st_param_asc"),
              
                (try_begin),
                    (eq, "$g_st_param_fixcomp" , 1),
                    (call_script, "script_reinsert_companions"),
                (try_end),
              
                (display_message, "@Sorted by level."),
            (try_end),

            (try_begin),
                (eq, "$g_st_sort_fac", ":object"),
              
                (call_script, "script_position_companions"),
                (call_script, "script_sort_troops_by_faction"),
              
                (try_begin),
                    (eq, "$g_st_param_fixcomp" , 1),
                    (call_script, "script_reinsert_companions"),
                (try_end),
              
                (display_message, "@Sorted by faction."),
            (try_end),
          
          
            (try_begin),
                (eq, "$g_st_sort_class", ":object"),
              
                (call_script, "script_position_companions"),
                (call_script, "script_sort_troops_by_class"),
              
                (try_begin),
                    (eq, "$g_st_param_fixcomp" , 1),
                    (call_script, "script_reinsert_companions"),
                (try_end),
              
                (display_message, "@Sorted by class."),             
            (try_end),
          
            #Clicks on faction list
            (try_begin),
          
                (ge, ":object", "$first_faction_btn"),
                (le, ":object", "$last_faction_btn" ),
              
                (try_begin), #1st click
                    (eq, "$g_elem1", -1),
                    (assign, "$g_elem1", ":object"),
                    (assign, "$g_elem3", -1), (assign, "$g_elem4", -1), #clicks in other list annulled
                  
                    (store_sub, ":i", "$g_elem1", "$first_faction_btn"),
                    (troop_get_slot, ":id_faction", "trp_temp_array_c", ":i"),
                    (str_store_faction_name, s0, ":id_faction"),
                    (display_message, "@ Swapping {s0} ... "), 
                  
                (else_try), #2nd click
                    (assign, "$g_elem2", ":object"),
                  
                    (store_sub, ":i", "$g_elem2", "$first_faction_btn"),
                    (troop_get_slot, ":id_faction", "trp_temp_array_c", ":i"),
                    (str_store_faction_name, s0, ":id_faction"),
                    (display_message, "@...with {s0}."),
                  
                    #swapping...
                    (store_sub, ":i1", "$g_elem1", "$first_faction_btn"),
                    (store_sub, ":i2", "$g_elem2", "$first_faction_btn"),
                  
                    (troop_get_slot, ":temp1", "trp_temp_array_c", ":i1"),
                    (troop_get_slot, ":temp2", "trp_temp_array_c", ":i2"),
                    (troop_set_slot, "trp_temp_array_c", ":i2", ":temp1"),
                    (troop_set_slot, "trp_temp_array_c", ":i1", ":temp2"),
                  
                    (try_for_range, ":i", 0, "$tot_factions"),
                        (troop_get_slot, ":id_faction", "trp_temp_array_c", ":i"),
                        (str_store_faction_name, s0, ":id_faction"),
                        (store_add, reg0, "$first_faction_btn", ":i"),
                        (overlay_set_text, reg0, "@{s0}"),
                    (try_end),
                  
                    (assign, "$g_elem1", -1),
                  
                (try_end),

            (try_end),
          
            #Clicks on class list
            (try_begin),
                (ge, ":object", "$first_class_btn" ),
                (le, ":object", "$last_class_btn" ),
          
                (try_begin), #1st click
                    (eq, "$g_elem3", -1),
                    (assign, "$g_elem3", ":object"),
                    (assign, "$g_elem1", -1), (assign, "$g_elem2", -1), #clicks in other list annulled
              
                    (store_sub, ":i", "$g_elem3", "$first_class_btn"),
                    (troop_get_slot, ":id_class", "trp_temp_array_d", ":i"),
                    (str_store_class_name, s0, ":id_class"),
                    (display_message, "@ Swapping {s0} ... "),
          
                (else_try), #2nd click
                  
                    (assign, "$g_elem4", ":object"),
                  
                    (store_sub, ":i", "$g_elem4", "$first_class_btn"),
                    (troop_get_slot, ":id_class", "trp_temp_array_d", ":i"),
                    (str_store_class_name, s0, ":id_class"),
                    (display_message, "@...with {s0}."),
                  
                    #swapping...
                  
                    (store_sub, ":i1", "$g_elem3", "$first_class_btn"),
                    (store_sub, ":i2", "$g_elem4", "$first_class_btn"),
                  
                    (troop_get_slot, ":temp1", "trp_temp_array_d", ":i1"),
                    (troop_get_slot, ":temp2", "trp_temp_array_d", ":i2"),
                    (troop_set_slot, "trp_temp_array_d", ":i2", ":temp1"),
                    (troop_set_slot, "trp_temp_array_d", ":i1", ":temp2"),
                  
                    (try_for_range, ":i", 0, "$tot_classes"),
                        (troop_get_slot, ":id_class", "trp_temp_array_d", ":i"),
                        (str_store_class_name, s0, ":id_class"),
                        (store_add, reg0, "$first_class_btn", ":i"),
                        (overlay_set_text, reg0, "@{s0}"),
                    (try_end),                 

                    (assign, "$g_elem3", -1),               
                  
                (try_end),
          
            (try_end),

        ]),
    ]),

The new scripts:

Python:
     #Arris
     #Sort troops in main party by level.
     #param -  0:descending, 1:ascending
   
    ("sort_troops_by_level",
        [
            (store_script_param, ":ascending", 1),
           
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_a", ":i", 0), #troop id
            (try_end),  
           
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_b", ":i", 0), # number troops
            (try_end),

            (party_get_num_companion_stacks , ":num_stacks_original", "p_main_party"),
           
            (try_for_range, ":i", 1, ":num_stacks_original"),
           
                (party_get_num_companion_stacks , ":num_stacks_current", "p_main_party"),
                (assign, ":indx_candidate", 1),
               
                (try_begin),
                    (eq, ":ascending", 0),
                    (assign, ":lvl_candidate", 0),
                (else_try),
                    (assign, ":lvl_candidate", 1000),
                (try_end),

                (try_for_range, ":j", 1, ":num_stacks_current"),
               
                    (party_stack_get_troop_id, ":troop_a",  "p_main_party",  ":j"),
                    (store_character_level, ":lvl_a", ":troop_a"),

                    (try_begin),
                        (eq, ":ascending", 0),
                        (gt, ":lvl_a",  ":lvl_candidate"),
                        (assign, ":lvl_candidate", ":lvl_a"),
                        (assign, ":indx_candidate", ":j"),
                    (else_try),
                        (eq, ":ascending", 1),
                        (lt, ":lvl_a",  ":lvl_candidate"),
                        (assign, ":lvl_candidate", ":lvl_a"),
                        (assign, ":indx_candidate", ":j"),
                    (try_end),
                   
                (try_end),
               
                (party_stack_get_troop_id, ":troop_s",  "p_main_party",  ":indx_candidate"),
                (party_stack_get_size, ":size_s", "p_main_party", ":indx_candidate"),
                (troop_set_slot, "trp_temp_array_a", ":i", ":troop_s"),
                (troop_set_slot, "trp_temp_array_b", ":i", ":size_s"),
                (party_remove_members, "p_main_party", ":troop_s", ":size_s"),

            (try_end),

            (try_for_range, ":i", 0, ":num_stacks_original"),
           
                (troop_get_slot, reg0, "trp_temp_array_a", ":i"),
                (troop_get_slot, reg1, "trp_temp_array_b", ":i"),
                (party_add_members, "p_main_party", reg0, reg1),
           
            (try_end),
       
        ]
    ),
   
   
    #Arris
    # Sort troops in main party by faction.
    # Faction order is in trp_temp_array_c
    # Limit reading of trp_temp_array_c "array" with $tot_factions
   
    ("sort_troops_by_faction",
        [
       
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_a", ":i", 0), #troop id
            (try_end),  
           
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_b", ":i", 0), # number troops
            (try_end),

            (assign, ":indx_temp", -1),
            (party_get_num_companion_stacks , ":num_stacks", "p_main_party"),
           
            (try_for_range,":indx", 0, "$tot_factions"), #for each faction, select
           
                (troop_get_slot, ":id_faction", "trp_temp_array_c", ":indx"),
               
                (try_for_range, ":i", 1, ":num_stacks"),
                   
                    (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
                    (store_troop_faction, reg0, ":troop"),
                   
                    #if match, copy troop id, size to temps.
                    (try_begin),
                        (eq, reg0, ":id_faction"),
                        (val_add, ":indx_temp", 1),
                        (party_stack_get_troop_id, ":troop_f",  "p_main_party",  ":i"),
                        (party_stack_get_size, ":size", "p_main_party", ":i"),
                        (troop_set_slot, "trp_temp_array_a", ":indx_temp", ":troop_f"),
                        (troop_set_slot, "trp_temp_array_b", ":indx_temp", ":size"),
                    (try_end),
               
                (try_end),

            (try_end),
           
            #delete all minus player
            (try_for_range, ":i", 0, ":num_stacks"),
                (troop_get_slot, reg0, "trp_temp_array_a", ":i"),
                (troop_get_slot, reg1, "trp_temp_array_b", ":i"),
                (party_remove_members, "p_main_party", reg0, reg1),
            (try_end),
           
            #add troops following order from temp a and b.
            (try_for_range, ":i", 0, ":num_stacks"),
                (troop_get_slot, reg0, "trp_temp_array_a", ":i"),
                (troop_get_slot, reg1, "trp_temp_array_b", ":i"),
                (party_add_members, "p_main_party", reg0, reg1),
            (try_end),
       
    ]),
   
   
    #Arris
    # Sort troops in main party by class.
    # Class order is in trp_temp_array_d
    # Limit reading of trp_temp_array_d "array" with $tot_classes
   
    ("sort_troops_by_class",
        [
       
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_a", ":i", 0), #troop id
            (try_end),  
           
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_b", ":i", 0), # number troops
            (try_end),

            (assign, ":indx_temp", -1),
            (party_get_num_companion_stacks , ":num_stacks", "p_main_party"),
           
            (try_for_range,":indx", 0, "$tot_classes"), #for each class, select
           
                (troop_get_slot, ":id_class", "trp_temp_array_d", ":indx"),
               
                (try_for_range, ":i", 1, ":num_stacks"),
                   
                    (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
                    (troop_get_class, reg0, ":troop"),
                   
                    #if match, copy troop id, size to temps.
                    (try_begin),
                        (eq, reg0, ":id_class"),
                        (val_add, ":indx_temp", 1),
                        (party_stack_get_troop_id, ":troop_c",  "p_main_party",  ":i"),
                        (party_stack_get_size, ":size", "p_main_party", ":i"),
                        (troop_set_slot, "trp_temp_array_a", ":indx_temp", ":troop_c"),
                        (troop_set_slot, "trp_temp_array_b", ":indx_temp", ":size"),
                    (try_end),
               
                (try_end),

            (try_end),
           
            #delete all minus player
            (try_for_range, ":i", 0, ":num_stacks"),
                (troop_get_slot, reg0, "trp_temp_array_a", ":i"),
                (troop_get_slot, reg1, "trp_temp_array_b", ":i"),
                (party_remove_members, "p_main_party", reg0, reg1),
            (try_end),
           
            #add troops following order from temp a and b.
            (try_for_range, ":i", 0, ":num_stacks"),
                (troop_get_slot, reg0, "trp_temp_array_a", ":i"),
                (troop_get_slot, reg1, "trp_temp_array_b", ":i"),
                (party_add_members, "p_main_party", reg0, reg1),
            (try_end),
       
       
    ]),
   
   
    #Arris
    # Reinserts companions in ordered party
    # in their original places.
    # Uses trp_temp_array_e for companion position info.
   
    ("reinsert_companions",
       
        [
       
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_a", ":i", 0), #troop id
            (try_end),  
           
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_b", ":i", 0), # number troops
            (try_end),
           
            (party_get_num_companion_stacks , ":num_stacks", "p_main_party"),
           
            #copy main_party a temp, with no companions
            (assign, ":indx_temp", -1),
           
            (try_for_range, ":i", 1, ":num_stacks"),
                (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
                (party_stack_get_size, ":size", "p_main_party", ":i"),
               
                (try_begin),
                    (troop_is_hero, ":troop"),
                (else_try),
                    (val_add, ":indx_temp", 1),
                    (troop_set_slot, "trp_temp_array_a", ":indx_temp", ":troop"),
                    (troop_set_slot, "trp_temp_array_b", ":indx_temp", ":size"),
                (try_end),
               
            (try_end),
           
            #delete all minus player in main_party
            (try_for_range, ":i", 1, ":num_stacks"),
                (party_stack_get_troop_id, reg0, "p_main_party", 1),
                (party_stack_get_size, reg1, "p_main_party", 1),
                (party_remove_members, "p_main_party", reg0, reg1),
            (try_end),
           
            #recopy from temp_e to main_party, intercalating companions at recorded position
            (assign, ":indx_temp", -1),
           
            (try_for_range, ":i", 1, ":num_stacks"),
               
                (try_begin),
                    (troop_get_slot, ":troop", "trp_temp_array_e", ":i"),
                    (neq, ":troop", -1),
                    (party_add_members, "p_main_party", ":troop", 1),
                (else_try),
                    (val_add, ":indx_temp", 1),
                    (troop_get_slot, reg0, "trp_temp_array_a", ":indx_temp"),
                    (troop_get_slot, reg1, "trp_temp_array_b", ":indx_temp"),
                    (party_add_members, "p_main_party", reg0, reg1),
                (try_end),
               
            (try_end),
                       
    ]),
   
   
    # Arris
    # Compile companion's positions in main party
    # Stored in trp_temp_array_e
   
     ("position_companions",
        [
       
            (try_for_range, ":i", 0, 100),
                (troop_set_slot, "trp_temp_array_e", ":i", -1),
            (try_end),
           
            (party_get_num_companion_stacks , ":num_stacks", "p_main_party"),  
           
            (try_for_range, ":i", 1, ":num_stacks"),
           
                (party_stack_get_troop_id, ":troop",  "p_main_party",  ":i"),
               
                (try_begin),
                    (troop_is_hero, ":troop"),
                    (troop_set_slot, "trp_temp_array_e", ":i", ":troop"),
                (try_end),
           
            (try_end),
       
     ]),


New submenu (included in "camp_action"):

Python:
#Arris
       ("action_sort_troops",
        [
            (party_get_num_companions, reg0, "p_main_party"),
            (gt, reg0, 1),
        ],
            "Sort troops.",
        [
            (start_presentation, "prsnt_sort_troops"),
        ]
       ),

A couple more temp arrays as new troops:

Code:
 ["temp_array_d","{!}temp_array_d","{!}temp_array_d",tf_hero|tf_inactive, 0,reserved,  fac_neutral,[],def_attrib|level(18),wp(60),knows_common, 0], #Arris
 ["temp_array_e","{!}temp_array_e","{!}temp_array_e",tf_hero|tf_inactive, 0,reserved,  fac_neutral,[],def_attrib|level(18),wp(60),knows_common, 0], #Arris

(Operation instructions and images in next post)
 
Last edited:

Arris Rumi

Recruit
To sort your troops, go to camping, take action:
VFbCR7q.png
The sorting screen appears:
GLR9Vg1.png
Press any of the corresponding buttons to sort by level, faction or class. If sorting by level you can specify ascending or descending sort with the checkbox.

To sort by faction or class you need to specify in which order either the factions or clases are to be sorted. The screens shows you the current factions/clases in your party, and a possible ordering. To modify the ordering, just swap items by clicking on the two items you want to swap until satisfied.

Finally, you can choose to not include your companions in the reordering by checking the "fixed companions" checkbox.

Note: In Native, the "Commoner" faction includes your companions and merchs.

Example of use:

You have this troops, with no order:
7Zi5uey.png

After sorting by troop level (descending), you get:
BIxODxB.png

Ordering by factions, like this:
26jke6W.png

Gets you this:
TbUPg7C.png

And ordering by class, like this:
Im3zb0f.png

Gets you this:
BkEBdRf.png

If you want to "fix" your companions, select that option. Here we sort by level, with the companions not involved in the sorting:
gkDMv7e.png

Giving:
plVEzBn.png

As you can see, Ymira and Jeremus retain their place even after sorting.
06PtD9J.png

Finally, if first sorting by level and immediately by faction, you get your troops grouped by faction, and within each faction, sorted by level:
zndKpKQ.png

Result:
aYbb6Ij.png

Note: Beware! Not all combinations will make sense! Sorting first by level and then by faction or by class groups the results. Other combinations, or a different order of sortings, won't.

And this is it. Any and all comments are welcome, especially bug reports :wink:.
 
Last edited by a moderator:
1. This is programmer-centric rather than user-centric. It focuses on functionality rather than what users need. No one needs all kinds of sorting with multiple keys. A realistic use case is sorting by level for general combat or putting archers first for sieges - I don't think anyone cares about troop faction. Know what players want.
2. The GUI presentation is messy and need to be reorganized. It could be simplified to two dropboxes (sort by, sort order) and a sort button (or redone as a menu instead of presentation). Companions should always be left alone where the player put them, and the sorting order should be: by level - always descending, by class - choose from the second dropbox a combination arch/inf/cav for sieges or cav/inf/arch or inf/arch/cav for field battles.
3. The whole thing should be put into the party screen presentation for much easier use.
4. If the goal is to help the player choose which troops would go into battle, better do this directly instead of just sorting the party.

Hope this helps and doesn't discourage. At least it's a good coding exercise for you that may lead to greater things.
 
Last edited:

Arris Rumi

Recruit
1. This is programmer-centric rather than user-centric. It focuses on functionality rather than what users need. No one needs all kinds of sorting with multiple keys. A realistic use case is sorting by level for general combat or putting archers first for sieges - I don't think anyone cares about troop faction. Know what players want.
2. The GUI presentation is messy and need to be reorganized. It could be simplified to two dropboxes (sort by, sort order) and a sort button (or redone as a menu instead of presentation). Companions should always be left alone where the player put them, and the sorting order should be: by level - always descending, by class - choose from the second dropbox a combination arch/inf/cav for sieges or cav/inf/arch or inf/arch/cav for field battles.
3. The whole thing should be put into the party screen presentation for much easier use.
4. If the goal is to help the player choose which troops would go into battle, better do this directly instead of just sorting the party.

Hope this helps and doesn't discourage. At least it's a good coding exercise for you that may lead to greater things.

Hi MadVader. You were one of the POP's modders, right? Congratulations on an excellent mod!

I liked your criticism, made me think. I guess the core difference between your vision and mine is that, actually, I don't know what the player will want, and that's why I gave them all options, as to say. Let the player decide what is useful and what isn't. Better to be excessive than lacking. Naturally, if feedback indicates that certain things are never used, or useful, I'll eliminate them. No problemo.

You are right on that the companions should almost always stay in the same position. I'll modify the code so that that is the default.

I agree with you that this would work better if accesible from the party screen. But, in my limited understanding, that screen is hard-wired, right? If you tell me how to modify it, it would be great.

I just completed a sub mod for Brytenwalda (fixing a "supply wagon" feature they have there, you may check it if you are interested) and there is something there that can be used to order the party by hand. Will take a look, see what happens.

Frankly, I don't think I will re-do this extensively, but again, thank you for your thoughts!

PS: This is the first time I "mod" any games. COVID boredom. But, just to tell you my friend, "coding exercises" of another kind, I've had plenty. :wink:

Regards,
Arris
 
PS: This is the first time I "mod" any games. COVID boredom. But, just to tell you my friend, "coding exercises" of another kind, I've had plenty. :wink:
PoP was the first time I modded something and it was a great experience. I recommend diving into Bannerlord modding if you want players now.

About the hardcoded party screen, it may be possible to get around its hardcodedness by advanced magic, but my knowledge is rusty at this point. There are hooks to certain button clicks there (like script_game_troop_upgrades_button_clicked) and maybe its possible to do some magic with an additional transparent presentation whenever the party screen pops up? Hopefully someone can help, the forge moderators like @Eärendil Ardamírë are extremely helpful here.
 

Eärendil Ardamírë

Subforum Moderator
WBWF&SM&B
Iirc there is no way to edit the party screen presentation, except for adding and implementing the troop tree button which has been a feature coming with VC. It is connected with the hook MadVader mentions (script_game_troop_upgrades_button_clicked), a full description can be found here:

The only way how I could imagine that you can hook it in a similar way would be that you add it as a page or switch at that troop tree presentation. Crysix implemented something similar as you only via the game menus:
Alternatively you could implement it as simple trigger like rubik did here, so that the player can choose the settings and it's getting sorted regulary by the game itself (rubik uses a simple trigger to do this with lords' parties):
 
Is it possible in these times, to designate in advance and by code more classes of troops than infantry, cavalry and archers? ... I would like to add for example, militia, hunters and grenadiers ... so that the players do not have to do it manual, but not for the type of item they use, since most of the troops of my mod, use only muskets
 

Arris Rumi

Recruit
Is it possible in these times, to designate in advance and by code more classes of troops than infantry, cavalry and archers? ... I would like to add for example, militia, hunters and grenadiers ... so that the players do not have to do it manual, but not for the type of item they use, since most of the troops of my mod, use only muskets

Qué tal Mauromagno (viva Chile!)

Just saw your message. Well, my code should be able to add all classes represented in your party automatically, because it just scans every troop on your party, takes note of any new class, and adds it. As long as the classes are correctly defined somewhere else, it should work.

(Acabo de ver tu mensaje. Bueno, el código debiera ser capaz de añadir todas las clases presentes en tu "party" automáticamente, porque hace un barrido por las tropas y añade a la lista de clases toda clase nueva que encuentre. Mientras hayas definido las clases de tropa correctamente, debiera funcionar.)

Saludos,
Arris.
 
Last edited:
Qué tal Mauromagno (viva Chile!)

Just saw your message. Well, my code should be able to add all classes represented in your party automatically, because it just scans every troop on your party, takes note of any new class, and adds it. As long as the classes are correctly defined somewhere else, it should work.

(Acabo de ver tu mensaje. Bueno, el código debiera ser capaz de añadir todas las clases presentes en tu "party" automáticamente, porque hace un barrido por las tropas y añade a la lista de clases toda clase nueva que encuentre. Mientras hayas definido las clases de tropa correctamente, debiera funcionar.)

Saludos,
Arris.
Thanks for the answer, I will test your code, to see if it is really what I need, then I will comment on the result 🙂
ps thanks for the translation, but it is not necessary hehehe and long live Chile 😀
 
Top Bottom