Recent content by xenoargh

  1. xenoargh

    Can These Things Be Fixed? <Long>

    I really like what you're doing here. Just wanted to wish you the best of luck and hope to give you some encouragement to continue. You recording your process here in the thread is a treat to read.

    While I've fallen off the series after the state Bannerlord released in, I do miss this community sometimes. Discord feels too ephemeral for me.
    I'm glad you've enjoyed reading this stuff, lol.

    Meanwhile, I'm like, IDK... halfway through troop updates, or so. Been very busy IRL this last couple of weeks, so progress has been slower than I like. I want to get Narf's other plate armor rigged for males this week if I can, too.
  2. xenoargh

    Any way to mod how AI chooses melee weapons?

    The source for all that ships with Blood and Steel, and that's all Open Source, so far as I'm concerned. The key function is in module_scripts, called via a Mission trigger, but there are bits of ancillary code dealing with situations. Here's the core script, though:

    Python:
    #TROOP EQUIPMENT SYSTEM
    #input:  agent id
    ("cf_troop_equipment_system",[
        (this_or_next|multiplayer_is_server),
        (neg|game_in_multiplayer_mode), 
        #(display_message, "@Running equipment script"),#DEBUG
        (store_trigger_param_1, ":agent_no"),
        
        (assign, ":stop", 0),   
        (agent_is_human, ":agent_no"),
        (agent_is_active, ":agent_no"),
        (agent_is_alive, ":agent_no"),
        (neq, ":agent_no", 0),
        (agent_get_troop_id, ":id", ":agent_no"),
            
        #MERCHANT FIXES   
        (try_begin),
            (this_or_next|is_between, ":id", armor_merchants_begin, armor_merchants_end),
            (this_or_next|is_between, ":id", weapon_merchants_begin, weapon_merchants_end),
            (this_or_next|is_between, ":id", goods_merchants_begin, goods_merchants_end),
            (this_or_next|eq, ":id", "trp_tavern_bookseller_1"),
            (this_or_next|eq, ":id", "trp_tavern_bookseller_2"),
            (is_between, ":id", horse_merchants_begin, horse_merchants_end),
            #(display_message, "@Merchant found, equipping him/her"),
            
            #Remove the gloves
            (agent_get_item_slot, ":gloves", ":agent_no", 7),#Get the gloves
            (try_begin),
                (gt, ":gloves", 0),
                (agent_unequip_item, ":agent_no", ":gloves"),
            (try_end),   
            #Remove the hats
            (agent_get_item_slot, ":hat", ":agent_no", 4),#Get the hats
            (try_begin),
                (gt, ":hat", 0),
                (agent_unequip_item, ":agent_no", ":hat"),
            (try_end),           
            
            (try_begin),
                (troop_get_type, ":cur_troop_gender", ":id"),
                (eq, ":cur_troop_gender", 0),
                (store_random_in_range, ":clothes", "itm_tunic_with_green_cape","itm_female_civ_clothes_start"),
                (store_random_in_range, ":shoes", "itm_ankle_boots", "itm_narf_bear_paw_shoes"),
                (agent_equip_item, ":agent_no", ":shoes"),
                (agent_equip_item, ":agent_no", ":clothes"),
            (else_try),
                (store_random_in_range, ":clothes", "itm_red_dress", "itm_female_civ_clothes_end"),
                (store_random_in_range, ":shoes", "itm_ankle_boots", "itm_narf_bear_paw_shoes"),
                (agent_equip_item, ":agent_no", ":shoes"),               
                (agent_equip_item, ":agent_no", ":clothes"),
            (try_end),
        (try_end),
        
        #CARAVAN MASTER
        (try_begin),
            (eq, ":id", "trp_caravan_master"),
            (agent_equip_item, ":agent_no", "itm_coat_of_plates_red"),
            (agent_equip_item, ":agent_no", "itm_steel_shield"),
            (agent_equip_item, ":agent_no", "itm_scale_gauntlets"),
            (agent_equip_item, ":agent_no", "itm_iron_greaves"),
            (agent_equip_item, ":agent_no", "itm_segmented_helmet"),
            (agent_equip_item, ":agent_no", "itm_winged_mace"),
        (try_end),   
        
        #Adjust the speeds of all Agents.
        (troop_get_slot, ":speed_mult", ":id", slot_troop_speed_mult),
        #(assign, reg0, ":speed_mult"),
        #(display_message, "@Speed Mult: {reg0}"),
        (agent_set_speed_modifier, ":agent_no", ":speed_mult"),
        (agent_set_speed_limit, ":agent_no", 35),
        
        #Speed up the player.
        (try_begin),
            (eq, ":id", "trp_player"),
            #Special speed boost for Barbarians.
            (troop_get_slot, ":char_class", "trp_player", slot_troop_character_class),
            (try_begin),
                (eq, ":id", "trp_player"),#It's the player
                (eq, ":char_class", 3),#Player is a Barbarian
                (agent_set_speed_modifier, ":agent_no", 200),#Really fast!
            (else_try),   
                (agent_set_speed_modifier, ":agent_no", 150),
            (try_end),
        (try_end),   
        
        #Gets rid of duplicate / extra weapons
        (try_begin),
            (neg|troop_is_hero, ":id"),
            (agent_get_wielded_item, ":wielded_item", ":agent_no", 0),
            (assign, ":got_weapon", 0),
            (assign, ":weapon_slot", 0),
            (is_between, ":wielded_item", "itm_weapons_start", "itm_missile_weapons_start"),#Agent is wielding a hand weapon at this time
            (try_for_range, ":i", 0, 4),#Search the item slots 0-3
                (agent_get_item_slot, ":item_id", ":agent_no", ":i"),
                (is_between, ":item_id", "itm_weapons_start", "itm_missile_weapons_start"),#hand weapon
                (assign, ":got_weapon", 1),
                (assign, ":weapon_slot", ":i"),
            (try_end),
    
            (try_for_range, ":i", 0, 4),#Search the item slots 0-3
                (eq, ":got_weapon", 1),
                (agent_get_item_slot, ":item_id", ":agent_no", ":i"),
                (is_between, ":item_id", "itm_weapons_start", "itm_missile_weapons_start"),#hand weapon
                (neq, ":weapon_slot", ":i"),
                (agent_unequip_item, ":agent_no", ":item_id", ":i"),#ditch it
            (try_end),       
        (try_end),
        
        #Gets rid of double shields.
        (try_begin),
            (neg|troop_is_hero, ":id"),
            (agent_get_wielded_item, ":wielded_item", ":agent_no", 1),#Shields
            (is_between, ":wielded_item", "itm_shields_start", "itm_shields_end"),#shield
            (assign, ":got_shield", 0),
            (assign, ":shield_slot", 0),
            (try_for_range, ":i", 0, 4),#Search the item slots 0-3
                (agent_get_item_slot, ":item_id", ":agent_no", ":i"),
                (is_between, ":item_id", "itm_shields_start", "itm_shields_end"),#shield
                (assign, ":got_shield",1),
                (assign, ":shield_slot",":i"),
            (try_end),
            (try_for_range, ":i", 0, 4),#Search the item slots 0-3
                (eq, ":got_shield",1),
                (agent_get_item_slot, ":item_id", ":agent_no", ":i"),
                (is_between, ":item_id", "itm_shields_start", "itm_shields_end"),#shield
                (neq, ":shield_slot", ":i"),
                (agent_unequip_item, ":agent_no", ":item_id", ":i"),#ditch it
            (try_end),       
        (try_end),       
    
        #Alephs can't crouch and are really slow
        (try_begin),
            (this_or_next|eq, ":id", "trp_aleph"),
            (eq, ":id", "trp_aleph_non_player"),
            (agent_ai_set_can_crouch, ":agent_no", 0),
        (try_end),
        
        #Remnants can't crouch and are really fast
        (try_begin),
            (eq, ":id", "trp_death_knight_remnant"),
            (agent_ai_set_can_crouch, ":agent_no", 0),
        (try_end),   
        
        #Convert Marnid into the Aleph if player is not driving it and we're not indoors
        (try_begin),
            (eq, "$g_player_drives_aleph", 0),
            (eq, "$g_player_owns_aleph", 1),
            (eq, "$g_can_drive_aleph_here", 1),
            (try_begin),
                (eq, ":id", "trp_npc2"),#Is Marnid
                (agent_get_team, ":team", ":agent_no"),
                (agent_get_position, pos1, ":agent_no"),
                (agent_fade_out, ":agent_no"),
                (set_spawn_position, pos1),
                (spawn_agent, "trp_aleph_non_player"),
                (agent_ai_set_can_crouch, reg0, 0),#disable crouching
                (agent_set_speed_modifier, reg0, 50),#Really slooow!
                (agent_set_team, reg0, ":team"),
            (try_end),
        (try_end),
        
        #EQUIP ALL SPECIAL-CASE TROOPS
        #FEMALE IRREGULARS
        #NOW WIELD BOWS FIRST
        (try_begin),
            (this_or_next|eq, ":id", "trp_mercenary_infantry_woman"),
            (this_or_next|eq, ":id", "trp_mercenary_infantry_woman_sergeant"),
            (this_or_next|eq, ":id", "trp_mercenary_infantry_woman_elite"),
            (eq, ":id", "trp_mercenary_infantry_woman_expert"),       
            (agent_equip_item, ":agent_no", "itm_javelin"),
            (agent_equip_item, ":agent_no", "itm_rogue_bow"),
            (agent_equip_item, ":agent_no", "itm_arrows"),
            (assign, ":tempIII", "itm_lui_inquisitorsword"),
            (val_add, ":tempIII", 1),       
            (store_random_in_range, ":sword", "itm_lui_inquisitiongreatsword", ":tempIII"),
            (agent_equip_item, ":agent_no", ":sword"),
            (assign, ":endme", 0),
            (try_for_range, ":i", 0, 4),#(slots < 10)?
                (eq, ":endme", 0),
                (troop_get_inventory_slot,":item",":id",":i"),
                (eq, ":item", "itm_rogue_bow"),
                (agent_set_wielded_item, ":agent_no", ":item"),
                (assign, ":endme", 1),
            (try_end),
        (try_end),
        
        #BATTLE SISTERS
        #GUARANTEED BWANGAS
        (try_begin),
            (this_or_next|eq, ":id", "trp_mercenary_polearm_woman_recruit"),
            (this_or_next|eq, ":id", "trp_mercenary_polearm_woman_regular"),
            (eq, ":id", "trp_mercenary_polearm_woman_elite"),       
            (agent_equip_item, ":agent_no", "itm_xenoargh_bwanga"),
        (try_end),
        
        #SISTERS OF MERCY
        #GUARANTEED GRENADES
        (try_begin),
            (eq, ":id", "trp_sister_of_mercy"),   
            (agent_equip_item, ":agent_no", "itm_xenoargh_troop_grenade"),
        (try_end),       
        
        #VAEGIR LEGIONNAIRES AND CRUSHERS
        (try_begin),
            (assign, ":tempI", "trp_vaegir_legionnaire_elite"),
            (val_add, ":tempI", 1),   
            (assign, ":tempII", "trp_vaegir_crusher_elite"),
            (val_add, ":tempII", 1),   
            (this_or_next|is_between, ":id", "trp_vaegir_legionnaire_recruit", ":tempI"),
            (this_or_next|is_between, ":id", "trp_vaegir_crusher_recruit", ":tempII"),
            (eq, ":id", "trp_vaegir_praetorian"),
            
            #Give 'em their throwing spears
            (agent_equip_item, ":agent_no", "itm_throwing_spears"),
            (agent_equip_item, ":agent_no", "itm_jarid"),
            
            #Give Legionnaires short-swords and Crushers two-handers
            (try_begin),
                (is_between, ":id", "trp_vaegir_legionnaire_recruit", ":tempI"),
                (assign, ":tempIII", "itm_lui_mercenaryshort"),
                (val_add, ":tempIII", 1),       
                (store_random_in_range, ":sword", "itm_sword_medieval_b_small", ":tempIII"),
                (agent_equip_item, ":agent_no", ":sword"),
                (assign, ":tempIII", "itm_spak_hermitage_shield_3"),
                (val_add, ":tempIII", 1),               
                (store_random_in_range, ":shield", "itm_spak_hermitage_shield_1", ":tempIII"),
                (agent_equip_item, ":agent_no", ":shield"),           
            (else_try),
                (assign, ":tempIII", "itm_lui_roughdaksword"),
                (val_add, ":tempIII", 1),       
                (store_random_in_range, ":sword", "itm_lui_midnight", ":tempIII"),
                (agent_equip_item, ":agent_no", ":sword"),       
            (try_end),
            (assign, ":endme", 0),
            (try_for_range, ":i", 0, 4),#(slots < 10)?
                (eq, ":endme", 0),
                (troop_get_inventory_slot,":item",":id",":i"),
                (eq, ":item", "itm_throwing_spears"),
                (agent_set_wielded_item, ":agent_no", ":item"),
                (assign, ":endme", 1),
            (try_end),
        (try_end),   
        
        #MERC GRENADIERS
        #BIG CHANGES, NO LONGER GET SHIELDS, ALWAYS GET GRENADES IN SECOND SLOT
        #ALWAYS SET TO WIELD ARQUEBUS
        (try_begin),
            (eq, ":id", "trp_mercenary_grenadier"),
            (agent_equip_item, ":agent_no", "itm_arquebus"),
            (agent_equip_item, ":agent_no", "itm_xenoargh_troop_grenade"),
            (agent_equip_item, ":agent_no", "itm_bolts"),
            (agent_equip_item, ":agent_no", "itm_boar_spear"),
            (assign, ":endme", 0),
        (try_end),
        
        #MERC DRAGOON
        #ALWAYS GET GRENADES IN SECOND SLOT AND DRAGONS
        (try_begin),
            (eq, ":id", "trp_mercenary_dragoon"),
            (agent_equip_item, ":agent_no", "itm_dragon"),
            (agent_equip_item, ":agent_no", "itm_xenoargh_troop_grenade"),
            (agent_equip_item, ":agent_no", "itm_bolts"),
            (assign, ":endme", 0),
        (try_end),   
        
        #ROYAL HUNTSMEN
        (try_begin),
            (eq, ":id", "trp_swadian_royal_huntsman"),
            (agent_equip_item, ":agent_no", "itm_long_bow"),
            (agent_equip_item, ":agent_no", "itm_arrows"),
            (agent_equip_item, ":agent_no", "itm_xenoargh_troop_grenade"),
            (assign, ":endme", 0),
            (try_for_range, ":i", 0, 4),#(slots < 10)?
                (eq, ":endme", 0),
                (troop_get_inventory_slot,":item",":id",":i"),
                (eq, ":item", "itm_long_bow"),
                (agent_set_wielded_item, ":agent_no", ":item"),
                (assign, ":endme", 1),
            (try_end),
        (try_end),   
    
        #HERO BATTLE EQUIPMENT
        (try_begin),
            (troop_is_hero,":id"),
            #Swadians
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_1_1", "trp_knight_2_1"),
                (eq, ":id", "trp_kingdom_of_swadians_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_narf_gothic_plate"),
                (agent_equip_item, ":agent_no", "itm_spak_warhorse_imperial"),
                (agent_equip_item, ":agent_no", "itm_narf_shynbaulds"),
                (agent_equip_item, ":agent_no", "itm_dejawolf_greathelm1"),
                (agent_equip_item, ":agent_no", "itm_narf_plate_mittens"),
            (try_end),
            #Vaegir
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_2_1", "trp_knight_3_1"),
                (eq, ":id", "trp_kingdom_of_vaegirs_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_amade_bronze_plate"),
                (agent_equip_item, ":agent_no", "itm_warhorse_sarranid"),
                (agent_equip_item, ":agent_no", "itm_amade_bronze_greaves"),
                (agent_equip_item, ":agent_no", "itm_amade_bronze_gauntlets"),
                (agent_equip_item, ":agent_no", "itm_amade_bronze_winged_helm"),
            (try_end),
            #Khergits
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_3_1", "trp_knight_4_1"),
                (eq, ":id", "trp_kingdom_of_khergits_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_ssh_yoroi"),
                (agent_equip_item, ":agent_no", "itm_warhorse_steppe"),
                (agent_equip_item, ":agent_no", "itm_ssh_suneate"),
                (agent_equip_item, ":agent_no", "itm_ssh_kote"),
                (agent_equip_item, ":agent_no", "itm_ssh_kabuto"),               
            (try_end),
            #Nords
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_4_1", "trp_knight_5_1"),
                (eq, ":id", "trp_kingdom_of_nords_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_dejawolf_vikingbyrnie"),
                (agent_equip_item, ":agent_no", "itm_warhorse_chain_barding01"),
                (agent_equip_item, ":agent_no", "itm_splinted_greaves"),
                (agent_equip_item, ":agent_no", "itm_mail_mittens"),
                (agent_equip_item, ":agent_no", "itm_xenoargh_viking_steel_winged_helm02"),               
            (try_end),
            #Rhodoks
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_5_1", "trp_knight_6_1"),
                (eq, ":id", "trp_kingdom_of_rhodoks_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_narf_milanese_plate"),
                (agent_equip_item, ":agent_no", "itm_charger_plate"),
                (agent_equip_item, ":agent_no", "itm_narf_steel_greaves"),
                (agent_equip_item, ":agent_no", "itm_gauntlets"),
                (agent_equip_item, ":agent_no", "itm_narf_visored_sallet_coif"),
            (try_end),
            #Sarranids
            (try_begin),
                (this_or_next|is_between, ":id", "trp_knight_6_1", "trp_kingdom_of_swadians_pretender"),
                (eq, ":id", "trp_kingdom_of_sarranids_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_wei_xiadi_sarranid_mamluk_armor"),
                (agent_equip_item, ":agent_no", "itm_warhorse_sarranid"),
                (agent_equip_item, ":agent_no", "itm_sarranid_boots_c"),
                (agent_equip_item, ":agent_no", "itm_narf_wisby_gauntlets_black"),
                (agent_equip_item, ":agent_no", "itm_sarranid_veiled_helmet"),
            (try_end),
            #Death Knights
            (try_begin),
                #(this_or_next|is_between, ":id", "trp_knight_6_1", "trp_kingdom_of_swadians_pretender"),
                (eq, ":id", "trp_death_knights_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_narf_milanese_plate_dark"),
                (agent_equip_item, ":agent_no", "itm_spak_horny_charger_plate"),
                (agent_equip_item, ":agent_no", "itm_narf_steel_greaves_dark"),
                (agent_equip_item, ":agent_no", "itm_narf_wisby_gauntlets_black"),
                (agent_equip_item, ":agent_no", "itm_spak_demon_hood"),
            (try_end),
            #Holy Army
            (try_begin),
                #(this_or_next|is_between, ":id", "trp_knight_6_1", "trp_kingdom_of_swadians_pretender"),
                (eq, ":id", "trp_templars_lord"),
                (neq, "$talk_context", tc_court_talk),
                (agent_equip_item, ":agent_no", "itm_narf_early_transitional_templar"),
                (agent_equip_item, ":agent_no", "itm_warhorse_chain_barding_templar"),
                (agent_equip_item, ":agent_no", "itm_narf_steel_greaves_dark"),
                (agent_equip_item, ":agent_no", "itm_narf_wisby_gauntlets_black"),
                (agent_equip_item, ":agent_no", "itm_narf_sugarloaf_coif_templar"),
            (try_end),       
        (try_end),   
        
        #SPECIAL AMMO SYSTEM
        (try_begin),
            (agent_has_item_equipped, ":agent_no", "itm_xenoargh_rocket_projector"),
            (neg|agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
            (agent_unequip_item, ":agent_no", "itm_xenoargh_rocket_projector"),
        (try_end),
    
        (try_begin),
            (agent_has_item_equipped, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
            (neg|agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
            (agent_unequip_item, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
        (try_end),   
        
        (try_begin),
            (agent_has_item_equipped, ":agent_no", "itm_handgonne"),
            (neg|agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
            (agent_unequip_item, ":agent_no", "itm_handgonne"),
        (try_end),       
    
        (try_begin),
            (agent_has_item_equipped, ":agent_no", "itm_aleph_cannon"),
            (neg|agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
            (agent_unequip_item, ":agent_no", "itm_aleph_cannon"),
        (try_end),       
    
        (try_begin),#Strip universal cannon ammunition
            (neg|agent_has_item_equipped, ":agent_no", "itm_aleph_cannon"),
            (agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
            (agent_unequip_item, ":agent_no", "itm_universal_cannon_ammo"),
            
            #Strip attempts to get around ammo limits.
            (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
                    (agent_unequip_item, ":agent_no", "itm_universal_cannon_ammo"),
            (try_end),
            
            (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_universal_cannon_ammo"),
                    (agent_unequip_item, ":agent_no", "itm_universal_cannon_ammo"),
            (try_end),       
            
            (try_begin),
                (eq, ":stop", 0),
                (agent_has_item_equipped, ":agent_no", "itm_handgonne"),
                (agent_equip_item, ":agent_no", "itm_mortar_grenade"),
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_xenoargh_rocket_projector"),
                    (agent_unequip_item, ":agent_no", "itm_xenoargh_rocket_projector"),
                (try_end),   
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
                    (agent_unequip_item, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
                (try_end),               
                (agent_refill_ammo, ":agent_no"),               
                (assign, ":stop", 1),
            (try_end),   
    
            (try_begin),
                (eq, ":stop", 0),
                (agent_has_item_equipped, ":agent_no", "itm_aleph_cannon"),           
                (assign, ":stop", 1),
            (try_end),           
    
            (try_begin),
                (eq, ":stop", 0),
                (agent_has_item_equipped, ":agent_no", "itm_xenoargh_rocket_projector"),
                (agent_equip_item, ":agent_no", "itm_explosive_rocket_arrows"),       
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_handgonne"),
                    (agent_unequip_item, ":agent_no", "itm_handgonne"),
                (try_end),       
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
                    (agent_unequip_item, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
                (try_end),           
                (agent_refill_ammo, ":agent_no"),           
                (assign, ":stop", 1),
            (try_end),
    
            (try_begin),
                (eq, ":stop", 0),
                (agent_has_item_equipped, ":agent_no", "itm_xenoargh_byzantine_flamethrower"),
                (agent_equip_item, ":agent_no", "itm_xenoargh_byzantine_flamethrower_fuel"),       
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_handgonne"),
                    (agent_unequip_item, ":agent_no", "itm_handgonne"),
                (try_end),       
                (try_begin),
                    (agent_has_item_equipped, ":agent_no", "itm_xenoargh_rocket_projector"),
                    (agent_unequip_item, ":agent_no", "itm_xenoargh_rocket_projector"),
                (try_end),           
                (agent_refill_ammo, ":agent_no"),           
                (assign, ":stop", 1),
            (try_end),           
        (try_end),
    ]),
  3. xenoargh

    Suggestion General Various Fixes, Thoughts

    As an example of what I was talking about for armors (being able to exclude wearing of <category>), this suit cannot be implemented properly in the current Bannerlord system at all:

    bl_narf_04.jpg


    1. It uses gloves that aren't Giant Elbow-Length Gloves. They're... just gloves. Or, in this case, gauntlets. They need the "no_slim" tag I mentioned earlier, otherwise they'd trigger the _slim meshes, which were clearly designed for Bannerlord's gloves, but don't work for anything that merely covers the hands.

    2. The armor's not designed for _slim, and will look pretty bad with a _slim mesh and other gloves.

    3. The armor, while it can technically operate with Bannerlord's boots, is really designed for these particular shynbaulds.

    4. The helmet, which is one of the best we ever had from Warband, was designed for "hides_head". I've made it "work" here, as you can see, but I've had to make some artistic compromises I don't like: the neck area had to be made almost absurdly large to avoid clipping with the new body / head meshes and I've had to rig the bottom part of the mesh to the neck bone, which looks less than ideal, but it at least prevents the head mesh from clipping through the geometry.

    5. Obviously, this kind of full suit of body armor, which is designed with explicit, unique pauldrons, cannot possibly be made to work with Bannerlord's pauldron / cape armors properly.

    So, if I had the features I've requested, I'd probably declare the armor as "all_but_head"; the shynbaulds and gloves would be integrated into the suit; the suit would have the "hides_hands" flag enabled (I'm just going to guess here, but I'll bet your code doesn't even check that flag if it's body armor) and the head would use "hides_head" so that it didn't have to make so many compromises to its aesthetics (this might result in it "floating" above Bannerlord-standard armors at the neck join, but that's easier to fix than having to do a rig that makes it flex in inappropriate ways).

    In short, this is, in one suit of armor, why I want much more control over how armors are presented, and I think this would be good for everybody, including you folks, should you choose to develop more content for the game. Armors should be able to hide all body parts, hand armors should be able to both hide hands and not trigger _slim, armors need to be able to exclude other types of body armor being worn. I think that most of these features should be (fairly) trivial, since pretty much all of the code exists (or can be easily re-purposed):

    1. There's already code to exclude Item A if Item B isn't installed (horses and saddles); extending that to not allow certain equipment and uninstall it if an armor with <type exclusion> is installed by the user via the Inventory UI should be straightforward.

    Essentially:

    C#:
      switch(ItemFlag.armor_compatibility){
        "all":
            remove all other armor items by iteration on the Troop's ItemRoster; removes the items that aren't <this armor type> and places them back into the player's inventory
            alert user by marking the other item boxes in red
            break;
        "all_but_helmet"
            remove all non-helmet armor items
            alert user by marking the other item boxes in red
            break;
        
        etc.
            
        default:
    
            do nothing;
    
            break;
    
      }


    2. "hides_head" is just another boolean Item Flag; hiding other parts is already done, so this is just one more binary check (I presume this check's done once, and only once, when the Agent spawns w/ their equipment, rather than every frame during a Mission- even in that case, it's trivial and non-expensive vs. how it works now, where the entire head, eyes, etc. are all being drawn or are depth-tested for culling, etc.). hides_head should, of course, default to false, to preserve current behaviors.

    3. "no_slim" should be pretty straightforward:

    If(ItemFlag.no_slim) --> use mesh mesh_name for males / mesh_name_converted for females. no_slim should default to false, of course, to preserve existing behaviors.
  4. xenoargh

    Can These Things Be Fixed? <Long>

    Banged this out. This is way, way better than I thought it'd be, lol. Yes, the specular on the pants is a bit too high; I'll tune that down later.

    I guess I have to try the Milanese armor now. I don't think I can fully rescue the Transitional Armor; the maille neck will be a real issue. But there is enough stuff in Bannerlord that more-or-less covers that category.

    Full-face helms are another problem; we have wonderful ones that I'm sure I can make look good as individuals, but Bannerlord doesn't have a "hides_head" tag for helmets, so I'm a little stuck there, and any of them that require a super-specific connection to the neckline will present problems.

    The proper gauntlets for this armor are a problem, too; I can probably kludge them in and make it all work, but only the sense that the complete set will look good, visually. They won't get along with any other armors, though.

    bl_narf_03.jpg
  5. xenoargh

    Suggestion General Various Fixes, Thoughts

    For the Model Viewer, I have several feature requests:

    1. Under File or a new menu, "reset camera". Does what it says; the camera's origin, position and orientation are reset to the defaults. Reason: right now, if you ever move the camera around with the middle-mouse button and get the origin moved somewhere odd, you can end up in situations where you literally cannot see what you're working on and can't fix the camera without restarting the entire application (because Model Viewer's state is saved even when you close that window).

    2. The camera in Model Viewer really needs a smoother zoom function. Middle-mouse scrolling is incredibly jumpy and it often makes it difficult to do screen-captures, etc.

    Suggestion: keep middle-mouse wheel behavior as present, for rough adjustments, and right-click + LSHIFT for a very smooth, slow movement of the camera forwards and backwards. It'd be helpful if there was a similar function for panning, but it's less of an issue than zoom. This probably seems like a minor thing, but I'm sure your own staff has sometimes had trouble setting up a screenshot of a new asset, and had to resort to moving it around with Translate / Rotate, rather than use the camera controls.
  6. xenoargh

    Can These Things Be Fixed? <Long>

    Well, I'll be darned, it actually worked.

    When I posted the above, I thought I had it done and could just move on to the shynbaulds. Nope. Got them in, looked at stuff, and I'm like, "er, what on earth is going on w/ the knees", lol.

    The knees... they're going to haunt my dreams. Narf expected that the verts would be just so in relation to the knee joint position, and guess what, it's not where it used to be, lol. Working around that was fun, and it still clips slightly, but it's probably invisible to Average Joe Gamer during normal gameplay. The pauldrons were also fun, but in a totally expected way.

    Also! I finally figured out what that extra arm bone (between the elbow and shoulder) is for. It's been a mystery and I've largely ignored it. It's for elbow armors, so that they (largely) go where they should. The results here still clip a bit, but it's not bad, considering Narf wasn't rigging for that at all.

    bl_narf_02.jpg
  7. xenoargh

    Can These Things Be Fixed? <Long>

    Ima just leaving this here. For you know, reasons.
    bl_narf_01.jpg
  8. xenoargh

    Can These Things Be Fixed? <Long>

    "I'm from the Empire. We're here to 'help'."

    Anyhow, that's a wrap on Amade's stuff; now I just need to integrate them with the game, etc. I think the main takeaway from this is that I'll want to pick my battles about what to try porting next; not everything will work out this nicely.
    bl_amade_armor03.jpg
  9. xenoargh

    Suggestion General Various Fixes, Thoughts

    Can you check whether the vsync is enabled in the config?
    VSync is now enabled and I've verified that it works in the Modding Toolkit.

    That really helps keep things cool and stable, in general, but in the Modding Toolkit, it's exceptionally important, because the CPU / GPU load is often so low that the GPU may be rendering hundreds of frames a second otherwise, which isn't good for it, lol. Honestly, in Modding Toolkit we simply shouldn't need FPS higher than 60, imo.

    We will bring this up internally.

    Thanks. These are all just minor things that would help modders shape the way gear equips work. In general, to have a system that's flexible and transparent for players, it's easier to exclude gear that's not desired by the artist.

    But! Perhaps, instead of the idea of "no_pauldron", there should be an ItemFlag:

    armor_incompatibilty = <string type enum>

    Values would be "all", "all_but_helmet", "pauldron", "boots", "gloves".


    This would cover 99% of use cases. In the vast majority of cases, "all_but_helmet" would give artists pretty complete freedom w/ body armors. For really extreme armors (say, somebody wants to put Batman's armor into the game) "all" would allow that.

    But they could also, for example, have armor with built-in gloves, but have armor_incompatibility="gloves" and hides_hands="true".

    So, the concept of "armor that can exclude other armor types from being worn" would be very useful for artists. As things stand, I'll just have to tell players that if they wear certain armors, that they'll look absolutely terrible w/ pauldrons and gloves, or are meant to be paired with <helmet>, but it can't be helped.

    I still want an ItemFlag for "hides head" like we had in Warband, too. A full-face helmet that completely encloses the head and neck shouldn't need to be designed around the head / neck mesh being present and possibly clipping.
  10. xenoargh

    Can These Things Be Fixed? <Long>

    Man, these old armors are so old and stuff. They'll never look good in Banner-

    bl_amade_armor01.jpg


    On a more serious note... of course I had to start with the hardest male armor I've got. Seriously, I don't think Narf's stuff will be worse. I feel kind of dumb, honestly; I should've started with one of mine. At least this was easier than Dthehun's stuff...

    Amade's armors were pretty delicate in Warband; the rigging's not typical, etc. But now I've crossed the Rubicon... largely by leveraging all the hard lessons from the female ones. I"ve already built a maille "bodysuit" that I can use wherever I want to avoid seam issues (you can't see it here, but there's a little bit of it in this armor at the knees; Warband armor legs end considerably higher up than Bannerlord's do, so I've built that to make sure there's no seam with the existing boots).

    The biggest issue w/ these is that the neck / shoulder area is massively different from Warband. Every armor's going to need its neckline area raised considerably to avoid issues with the necks. I got lucky with this one on a few places; armors with maille in that area are probably a no-go without a repaint.

    bl_amade_armor02.jpg

    Seriously, if you're trying to model armors for BL, you need to build one of these things (a quick, rough version of the base mesh w/ some nice dark texture at the border areas, preferably w/ some neutral armor-ish material elsewhere) first; it saves sooooo much time. I could've probably cut Amade's armor into a few bits and replaced the maille / leather with this, using booleans... and it would've cut my rigging time in half).
  11. xenoargh

    Crash when using SetScriptedPositionAndDirection with non-human agents

    Hmm. So at least they can arrive at <position>?

    Can you give them a facing order (what happens when player uses F7 in the Order UI) when they reach there, maybe?

    So far as I know, the Support Forum's it. Maybe there's a bug-report system somewhere, but IDK.
  12. xenoargh

    Can These Things Be Fixed? <Long>

    Overall, it's a bit frustrating when these limits are turned off. Lord armies are, just like Warband, completely divorced from the "real economy" of the game. Ever notice that Lords only have about 5K in cash, every time you meet them? Yeah... they don't actually have any relationship with the in-game economy like the player does. They still magic up armies.

    But apparently just giving them more headroom isn't enough; I think they're forced to at least pretend to be like players and sit on Villages until they hit their current size goals; when "killed" the goal can reset. I think I'll change my tune when enough of them have gotten "killed" and come back from the dead, though; I'm starting to see 250+ sized Empire armies.

    The only thing that's obviously and immediately affected is, strangely, Caravans. It was kind of amusing seeing 1000+ Caravans running around w/ total immunity to 500+ Bandit parties, lol. I'll have to look at that; something very random's happening there.
  13. xenoargh

    Suggestion General Various Fixes, Thoughts

    Using reflection via Harmony on DefaultPartyWageModel.GetCharacterWage(CharacterObject character) can cause an engine crash, due to an object not being properly locked before access in multithreading code. The code that crashes appears to be used by the Lords to determine what Troops in their Party may be upgraded; it does something really odd where it hits a div-by-zero, presumably because something's very briefly not returning the correct state while Harmony is accessing the variable.

    C#:
        internal class fixWagesOfTroops
        {
            [HarmonyPatch(typeof(DefaultPartyWageModel))]
            [HarmonyPatch("GetCharacterWage")]
            private class newGetCharacterWage
            {
                private static void Postfix(ref CharacterObject character, ref int __result)
                {
    
                    if (character != null)
                    {
    
                        if (character.IsHero && !character.IsPlayerCharacter)
                        {
                            __result = character.Level;
                        } else
                        {
                            //CAN CRASH
                            switch(character.Level){
    
                            }
                            //THIS CODE CAN RUN WITHOUT CRASHES (THUS FAR)
                            if (character.IsRanged)
                            {
                                __result = Math.Max(3,(__result * 3) / 2);
                            } else
                            {
                                __result = Math.Max(3, character.Level / 2);
                            }
                            
                            //Allows "elite pricing" for high-level Troops.
                            if (character.Tier > 6)
                            {
                                __result *= 2;
                            }
                            //Bumps/nerfs for whether the troop is mounted or is a Bandit scrub.
                            if (character.IsMounted) { __result *= 2; }
                            if (character.Occupation.Equals(Occupation.Bandit)) { __result /= 2; }
                        }
                    }
                }
            }
        }
  14. xenoargh

    Crash when using SetScriptedPositionAndDirection with non-human agents

    Hmm. Sounds like when the Agent reaches the required location, it's doing a conventional state-check (as if it's human) and a Horse probably fails bc something is returning null. That should be reported as an engine bug affecting modding; code like that should always be safe to use on an Agent, imo.

    Meanwhile, there's perhaps a way to get around it; maybe when the Agent's near <destination> it should have its state and flags explicitly set, or perhaps they can be set in advance. Well, providing that af_can_wield_weapon returns false if Agent != human...

    Maybe try when the Agent's < 3 meters from <destination> setting the order state to null? The problem w/ this workaround is that you'd need to space out doing the vector calcs across Agents (or explicitly multithread this) to keep performance tidy. Horses move quickly enough that the distance to check would have to be kept quite high to be 100% safe, too.
  15. xenoargh

    Can These Things Be Fixed? <Long>

    Did some testing last night, to see what happens when you join an existing empire as a vassal. The sophistication of the simulation battles is pretty lousy.

    More importantly, here's code for doing basic manipulation of the army sizes (to allow large forces ala Blood and Steel), effectively getting rid of Prisoner Limit (because that's a boring mechanic) and... altering troop wages.


    C#:
    internal class fixPartyLimit
        {
            [HarmonyPatch(typeof(DefaultPartySizeLimitModel))]
            [HarmonyPatch("GetPartyMemberSizeLimit")]
            private class newGetPartyMemberSizeLimit
            {
                private static void Postfix(ref ExplainedNumber __result)
                {
                    __result.Add(999);
                }
            }
        }
    
    
        internal class fixPrisonerLimit
        {
            [HarmonyPatch(typeof(DefaultPartySizeLimitModel))]
            [HarmonyPatch("GetPartyPrisonerSizeLimit")]
            private class newGetPartyPrisonerSizeLimit
            {
                private static void Postfix(ref ExplainedNumber __result)
                {
                    __result.Add(999);
                }
            }
        }

    This one requires a special note. It appears that while this function is being called, Taleworlds is also calling other stuff that's multithreaded, needs access to the Character object, and doesn't lock it!!!

    I've gotten it working here, on this hardware; it can now differentiate between Cavalry, Archers, Archer-Cav and Bandits. Just be careful and test things a lot before trying a variation on this. The code I wrote that crashed before used a switch.

    C#:
        internal class fixWagesOfTroops
        {
            [HarmonyPatch(typeof(DefaultPartyWageModel))]
            [HarmonyPatch("GetCharacterWage")]
            private class newGetCharacterWage
            {
                private static void Postfix(ref CharacterObject character, ref int __result)
                {
    
                    if (character != null)
                    {
    
                        if (character.IsHero && !character.IsPlayerCharacter)
                        {
                            __result = character.Level;
                        } else
                        {
                            if (character.IsRanged)
                            {
                                __result = Math.Max(3,(__result * 3) / 2);
                            } else
                            {
                                __result = Math.Max(3, character.Level / 2);
                            }
                            
                            //Allows "elite pricing" for high-level Troops.
                            if (character.Tier > 6)
                            {
                                __result *= 2;
                            }
                            //Bumps/nerfs for whether the troop is mounted or is a Bandit scrub.
                            if (character.IsMounted) { __result *= 2; }
                            if (character.Occupation.Equals(Occupation.Bandit)) { __result /= 2; }
                        }
                    }
                }
            }
        }
Back
Top Bottom