This OSP is intended for use in singleplayer Warband - it allows you to save a set of equipment for any troop and have them spawn with it in battle. The assignment is done in dialogs, and the equipment is saved in troop slots along with item modifiers, if any. There is no need for declaring additional heroes for holding the inventory or item pools. If the slot is not defined, whatever the agent spawned with is left there. Mark the troop as customizable by defining & setting the troop's
to -1.
Once a mission starts, two triggers take place. One replaces the agent's equipment on the fly as they spawn, the second one forces the agent's horse to the designated value before respawning them. A third trigger can also be added for reinforcement waves, although most people will have their battlesizer set to max.
During the mission a number of changes need to be made such that the replacement agents are recognized properly and take orders from the player. In addition casualty calculations need to be changed so that agents that are replaced don't show up as being killed and the spawned agents do not show up as allies.
Code:
slot_troop_upgrade_troop
Code:
slot_troop_upgrade_troop = 42
...
slot_troop_ek_item_0 = 85
slot_troop_ek_head = slot_troop_ek_item_0 + ek_head
slot_troop_ek_horse = slot_troop_ek_item_0 + ek_horse
#reserve 10 slots after this for item modifiers
Code:
## custom troops begin
("copy_inventory",
[
(store_script_param_1, ":source"),
(store_script_param_2, ":target"),
(troop_clear_inventory, ":target"),
(troop_get_inventory_capacity, ":inv_cap", ":source"),
(try_for_range, ":i_slot", 0, ":inv_cap"),
(troop_get_inventory_slot, ":item", ":source", ":i_slot"),
(troop_set_inventory_slot, ":target", ":i_slot", ":item"),
(troop_get_inventory_slot_modifier, ":imod", ":source", ":i_slot"),
(troop_set_inventory_slot_modifier, ":target", ":i_slot", ":imod"),
(troop_inventory_slot_get_item_amount, ":amount", ":source", ":i_slot"),
(gt, ":amount", 0),
(troop_inventory_slot_set_item_amount, ":target", ":i_slot", ":amount"),
(try_end),
]),
("troop_equip_loadout",
[
(store_script_param_1, ":troop_no"),
(store_script_param_2, ":backup_troop"),
(try_begin),
(gt, ":backup_troop", 0),
(call_script, "script_copy_inventory", ":troop_no", ":backup_troop"),
(troop_sort_inventory, ":backup_troop"),
(try_end),
(try_for_range, ":item_slot", slot_troop_ek_item_0, slot_troop_ek_item_0 + ek_food),
(store_sub, ":inventory_slot", ":item_slot", slot_troop_ek_item_0),
(try_begin), #backup old slot
(eq, ":backup_troop", "trp_find_item_cheat"),
(troop_get_inventory_slot, ":item", ":backup_troop", ":inventory_slot"),
(gt, ":item", 0),
(troop_get_inventory_slot_modifier, ":imod", ":troop_no", ":inventory_slot"),
(troop_add_item, ":troop_no", ":item", ":imod"),
(try_end),
(troop_get_slot, ":item", ":troop_no", ":item_slot"),
(gt, ":item", 0),
(val_add, ":item_slot", 10),
(troop_get_inventory_slot_modifier, ":imod", ":troop_no", ":item_slot"),
#(val_sub, ":item_slot", slot_troop_ek_item_0 + 10),
(assign, reg0, ":inventory_slot"),
(str_store_item_name, s0, ":item"),
(display_message, "@loading slot {reg0} with {s0}"),
(troop_remove_item, ":troop_no", ":item"), #prevent duplicate within inventory?
(troop_set_inventory_slot, ":troop_no", ":inventory_slot", ":item"),
(troop_set_inventory_slot_modifier, ":troop_no", ":inventory_slot", ":imod"),
(else_try),
(troop_set_inventory_slot, ":troop_no", ":inventory_slot", -1),
(try_end),
]),
("inventory_parity_check",
[
(store_script_param_1, ":troop_no"),
(troop_get_inventory_capacity, ":inv_cap", ":troop_no"),
(store_troop_value, reg0, ":troop_no"),
(str_store_troop_name, s0, ":troop_no"),
(display_message, "@{s0} parity check: {reg0}"),
(try_for_range, ":i_slot", 0, ":inv_cap"),
(troop_get_inventory_slot, ":item", ":troop_no", ":i_slot"),
(gt, ":item", 0),
(store_item_value, ":value", ":item"),
(val_add, reg0, ":value"),
(try_end),
]),
## custom end
Code:
######################################
# GENERIC MEMBER CHAT
######################################
[anyone,"member_chat", [], "Your orders {sir/madam}?", "regular_member_talk",[]],
[anyone|plyr,"regular_member_talk", [], "Tell me about yourself", "view_regular_char_requested",[]],
[anyone,"view_regular_char_requested", [], "Aye {sir/madam}. Let me tell you all there is to know about me.", "do_regular_member_view_char",[[change_screen_view_character]]],
[anyone|plyr,"regular_member_talk", [
(troop_slot_eq, "$g_talk_troop", slot_troop_upgrade_troop, -1),
], "Change your loadout", "customize_char_requested",[
(call_script, "script_copy_inventory", "$g_talk_troop", "trp_find_item_cheat"),
(troop_sort_inventory, "trp_find_item_cheat"),
(try_for_range, ":item_slot", slot_troop_ek_item_0, slot_troop_ek_item_0 + ek_food),
(store_sub, ":inventory_slot", ":item_slot", slot_troop_ek_item_0),
(try_begin), #backup old slot
(troop_get_inventory_slot, ":item", "trp_find_item_cheat", ":inventory_slot"),
(gt, ":item", 0),
(troop_get_inventory_slot_modifier, ":imod", "$g_talk_troop", ":inventory_slot"),
(troop_add_item, "$g_talk_troop", ":item", ":imod"),
(try_end),
(troop_get_slot, ":item", "$g_talk_troop", ":item_slot"),
(gt, ":item", 0),
(val_add, ":item_slot", 10),
(troop_get_inventory_slot_modifier, ":imod", "$g_talk_troop", ":item_slot"),
#(val_sub, ":item_slot", slot_troop_ek_item_0 + 10),
(assign, reg0, ":inventory_slot"),
(str_store_item_name, s0, ":item"),
(display_message, "@loading slot {reg0} with {s0}"),
(troop_remove_item, "$g_talk_troop", ":item"), #prevent duplicate within inventory?
(troop_set_inventory_slot, "$g_talk_troop", ":inventory_slot", ":item"),
(troop_set_inventory_slot_modifier, "$g_talk_troop", ":inventory_slot", ":imod"),
(else_try),
(troop_set_inventory_slot, "$g_talk_troop", ":inventory_slot", -1),
(try_end),
]],
[anyone,"customize_char_requested", [], "Aye captain. Let me show you my moves.", "do_custom_member_view_char",[
(set_player_troop, "$g_talk_troop"),
(troop_clear_inventory, "trp_temp_troop"),
#add placeholder items here
(change_screen_loot, "trp_temp_troop"),
]],
#restore inventory - some might be left on the other screen
[anyone,"do_custom_member_view_char", [], "Anything else?", "custom_member_talk",[]],
[anyone,"do_regular_member_view_char", [], "Anything else?", "regular_member_talk",[]],
[anyone|plyr,"custom_member_talk", [], "Carry on, soldier.", "close_window",[(set_player_troop, "trp_player"),
(try_for_range, ":item_slot", ek_item_0, ek_food),
(troop_get_inventory_slot, ":item", "$g_talk_troop", ":item_slot"),
(gt, ":item", 0),
(troop_remove_item, "trp_find_item_cheat", ":item"),
(troop_get_inventory_slot_modifier, ":imod", "$g_talk_troop", ":item_slot"),
(val_add, ":item_slot", slot_troop_ek_item_0),
(assign, reg0, ":item_slot"),
(str_store_item_name, s0, ":item"),
(display_message, "@setting slot {reg0} with {s0}"),
(troop_set_slot, "$g_talk_troop", ":item_slot", ":item"),
(val_add, ":item_slot", 10),
(troop_set_slot, "$g_talk_troop", ":item_slot", ":imod"),
(else_try),
(val_add, ":item_slot", slot_troop_ek_item_0),
(troop_set_slot, "$g_talk_troop", ":item_slot", -1),
(val_add, ":item_slot", 10),
(troop_set_slot, "$g_talk_troop", ":item_slot", -1),
(try_end),
#this should now be missing the items that were selected
(troop_sort_inventory, "trp_find_item_cheat"),
#disregard this, as players can discard items randomly
(troop_clear_inventory, "$g_talk_troop"),
(troop_get_inventory_capacity, ":inv_cap", "trp_find_item_cheat"),
(try_for_range, ":item_slot", 0, ":inv_cap"),
(troop_get_inventory_slot, ":item", "trp_find_item_cheat", ":item_slot"),
(gt, ":item", 0),
(troop_get_inventory_slot_modifier, ":imod", "trp_find_item_cheat", ":item_slot"),
(troop_add_item, "$g_talk_troop", ":item", ":imod"),
(try_end),
]],
[anyone|plyr,"regular_member_talk", [], "Nothing. Keep moving.", "close_window",[]],
Once a mission starts, two triggers take place. One replaces the agent's equipment on the fly as they spawn, the second one forces the agent's horse to the designated value before respawning them. A third trigger can also be added for reinforcement waves, although most people will have their battlesizer set to max.
Code:
custom_troop_reequip = (
ti_on_agent_spawn, 0, 0,
[
(store_trigger_param_1, ":agent_no"),
(agent_get_party_id, ":party_no", ":agent_no"),
(this_or_next|eq, ":party_no", -1), #respawned agents
(eq, ":party_no", "p_main_party"),
(agent_get_troop_id, ":troop_id", ":agent_no"),
(troop_slot_eq, ":troop_id", slot_troop_upgrade_troop, -1),
(try_begin), #spawn_agent waits for this to be called
(eq, ":party_no", -1), #ti_on_init_item called before ti_on_agent_spawn
(agent_set_slot, ":agent_no", slot_agent_is_respawn_as_bot, 1),
(try_end),
],
[
(store_trigger_param_1, ":agent_no"),
(agent_get_troop_id, ":troop_id", ":agent_no"),
(try_for_range, ":item_slot", slot_troop_ek_head, slot_troop_ek_horse),
(troop_get_slot, ":item_no", ":troop_id", ":item_slot"),
(gt, ":item_no", 0),
(neg|agent_has_item_equipped, ":agent_no", ":item_no"),
(try_begin), #unequip to prevent flathead
(val_sub, ":item_slot", slot_troop_ek_item_0),
(agent_get_item_slot, ":old_item", ":agent_no", ":item_slot"),
(gt, ":old_item", 0),
(agent_unequip_item, ":agent_no", ":old_item"),
(try_end),
(agent_equip_item, ":agent_no", ":item_no"),
(try_end),
#weapons can be in random slots already - with existing modifiers
#assume shields, projectiles, etc are logically placed in later slots
(try_for_range_backwards, ":item_slot", slot_troop_ek_item_0, slot_troop_ek_head),
(troop_get_slot, ":weapon_no", ":troop_id", ":item_slot"),
(gt, ":weapon_no", 0),
(item_set_slot, ":weapon_no", slot_item_is_checked, ":item_slot"),
(try_begin),
(neg|agent_has_item_equipped, ":agent_no", ":weapon_no"),
(assign, ":item_no", 0), #replacement check
(try_for_range_backwards, ":ek_slot", ek_item_0, ek_head),
(eq, ":item_no", 0),
(agent_get_item_slot, ":old_item", ":agent_no", ":ek_slot"),
(try_begin), #empty slot
(le, ":old_item", 0),
(assign, ":item_no", -1),
(else_try), #not custom loadout
(item_get_slot, ":old_slot", ":old_item", slot_item_is_checked),
(neg|is_between, ":old_slot", slot_troop_ek_item_0, slot_troop_ek_head),
(assign, ":item_no", ":old_item"),
(try_end),
(try_end),
(try_begin),
(neq, ":item_no", -1),
(agent_unequip_item, ":agent_no", ":old_item"),
(try_end),
(agent_equip_item, ":agent_no", ":weapon_no"),
(try_end),
(try_end),
#reset temp slot
(try_for_range, ":item_slot", slot_troop_ek_item_0, slot_troop_ek_horse),
(troop_get_slot, ":weapon_no", ":troop_id", ":item_slot"),
(gt, ":weapon_no", 0),
(item_set_slot, ":weapon_no", slot_item_is_checked, 0),
(try_end),
]
)
#exclude this from siege missions, no horse anyway
#call this again after add_reinforcements_to_entry
custom_troop_remount = (
ti_after_mission_start, 0, ti_once,
[
(party_get_num_companion_stacks, ":cap", "p_main_party"),
(try_for_range, ":slots", 1, ":cap"),
(party_stack_get_troop_id, ":troop_id", "p_main_party", ":slots"),
(neg|troop_is_hero, ":troop_id"),
(troop_set_slot, ":troop_id", slot_troop_temp_slot, 0),
(try_end),
(try_for_agents, ":agent_no"),
(agent_is_active, ":agent_no"),
(agent_is_human, ":agent_no"),
(agent_get_party_id, ":troop_id", ":agent_no"),
(eq, ":troop_id", "p_main_party"), #player troops
(agent_get_troop_id, ":troop_id", ":agent_no"),
(neg|troop_is_hero, ":troop_id"),
(troop_slot_eq, ":troop_id", slot_troop_upgrade_troop, -1),
(troop_get_slot, ":horse_item", ":troop_id", slot_troop_ek_horse),
(gt, ":horse_item", 0),
(agent_get_horse, ":horse_no", ":agent_no"),
(agent_get_item_id, ":horse_id", ":horse_no"),
(neq, ":horse_id", ":horse_item"),
(troop_get_slot, ":cur_count", ":troop_id", slot_troop_temp_slot),
(val_add, ":cur_count", 1),
(troop_set_slot, ":troop_id", slot_troop_temp_slot, ":cur_count"),
(agent_fade_out, ":agent_no"),
(agent_set_slot, ":agent_no", slot_agent_is_respawn_as_bot, -1),
(try_end),
],
[
(get_player_agent_no, ":player_agent"),
(party_get_num_companion_stacks, ":cap", "p_main_party"),
(agent_get_team, ":player_team", ":player_agent"),
(try_for_range, ":slots", 1, ":cap"),
(party_stack_get_troop_id, ":troop_id", "p_main_party", ":slots"),
(neg|troop_is_hero, ":troop_id"),
(troop_get_slot, ":num_troops", ":troop_id", slot_troop_temp_slot),
(gt, ":num_troops", 0),
(troop_set_auto_equip, ":troop_id", 0),
(troop_get_inventory_slot, ":horse_id", ":troop_id", ek_horse),
(troop_get_inventory_slot_modifier, ":old_imod", ":troop_id", ek_horse),
(troop_get_slot, ":horse_item", ":troop_id", slot_troop_ek_horse),
(troop_get_slot, ":horse_imod", ":troop_id", slot_troop_ek_horse + 10),
(troop_set_inventory_slot, ":troop_id", ek_horse, ":horse_item"),
(troop_set_inventory_slot_modifier, ":troop_id", ek_horse, ":horse_imod"),
(entry_point_get_position, pos4, 4),
(set_spawn_position, pos4),
(assign, "$g_respawn_in_progress", ":troop_id"),
(try_for_range, ":unused", 0, ":num_troops"),
(spawn_agent, ":troop_id"),
(assign, ":agent_no", reg0),
(agent_set_team, ":agent_no", ":player_team"),
(agent_set_slot, ":agent_no", slot_agent_is_respawn_as_bot, 1),
(agent_force_rethink, ":agent_no"),
(try_end),
(assign, "$g_respawn_in_progress", 0),
(assign, reg1, ":num_troops"),
(str_store_troop_name_plural, s1, ":troop_id"),
(display_message, "@respawning {reg1} {s1}"),
(troop_set_auto_equip, ":troop_id", 1),
(troop_set_inventory_slot, ":troop_id", ek_horse, ":horse_id"),
(troop_set_inventory_slot_modifier, ":troop_id", ek_horse, ":old_imod"),
(try_end),
]
)
During the mission a number of changes need to be made such that the replacement agents are recognized properly and take orders from the player. In addition casualty calculations need to be changed so that agents that are replaced don't show up as being killed and the spawned agents do not show up as allies.
Code:
...
(neq, ":party_no", "p_main_party"),
(assign, ":continue", 1),
(store_faction_of_party, ":party_faction", ":party_no"),
(try_begin), #custom troop replacements
(agent_slot_eq, ":agent_no", slot_agent_is_respawn_as_bot, 1),
(assign, ":continue", 0),
(else_try),
(eq, ":party_faction", "$players_kingdom"),
...
Code:
...
(try_begin),
(neq, ":agent_no", ":player_agent"),
(agent_get_party_id, ":agent_party", ":agent_no"),
(try_begin), # custom troop replacement dot
(this_or_next|agent_slot_eq, ":agent_no", slot_agent_is_respawn_as_bot, 1),
(eq, ":agent_party", "p_main_party"),
(agent_get_division, ":agent_division", ":agent_no"),
Code:
(store_script_param, ":tableau_no",1),
(store_script_param, ":agent_no", 2),
(store_script_param, ":troop_no", 3),
(try_begin), #custom troop, custom banner
(gt, "$g_respawn_in_progress", 0),
(troop_slot_eq, ":troop_no", slot_troop_upgrade_troop, -1),
(troop_get_slot, ":banner_spr", "trp_player", slot_troop_banner_scene_prop),
(val_sub, ":banner_spr", banner_scene_props_begin),
(val_add, ":banner_spr", arms_meshes_begin),
(assign, reg0, ":banner_spr"),
(else_try),
(call_script, "script_agent_troop_get_banner_mesh", ":agent_no", ":troop_no"),
(try_end),
(cur_item_set_tableau_material, ":tableau_no", reg0),
Code:
(party_clear, "p_player_casualties"),
(party_clear, "p_enemy_casualties"),
(party_clear, "p_ally_casualties"),
(assign, "$any_allies_at_the_last_battle", 0),
(try_for_range, ":agent_troop_id", regular_troops_begin, regular_troops_end),
(troop_set_slot, ":agent_troop_id", slot_troop_player_routed_agents, 0),
(troop_set_slot, ":agent_troop_id", slot_troop_ally_routed_agents, 0),
(troop_set_slot, ":agent_troop_id", slot_troop_enemy_routed_agents, 0),
(try_end),
(try_for_agents, ":cur_agent"),
(agent_is_human, ":cur_agent"),
(agent_get_party_id, ":agent_party", ":cur_agent"),
(agent_get_troop_id, ":agent_troop_id", ":cur_agent"),
(assign, ":agent_status", 0),
(try_begin), #custom troop casualty adjustment
(eq, ":agent_party", -1),
(agent_slot_eq, ":cur_agent", slot_agent_is_respawn_as_bot, 1),
(assign, ":agent_party", "p_main_party"),
(else_try),
(neq, ":agent_party", "p_main_party"),
(try_begin),
(agent_is_ally, ":cur_agent"),
(assign, "$any_allies_at_the_last_battle", 1),
(assign, ":agent_status", 1),
(else_try),
(assign, ":agent_status", 2),
(try_end),
(try_end),
(try_begin),
(agent_is_routed, ":cur_agent"),
(agent_slot_eq, ":cur_agent", slot_agent_is_running_away, 1),
(try_begin),
(try_begin),
(eq, ":agent_status", 0),
(val_add, "$num_routed_us", 1),
(else_try),
(eq, ":agent_status", 1),
(val_add, "$num_routed_allies", 1),
(else_try),
#for now only count and include routed enemy agents in new routed party.
(val_add, "$num_routed_enemies", 1),
(store_faction_of_party, ":faction_of_routed_agent_party", ":agent_party"),
(faction_get_slot, ":num_agents", ":faction_of_routed_agent_party", slot_faction_num_routed_agents),
(val_add, ":num_agents", 1),
(faction_set_slot, ":faction_of_routed_agent_party", slot_faction_num_routed_agents, ":num_agents"),
(party_add_members, "p_routed_enemies", ":agent_troop_id", 1),
(try_end),
(try_end),
(try_begin),
(store_add, ":routed_agents", ":agent_status", slot_troop_player_routed_agents),
(troop_get_slot, ":num_agents", ":agent_troop_id", ":routed_agents"),
(val_add, ":num_agents", 1),
(troop_set_slot, ":agent_troop_id", ":routed_agents", ":num_agents"),
(try_end),
(try_end),
(neg|agent_is_alive, ":cur_agent"),
(neg|agent_slot_eq, ":cur_agent", slot_agent_is_respawn_as_bot, -1), #custom troop skip fades
(try_begin),
(eq, ":agent_status", 0),
(assign, ":agent_party", "p_player_casualties"),
(else_try),
(eq, ":agent_status", 1),
(assign, ":agent_party", "p_ally_casualties"),
(else_try),
(assign, ":agent_party", "p_enemy_casualties"),
(try_end),
(try_begin),
(party_add_members, ":agent_party", ":agent_troop_id", 1),
(try_begin),
(agent_is_wounded, ":cur_agent"),
(party_wound_members, ":agent_party", ":agent_troop_id", 1),
(try_end),
(try_end),
(try_end),